I new to jaxB XML parser. i need to get the all the attribute (idref, type, name, scope) from element tag ** I tried something but getting error.
XML File
<?xml version="1.0" encoding="windows-1252"?>
<xmi:XMIxmi:version="2.1"xmlns:uml="http://www.omg.org/spec/UML/20090901"xmlns:xmi="http://schema.omg.org/spec/XMI/2.1" xmlns:thecustomprofile="http://www.sparxsystems.com/profiles/thecustomprofile/1.0" xmlns:SysML="http://www.omg.org/spec/SysML/20161101/SysML">
<xmi:Documentation exporter="Enterprise Architect" exporterVersion="6.5" exporterID="1555"/>
<xmi:Extension extender="Enterprise Architect" extenderID="6.5">
<elements>
<element xmi:idref="EAPK_5560E5AF_736A_4703_AC79_CA3FAA60984B" xmi:type="uml:Package" name="PackageView" scope="public"></element>
<element xmi:idref="EAPK_59058493_9220_4b05_888A_67C6854C97EC" xmi:type="uml:Package" name="Read from Communication Interface" scope="public">
</element>
<element xmi:idref="EAID_870B8E54_0FF2_4a90_A9C1_23F477DF695F" xmi:type="uml:Activity" name="Read from communication interface" scope="public">
</element>
</elements>
</xmi:Extension>
</xmi:XMI>
Main Class
public class XmlElement {
public static void main(String[] args) {
JAXBContext jaxbContext;
String fileLocation = "C:\\vinoth\\XML_JaxbParser\\elements.xml";
try (FileInputStream fileInputStream = new FileInputStream(fileLocation)) {
System.out.println("******** PARSING START ********");
jaxbContext = JAXBContext.newInstance(Xmi.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
elements elements = (elements) unmarshaller.unmarshal(fileInputStream);
System.out.println(elements);
System.out.println("******** PARSING DONE ********");
} catch (Exception e) {
System.out.println("******** ERROR: SOMETHING WENT WRONG ********");
e.printStackTrace();
}
}
}
elements.java
#XmlRootElement(name = "xmi")
#XmlAccessorType(XmlAccessType.FIELD)
public class Elements {
#XmlElement(name = "elements")
private List<Elements> elements;
// Generate Getters and Setters...
#Override
public String toString() {
return "Elements [elements="+ elements +"]";
}
}
element.java
#XmlAccessorType(XmlAccessType.FIELD)
public class Element {
#XmlAttribute(name = "idref")
private String idref;
#XmlAttribute(name = "type")
private String type;
#XmlAttribute(name = "name")
private String name;
#XmlAttribute(name = "scope")
private String scope;
//Generate Getters and Setters...
#Override
public String toString() {
return "Element [idref=" + idref + ",type=" + type + ", name=" + name + ", scope=" + scope+ "]";
}
}
I need to get the the element attribute from the given XML file. I don't know where I made a mistake. Root element and parent and children, i can understand mistake from mapping section. but I couldn't sort out.
Your XML file uses many different XML namespaces,
which you need to consider in your Java code.
Especially notice, that the namespace URIs (e.g.
"http://schema.omg.org/spec/XMI/2.1") are the
only relevant thing. The namespace prefixes (e.g. xmi:) are not
relevant for Java. They were only invented to make the XML
easier to read for humans.
I recommend to define all your XML namespace URIs as Java
string contants to avoid typing them many times in your code:
public class NameSpaces {
public final static String UML = "http://www.omg.org/spec/UML/20090901";
public final static String XMI = "http://schema.omg.org/spec/XMI/2.1";
public final static String THE_CUSTOM_PROFILE = "http://www.sparxsystems.com/profiles/thecustomprofile/1.0";
public final static String SYSML = "http://www.omg.org/spec/SysML/20161101/SysML";
}
You need to carefully look at your XML content (XML elements
XMI, Documentation, Extension, Elements, Element and
their XML attributes) to see which XML namespace is used where.
Then in all your Java classes you need to specify the right
namespace in the #XmlAttribute and #XmlElement annotations.
You will also need to specify a namespace in the #XmlRootElement
annotation of your root class.
See also the Javadoc of the JAXB annotations.
I will not do all your work for you, but instead only show how
your root class and the Element class may look like.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "XMI", namespace = NameSpaces.XMI)
public class XMI {
#XmlAttribute(name = "version", namespace = NameSpaces.XMI)
private String version;
#XmlElement(name = "Documentation", namespace = NameSpaces.XMI)
private Documentation documentation;
#XmlElement(name = "Extension", namespace = NameSpaces.XMI)
private Extension extension;
// Getters, setters, toString omitted here for brevity
}
#XmlAccessorType(XmlAccessType.FIELD)
public class Element {
#XmlAttribute(name = "idref", namespace = NameSpaces.XMI)
private String idref;
#XmlAttribute(name = "type", namespace = NameSpaces.XMI)
private String type;
#XmlAttribute(name = "name")
private String name;
#XmlAttribute(name = "scope")
private String scope;
// Getters, setters, toString omitted here for brevity
}
Related
I met a problem that looks simple but not obvious to solve.
I have 2 packages with classes marshalled to xml with different namespaces. One class is container for others.
package namespace1;
#XmlRootElement(name = "container", namespace = "urn:nmsp:container:001.02")
#XmlAccessorType(XmlAccessType.FIELD)
#Getter
#Setter
public class Container {
#XmlElement(name = "name")
private String name;
#XmlElement(name = "messages")
private List<Message> messages;
}
-------------------------------------------
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Message", propOrder = {
"document"
})
public class Message {
#XmlElement(name = "Document", namespace = "urn:iso:std:iso:20022:001", required = true)
protected Document document;
}
-------------------------------------------
package-info.java
#javax.xml.bind.annotation.XmlSchema(namespace = "urn:nmsp:container:001.02",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
xmlns = {
#XmlNs(namespaceURI = "urn:nmsp:container:001.02", prefix = "")
})
package namespace1;
and
package namespace2;
#XmlRootElement(name = "document", namespace = "urn:iso:std:iso:20022:001")
#XmlAccessorType(XmlAccessType.FIELD)
public class Document {
#XmlElement(name = "id")
private String id;
}
package-info.java
#javax.xml.bind.annotation.XmlSchema(namespace = "urn:iso:std:iso:20022:001",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
xmlns = {
#XmlNs(namespaceURI = "urn:iso:std:iso:20022:001", prefix = "")
})
package namespace2;
What I would like to get is:
<container xmlns="urn:nmsp:container:001.02">
<name>Hello</name>
<messages>
<Document xmlns="urn:iso:std:iso:20022:001">
<id>ID1</id>
</Document>
</messages>
</container>
But what I get is:
<container xmlns="urn:nmsp:container:001.02" xmlns:ns2="urn:iso:std:iso:20022:001">
<name>Hello</name>
<messages>
<ns2:Document>
<ns2:id>ID1</ns2:id>
</ns2:Document>
</messages>
</container>
Marshalling code is:
Container conxml = new Container("Hello");
conxml.setMessages(List.of(new Message(new Document("ID1")))));
JAXBContext jc = JAXBContext.newInstance(Container.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter writer = new StringWriter();
QName _Conxml_QNAME = new QName("urn:nmsp:container:001.02", "container");
JAXBElement<Container> conxmlJAXBElement = new JAXBElement<>(_Conxml_QNAME, Container.class, null, conxml);
marshaller.marshal(conxmlJAXBElement, writer);
System.out.println(writer.toString());
Almost all solutions suggest to fix it with package-info.java but it doesn't help practically.
Can you please give me a hint where I am doing it wrong?
The link to maven project: JaxbTest.7z
The two XML files you give are equivalent, your choice of namespace declaration is a question of taste. The prefixes you set in the #XmlNs annotations are taken into account, when choosing the prefix for each namespace. However, JAXB RI at least, does not redefine them mid-document.
If you want to more directly intervene in the way the XML is generated, you need to add additional components between JAXB and the Writer. E.g. you can use StAX and marshall your document to an XMLStreamWriter like this one (the IndentingXMLStreamWriter comes from TXW2, a dependency of JAXB RI):
private static class RedefineNsXmlStreamWriter extends IndentingXMLStreamWriter {
#Override
public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
final String known_prefix = getNamespaceContext().getPrefix(namespaceURI);
super.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, localName, namespaceURI);
if (!XMLConstants.DEFAULT_NS_PREFIX.equals(known_prefix)) {
super.writeNamespace(XMLConstants.DEFAULT_NS_PREFIX, namespaceURI);
}
}
#Override
public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
// Ignore it
}
public RedefineNsXmlStreamWriter(XMLStreamWriter out) {
super(out);
}
}
Then you create an XMLStreamWriter capable of writing to the Writer and serialize:
final XMLStreamWriter xmlWriter = new RedefineNsXmlStreamWriter(XMLOutputFactory.newFactory()//
.createXMLStreamWriter(writerCont));
marshallerCont.marshal(conxmlJAXBElement, xmlWriter);
Of course the RedefineNsXmlStreamWriter get more complicated once you take into account all cases, but it works for your example.
How do I annotate the externalValue and companyId fields in the Root class so that "abc" gets mapped to externalValue and "123" gets mapped to companyId?
Do I need the #XmlJavaTypeAdapter annotation? Where? I'm hoping that if I do, it can just handle those 2 fields and I can leave the annotations for title and countryCodes as-is.
XML:
<item>
<externalValue companyId="123">abc</externalValue>
<title>My Title</title>
<country>US</country>
<country>CA</country>
</item>
POJO:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Item {
private String externalValue;
private String companyId;
#XmlElement
private String title;
#XmlElement(name = "country")
public List<String> countryCodes;
// getters and setters...
}
I am afraid that this is not possible to achieve only with annotations (so without extra POJO and some adapter) in general case namely JAXB specs. However if your happen to use MOXy as your JAXB implementation it is easy as adding annotation #XmlPath like this:
#XmlPath("externalValue/#companyId")
private String companyId;
Related question: Unmarshalling an XML using Xpath expression and jaxb
You have to define the class in the following manner.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Item {
private CompanyIdValue companyIdValue;
#XmlElement
private String title;
#XmlElement(name = "country")
public List<String> countryCodes;
//getter and setter
}
In case of both attribute in an XML element tag, you have to define a separate class. Define a separate class called CompanyIdValue, for XML element, you have to define #XmlValue and for attribute you have to annotate with #XmlAttribute
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlValue;
public class CompanyIdValue {
#XmlElement(name = "externalValue")
private String externalValue;
private String companyId;
public String getExternalValue() {
return externalValue;
}
#XmlValue
public void setExternalValue(String externalValue) {
this.externalValue = externalValue;
}
public String getCompanyId() {
return companyId;
}
#XmlAttribute
public void setCompanyId(String companyId) {
this.companyId = companyId;
}
}
I provide below a test program also for testing.
public class Test {
public static void main(String[] args) {
try {
Item item = new Item();
CompanyIdValue companyIdValue = new CompanyIdValue();
companyIdValue.setCompanyId("SomeId");
companyIdValue.setExternalValue("Some External value");
item.setCompanyIdValue(companyIdValue);
item.setCountryCodes(Arrays.asList("A", "B"));
item.setTitle("Some Title");
JAXBContext jaxbContext = JAXBContext.newInstance(Item.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
jaxbMarshaller.marshal(item, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
I need to convert XML string into java object.
This is the XML File
<?xml version="1.0" encoding="UTF-8"?>
<DATA_DS>
<G_1>
<TERM_ID>4</TERM_ID><NAME>30 Net</NAME>
</G_1>
</DATA_DS>
I have created Class like this;
#XmlRootElement(name = "DATA_DS")
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymentTerm {
#XmlElement(name = "TERM_ID")
private double termId;
#XmlElement(name = "NAME")
private String termName;
public double getTermId() {
return termId;
}
public void setTermId(double termId) {
this.termId = termId;
}
public String getTermName() {
return termName;
}
public void setTermName(String termName) {
this.termName = termName;
}
}
In Main Class
jaxbContext = JAXBContext.newInstance(PaymentTerm.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(xmlString);
PaymentTerm paymentTerm = (PaymentTerm) unmarshaller.unmarshal(reader);
This doesn't unmarshell the XML string properly because of nested groups in XML file.
If I remove the G_1 group from XML file then it convert perfectly. I need to do conversion with G_1 group
Where I have to fix the code?
<DATA_DS> contains one element, <G_1>, which itself contains two elements, <TERM_ID> and <NAME>, so your objects needs to reflect that, i.e. the class representing <DATA_DS> must have one field, typed to be a class representing <G_1>, which must have two fields.
Where I have to fix the code?
You need to create a class for <G_1>:
#XmlRootElement(name = "DATA_DS")
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymentTerm {
#XmlElement(name = "G_1", required = true)
private PaymentGroup group;
}
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymentGroup {
#XmlElement(name = "TERM_ID", required = true)
private double termId;
#XmlElement(name = "NAME", required = true)
private String termName;
}
You should also consider why <G_1> exists, e.g. can there be more than one <G_1> inside <DATA_DS>? If so, make it a list:
#XmlElement(name = "G_1", required = true)
private List<PaymentGroup> groups;
I'm using java's jaxb to create XML files from java objects.
The problem I'm facing is the exact opposite as stated here: LinqToXml does not handle nillable elements as expected
In short: I want to properly depict members that are null in the resulting xml file.
I have following member in my class
#XmlElement (name = "order-detail", nillable = true)
private String orderDetail;
if I marshal an instance of this class, the resulting xml element is
<order-detail xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
Since also non-technicians are reading, maybe also manipulating, the file, I'd rather have it that way
<order-detail />
since I don't want to confuse them. So how can I achieve this?
UPDATE
Using an empty string instead of null
#XmlElement (name = "order-detail", nillable = true)
private String orderDetail = "";
yields
<order-detail></order-detail>
SSCCE
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
public class Example
{
public static void main(String[] args) throws JAXBException
{
Data data = new Data();
JAXBContext context = JAXBContext.newInstance(Data.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(data, System.out);
}
#XmlRootElement(name = "data")
static class Data
{
private String orderDetail;
#XmlElement (name = "order-detail", nillable = true)
public String getOrderDetail() { return orderDetail; }
public void setOrderDetail(String orderDetail) { this.orderDetail = orderDetail; }
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<data>
<order-detail xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</data>
JAXB will marshal an empty string ("") as an empty element. You could change your code so that when the field has a value of ("") the property reports a null value.
#XmlRootElement(name = "data")
static class Data
{
private String orderDetail = "";
#XmlElement (name = "order-detail", nillable = true)
public String getOrderDetail() {
if(orderDetail.length() == 0) {
return null;
}
return orderDetail;
}
public void setOrderDetail(String orderDetail) {
if(null == orderDetail) {
this.orderDetail = "";
} else {
this.orderDetail = orderDetail;
}
}
}
Normally an XmlAdapter is used to "fix up" values, but the JAXB reference implementation does not apply an XmlAdapter to null values.
Note
In short: I want to properly depict members that are null in the
resulting xml file.
Any empty element is not a valid representation of null in XML.
I m trying to convert XML file into Java Object using Jaxb unmarshalling.
public static void main(String[] args) {
String input = "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">"+
" <key>1</key>" +
"<income>100.335</income>" +
"</project>" ;
NexusClient c1 = new NexusClient();
c1.getObject(input);
}
/*********/
public boolean getObject(String input) {
InputSource inputSource = new InputSource(new StringReader(input));
System.out.println(inputSource);
try {
JAXBContext jaxbContext = JAXBContext
.newInstance(mavenEntity.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
mavenEntity mavenObject = (mavenEntity) jaxbUnmarshaller
.unmarshal(inputSource);
System.out.println("Success"+mavenObject.getIncome());
} catch (JAXBException e) {
System.out.println("Unable to parse the XML Context");
e.printStackTrace();
return false;
}
return true;
}
I m facing an issue while trying to extract "Income" tag information. I couldn't extract correct values using Jaxb. My pojo class is :
#XmlRootElement(name = "project", namespace = "http://maven.apache.org/POM/4.0.0")
#XmlAccessorType(XmlAccessType.FIELD)
public class mavenEntity {
#XmlElement(name = "key", type = String.class)
private String key;
#XmlElement(name = "income", type = String.class)
private String income;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getIncome() {
return income;
}
public void setIncome(String income) {
this.income = income;
}
}
I m getting Null as output for any tag in XML. I guess there is some problem with my name space in XML Annotation. But I really don't understand what it is. Before posting this, I did some groundwork by referring to few links similar to this But still my result is incorrect. Can some one help me out.
The namespace qualification in your model does not match the document. Instead of specifying the namespace on #XmlRootElement and all instances of #XmlElement you can specify the namespace qualification at the package level using #XmlSchema.
package-info.java
#XmlSchema(
namespace = "http://maven.apache.org/POM/4.0.0",
elementFormDefault = XmlNsForm.QUALIFIED)
package org.example.foo;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
mavenEntity.java
I have removed the unnecessary annotations from this class (see: http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html).
package org.example.foo;
import javax.xml.bind.annotation.XmlSchema;
#XmlRootElement(name = "project")
#XmlAccessorType(XmlAccessType.FIELD)
public class mavenEntity {
private String key;
private String income;
}
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
You will need to add namespace to your #XmlElement annotated fields too
#XmlElement(name = "key", namespace = "http://maven.apache.org/POM/4.0.0")
private String key;
#XmlElement(name = "income", namespace = "http://maven.apache.org/POM/4.0.0")
private String income;
That's because your root element has a particular namespace. Since the nested elements don't have namespace prefix, they are using the root's. I guess this is required by JAXB.
Some alternatives and/or explanations here and here.