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.
Related
Currently i have to hard-code the schema version (or parse it) manually in java code when working with generated JAXB classes. This can easily lead to mistakes when changing the XML schema version and feels wrong.
What i want is to specify the schema version in the schema and let xjc generate a constant in the corresponding root element class.
I haven't found a JAXB plugin or binding mechanism which i can use to meet these requirements.
example.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="my:namespace:v1"
targetNamespace="my:namespace:v1"
xmlns="my:namespace:v1"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
<!-- Use this version information in generated class! -->
version="1.0">
<xs:element name="root" type="RootType"/>
<xs:complexType name="RootType">
<xs:sequence>
<xs:element name="name" type="xs:string" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
<xs:attribute name="xsdVersion" type="xs:string" use="required"/>
[...]
</xs:schema>
Generated RootType.class:
[...]
public class RootType {
protected String name;
protected String xsdVersion;
// This shall be generated too
public static final GENERATED_WITH_VERSION = "1.0";
[...]
}
i'm new on this XML stuff, and i'm having one issue with the location of the element diops.
Here is my xml
<diops
xmlns:ans="ttp://dados.wsh.com.br/diopsxml-2016/xsd/2016/xsd/2016"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:SchemaLocation="http://dados.wsh.com.br/diopsxml-2016/xsd/2016 Diops2016.xsd">
And here is my XSD
<xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.ans.gov.br/ws/diops/financeiro/schema/v2016"
elementFormDefault="qualified"
targetNamespace="http://www.ans.gov.br/ws/diops/financeiro/schema/v2016"
version="1.1">
<xs:include schemaLocation="DiopsComplexTypes2016.xsd"/>
<xs:element name="diops">
<xs:complexType>
<xs:sequence>
<xs:element ref="tns:identificacao"/>
<xs:element name="financeiro" type="tns:financeiro"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
The message that appear to me is: "Cannot find the declaration of the element 'diops'.
But he is the first element that i declare in the XSD file, with the other elements i dont have any issue, only with the element called 'diops'.
Sorry about my poor english.
I guess you're trying to validate yout XML document against the schema.
Anyways, your schema defines the <diops> element to be in the http://www.ans.gov.br/ws/diops/financeiro/schema/v2016 namespace (that's what the targetNamespace attribute does). However, in your XML document, the <diops> element belongs to the empty namespace.
You should simply add a namespace declaration in your XML document:
<diops xmlns="http://www.ans.gov.br/ws/diops/financeiro/schema/v2016" ... >
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.
I want to add an xsd file to our project that relies on types defined in another xsd that is in a jar. We use jaxb to generate Java classes from the xsds.
How do i refer to SchemaContainingFooTypeIsInaJAR.xsd so that 'FooType' resolves correctly and the proper Java classes get generated
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:include schemaLocation="SchemaContainingFooTypeIsInaJAR.xsd"/>
<xs:complexType name="FooMoreType">
<xs:complexContent>
<xs:extension base="FooType">
<xs:sequence>
<xs:element name="something" type="xs:boolean" minOccurs="0">
<xs:annotation>
<xs:documentation xml:lang="en">
something something
</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
You might be interested in these features:
http://confluence.highsource.org/display/MJIIP/User+Guide#UserGuide-CompilingaschemafromaMavenartifact
http://confluence.highsource.org/display/MJIIP/User+Guide#UserGuide-Usingcatalogs
In short, you can write a catalog file which would point to your schema in a JAR file:
REWRITE_SYSTEM "some/url/a.xsd" "maven:org.jvnet.jaxb2.maven2:maven-jaxb2-plugin-tests-episodes-a!/a.xsd"
DISCLAIMER: I am the principal dev of maven-jaxb2-plugin.
See XML Schema reference and JAXB SchemaFactory source order must follow import order between schemas?
The consensus appears to be: you need to supply your own resolver.
Replace your line:
<xs:include schemaLocation="SchemaContainingFooTypeIsInaJAR.xsd"/>
with
<xs:include schemaLocation="jar:file:///path/to/jar/thing.jar!/path/inside/jar/to/file.xsd"/>
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