I'm using xjc from the command line to generate POJOs from an XSD. Here's the command I run:
"%java_home%\bin\xjc" -p com.etc.etc.etc.etc ConsolidatedAlert.xsd
For some of the POJOs generated, the properties in the POJO come back like the following:
#XmlElement(name = "UnparsedTelephone", namespace="")
protected String unparsedTelephone;
As far as I can tell, I don't specify these elements any differently than others that don't have the "namespace" attribute.
Here's the relevant sections of the XSD:
Type declaration:
<xs:complexType name="TelephoneType">
<xs:choice>
<xs:element name="UnparsedTelephone" type="xs:string"/>
<xs:element name="ParsedTelephone" type="ParsedTelephoneType"/>
</xs:choice>
</xs:complexType>
Element declaration:
<xs:element name="Telephone" type="TelephoneType"/>
Where "Telephone" is used:
<xs:complexType name="CompanyContactType">
<xs:sequence>
<xs:element ref="Telephone"/>
</xs:sequence>
</xs:complexType>
Where "CompanyContact" is used:
<xs:complexType name="AmountType">
<xs:sequence>
<xs:element ref="CompanyContact" minOccurs="0" />
<xs:element name="TriggerAmount" type="xs:string"/>
</xs:sequence>
</xs:complexType>
I can simply remove the namespace="" from each POJO, but that can take a bit, and I'd like a better understanding about why it's happening in the first place.
Also, this is about 8 XSDs all linked together. They all have the same targetNamespace and xmlns in the schema definition, but some of them have elementFormDefault="unqualified" and others have elementFormDefault="qualified". Could this be the cause of the problem?
Any ideas?
Namespace Qualification & XML Schema
When elementFormDefault="qualified" all the elements corresponding to this XML Schema will be namespace qualified. When elementFormDefault="unqualified" only global (top level) elements will be namespace qualified.
Namespace Qualification & JAXB
JAXB allows the namespace qualification to be set at the package level using #XmlSchema. Since you have multiple schemas and an undisclosed number of generated packages it's very possible XJC generated "" for namespace to override the default qualification to match the schema rules.
Related
I need to create an XML on JAVA but for multi fields on one element:
<cities>
<city_insert city_id="123" city_name="São Paulo" />
<city_insert city_id="456" city_name="Rio de Janeiro"/>
</cities>
As you can see on the example above, the element city_insert need to have city_id, and city_name , one element can have multiples fields.
How this can be done on Java?
I've searched for DOM and JDOM parsers but still don't know how this works.
Thank you!
Refer to this question for creating an XML using DOM parser.
Create XML file using java
In order to create an attribute (which you mentioned as fields), call setAttribute() method.
nodelist = doc.getElementsByTagName("city_insert");
for (Element element : nodelist) {
Element parent = element.getParentNode()
parent.setAttribute("city_id", "123");
parent.setAttribute("city_name", "São Paulo");
}
I allways do this things using jaxb
First, generate an xsd from your xml (there are many free online generators on the net)
For your xml, an online generated xsd look as follows:
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="cities">
<xs:complexType>
<xs:sequence>
<xs:element name="city_insert" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:short" name="city_id" use="optional"/>
<xs:attribute type="xs:string" name="city_name" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Then, using jaxb (many IDE's like Eclipse have an easy way of doing it) generate jaxb classes from an xsd:
Click finish, then this is java console output:
parsing a schema...
compiling a schema...
com\erax\xml\test\xsd\Cities.java
com\erax\xml\test\xsd\ObjectFactory.java
And the generated classes:
Then just use jaxb marshalling to serialize and deserialize
What are the conceptual and technical disadvantages of this request/response structure:
A)
<xs:element name="OrderRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="OrderID" type="xs:integer"/>
<xs:element name="OrderType" type="xs:integer"/>
<xsd:element name='OrderAttributes' type='xsd:string'/>
</xs:sequence>
</xs:complexType>
</xs:element>
where OrderAttributes element will contain string in the following XML structure:
<OrderName> xy </OrderName>
<OrderDate> xy </OrderDate>
<OrderDetails> xy </OrderDetails>
....lots of other attributes
compared to this request/response structure
B)
<xs:element name="OrderRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="OrderID" type="xs:integer"/>
<xs:element name="OrderType" type="xs:integer"/>
<xsd:element name="OrderAttributes">
<xs:complexType>
<xs:sequence>
<xs:element name="OrderName" type="xs:string"/>
<xs:element name="OrderDate" type="xs:date"/>
<xs:element name="OrderDetails" type="xs:string"/>
....lots of other attributes
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
I need to design web service interface for orders processing, and I am thinking about the two alternatives mentioned above.
Version A, is more generic, so interface doesn't need to change, when OrderAttributes structure changes in any way.
But schema validation is not possible.
And my question is, what are other disadvantages compared to version B. I am analyst, not programmer, so I cannot say, if there is some impact on parsing requests, generating code from contract etc...
First note that your generic use of the word attribute to refer to a property can be confusing in XML, where attribute refers to a specific construct that stands apart from element:
<element attribute="attribute value">
<childElement>child element value</childElement>
</element>
Then, while doing design, you might consider which properties you wish to represent as XML attribute and which you wish to represent as XML elements. See XML attribute vs XML element for help deciding.
Regarding your A vs B proposed designs, note that A simply is not viable -- you cannot have unescaped markup within an element declared to have xs:string content as you've shown. Furthermore, A would then require further parsing of the OrderAttributes contents anyway whereas B would leverage the XML parser to process OrderAttributes contents. (And, like you said, B would not leverage XSD validation either.)
For future expansion, consider instead the use of xs:any, which supports various interpretations of wildcard contents via its processContents attribute values of strict, lax, or skip.
I use JAXB to bind XSD schemas to POCOs. I have tried two different ways to write an XSD schema but each has a flaw:
Option 1
Problem: Each element is represented with <Elements> in XML instead of <Element>, plus they are not inside a container such as <ElementsContainer>.
XSD Schema
<xs:element name="Root" type="RootType" />
<xs:complexType name="RootType" />
<xs:sequence>
<xs:element name="Elements" type="xs:string" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
Java
RootType r = new RootType();
r.getElements.add("Str1");
r.getElements.add("Str2");
Marshaled XML
<Root>
<Elements>Str1</Elements>
<Elements>Str2</Elements>
</Root>
Option 2
Problem: Java code looks uglier.
XSD Schema
<xs:element name="Root" type="RootType" />
<xs:complexType name="RootType" />
<xs:element name="Elements">
<xs:complexType>
<xs:sequence>
<xs:element name="Element" type="xs:string" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:complexType>
Java
RootType r = new RootType();
r.getElements().getElement().add("Str1");
r.getElements().getElement().add("Str2");
Marshaled XML
<Root>
<Elements>
<Element>Str1</Element>
<Element>Str2</Element>
</Elements>
</Root>
Question: Is there a way to write a schema that outputs an XML like in Option 2 and whose code is written like in Option 1?
Edit: <xs:list> is not an option as elements may have white-spaces.
Starting from Java Classes
If you are starting from Java Objects you can use the #XmlElementWrapper annotation to add a grouping element.
#XmlElementWrapper(name="Elements")
#XmlElement(name="Element)
public List<Element> getElements() {
return elements;
}
Starting from XML Schemas
The XJC tool is very extensible. The following plug-in written for the XJC tool appears to allow you to generate #XmlElementWrapper annotations into your model.
https://github.com/dmak/jaxb-xew-plugin
I'm using JAXB on my project, but from time to time, I face some problems that I can't solve. I have setup my environment like this:
Armor Class
package com.fortresswars.entity.component;
#XmlType(name = "armor", namespace = "http://fortresswars.com")
public class ArmorComponent extends AbstractComponent
package-info.java
#XmlSchema(xmlns = #XmlNs(namespaceURI = "http://fortresswars.com", prefix = "fw"), elementFormDefault = XmlNsForm.UNQUALIFIED, namespace = "http://fortresswars.com")
package com.fortresswars.entity.component;
The generated schema header is almost correct:
<xs:schema elementFormDefault="unqualified" version="1.0" targetNamespace="http://fortresswars.com" xmlns:fw="http://fortresswars.com" xmlns:tns="http://fortresswars.com" xmlns:xs="http://www.w3.org/2001/XMLSchema">
The only thing I didn't like is that TNS prefix that JAXB puts there and I can't remove. I'm using an ant task (com.sun.tools.jxc.SchemaGenTask), and I remember reading somewhere that this was the problem.
The rest of the generated scheme follows below. I'll show only the relevant part about armor:
<xs:complexType name="armor">
<xs:complexContent>
<xs:extension base="tns:abstractComponent">
<xs:sequence>
<xs:element name="value" type="xs:short" minOccurs="0"/>
<xs:element name="type" type="tns:armor-type" minOccurs="0"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
And the element that is using the armor component:
<xs:complexType name="character">
<xs:complexContent>
<xs:extension base="tns:thing">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="armor" type="tns:armor"/>
<xs:element name="model" type="tns:model"/>
<xs:element name="status" type="tns:status"/>
<xs:element name="costs" type="tns:costs"/>
</xs:choice>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
To test this, I created a XML Document (see the TNS prefix, I need to put it, or the fw prefix, along with the xmlns:fw also).
<?xml version="1.0" encoding="UTF-8"?><tns:character xmlns:tns="http://fortresswars.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="/home/shirkit/jMonkeyProjects/Fortress Wars/Core/schema/full.xsd">
<armor>
<value>5</value>
<type>NORMAL</type>
</armor>
</tns:character>
But when I'm unmarshalling this document, here's the error I get:
Exception: unexpected element (uri:"", local:"armor"). Expected elements are <{http://fortresswars.com}armor>,<{http://fortresswars.com}attacks>,<{http://fortresswars.com}costs>,<{http://fortresswars.com}model>,<{http://fortresswars.com}abilities>,<{http://fortresswars.com}status>,<{http://fortresswars.com}movement>
I have setup elementFormDefault to UNQUALIFIED, and even though this doesn't work. Why I'm getting this exception? And can I remove TNS prefix from the generated schema?
when you define a namespace prefix for elements of http://fortresswars.com you need to prefix all elements with it, not only character. So this should work
<?xml version="1.0" encoding="UTF-8"?>
<tns:character
xmlns:tns="http://fortresswars.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="/home/shirkit/jMonkeyProjects/Fortress Wars/Core/schema/full.xsd">
<tns:armor>
<tns:value>5</tns:value>
<tns:type>NORMAL</tns:type>
</tns:armor>
</tns:character>
The tns prefix used in the schema is unrelated to what you use as prefix for XML text that you unmarshal. You may choose any other in xmlns:whatyoulike="http://fortresswars.com". The key that connects the elements in the XML document to the definitions in the schema file is the namespace URI, in your case "http://fortresswars.com". If you define your namespace as default namespace, you can omit the prefix on every element:
<?xml version="1.0" encoding="UTF-8"?>
<character
xmlns="http://fortresswars.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="/home/shirkit/jMonkeyProjects/Fortress Wars/Core/schema/full.xsd">
<armor>
<value>5</value>
<type>NORMAL</type>
</armor>
</character>
The namespace prefix in the XSD file helps to avoid name clashes if you wan't to use the schema file together with other schema files that define types or elements with the same name. It does not force you to use it in the xml files you want to unmarshal.
On the other hand, when you marhshal objects to XML, the file package-info.java defines what prefix JAXB uses, but this only works in recent versions of JAXB and it's not always easy to assure that the correct version is in use when your code runs. But you may use a NamespacePrefixMapper to control that.
I have an XSD that defines the following schema:
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://example.com/2010/aa/"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:aa="http://example.com/2010/aa/"
targetNamespace="http://example.com/2010/aa/"
elementFormDefault="qualified">
...
<xs:element name="user" type="aa:User"/>
<xs:complexType name="User">
<xs:sequence>
<xs:element ref="aa:firstName" minOccurs="0" maxOccurs="1"/>
<xs:element ref="aa:lastName" minOccurs="0" maxOccurs="1"/>
...
<xs:any namespace="##targetNamespace" processContents="skip" maxOccurs="unbounded" />
</xs:sequence>
<xs:anyAttribute processContents="skip" />
</xs:complexType>
<xs:element name="profile" type="aa:Profile"/>
<xs:complexType name="Profile">
<xs:sequence>
<xs:element ref="aa:username" minOccurs="0" maxOccurs="1"/>
<xs:element ref="aa:accountStatus" minOccurs="0" maxOccurs="1" />
<xs:element ref="aa:roleid" minOccurs="0" maxOccurs="1"/>
...
<xs:element ref="aa:userid"/>
</xs:sequence>
<xs:anyAttribute processContents="skip" />
</xs:complexType>
When JAXB is marshalling the generated Objects it defines the following:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user xmlns:ns2="http://example.com/2010/aa/">...</user>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<profile xmlns="http://example.com/2010/aa/">...</profile>
See how one namespace is xmlns:ns2 and the other one is xmlns. This is because all the elements of user are qualified for the aa namespace but the ones defined by the xs:any tag, hence the need to define two namespaces.
Profile doesn't have a xs:any tag and doesn't need to define more than one namespaces. This is my interpretation, since if I remove the xs:any from the user definition it will remove the ns2 from the generated XML.
How can I tell JAXB that both the targetNamespace and aa are the same namespace so it doesn't include both?
You could try to use a NamespacePrefixMapper to override how the prefixes are generated in the first place:
NamespacePrefixMapper mapper = new NamespacePrefixMapper() {
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
return "";
}
};
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", mapper);
I'm returning "" there, so there will be only a default prefix; implement a more sophisticated version as required.
This does create a dependency on a Sun class, which is a problem caused by JAXB. Please review this other post. The answer at the bottom shows how to modify package-info.java to achieve the same.
Alternatively, instead of using a proprietary Metro JAXB extension, you could use MOXy JAXB. MOXy will use the namespace prefixing defined in the #XmlSchema package level annotation.
For more information see:
JAXB marshalling problem - probably namespace related
Jaxb2Marshaller creating JAXBContext with empty namespace URI
Define Spring JAXB namespaces without using NamespacePrefixMapper