I'm trying to process some XML files using the JAXB implementation shipped in Java 7. I'm using these versions :
501 ~ % xjc -version
xjc 2.2.4
502 ~ %java -version
java version "1.7.0_01"
Java(TM) SE Runtime Environment (build 1.7.0_01-b08)
Java HotSpot(TM) Server VM (build 21.1-b02, mixed mode)
The problematic decalaration in the XML schema is the following :
<xsd:complexType name="CategorizeType">
<xsd:complexContent>
<xsd:extension base="se:FunctionType">
<xsd:sequence>
<xsd:element ref="se:LookupValue"/>
<xsd:element ref="se:Value"/>
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="se:Threshold"/>
<xsd:element ref="se:Value"/>
</xsd:sequence>
<xsd:element ref="se:Extension" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="thresholdBelongsTo"
type="se:ThresholdBelongsToType" use="optional"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
As you can see, there are two explicit occurences of se:Value in the Type. However, it doesn't stop the compilation using xjc. And if I have a look in the Java class generated for this type, I can see that it is theoritically possible to retrieve the elements of
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="se:Threshold"/>
<xsd:element ref="se:Value"/>
</xsd:sequence>
using the following method :
public List<Object> getThresholdAndValue() {
if (thresholdAndValue == null) {
thresholdAndValue = new ArrayList<Object>();
}
return this.thresholdAndValue;
}
Unfortunately, if I try to get the elements of the list, i can only retrieve the elements registered as threshold in my xml file, where the CategorizeType instance is defined as follow :
<Categorize thresholdsBelongTo="succeeding" fallbackValue="0">
<LookupValue>
<ns3:ValueReference>OUI_EEE92</ns3:ValueReference>
</LookupValue>
<Value>0.3</Value>
<Threshold>30.0</Threshold>
<Value>0.4</Value>
<Threshold>40.0</Threshold>
<Value>0.45</Value>
<Threshold>45.0</Threshold>
<Value>0.5</Value>
<Threshold>50.0</Threshold>
<Value>0.55</Value>
<Threshold>55.0</Threshold>
<Value>0.6</Value>
<Threshold>60.0</Threshold>
<Value>0.7</Value>
<Threshold>70.0</Threshold>
<Value>0.8</Value>
<Extension>
<ExtensionParameter name="method">MANUAL</ExtensionParameter>
</Extension>
</Categorize>
When retrieving the list, I can only see the Threshold values.
Do I make something wrong ? Is it an inner limitation of Jaxb ?
Note that I can't change the XML schema...
EDIT :
I've just run xjc with the -v option, and I obtain globally the same output. With verbosity :
xjc -verbose se/2.0/All.xsd
parsing a schema...
[WARNING] java.net.SocketException: Unexpected end of file from server
line 23 of file:/home/alexis/crap/SE-Schema-2.0/ows/2.0/ows19115subset.xsd
[WARNING] java.net.SocketException: Unexpected end of file from server
line 22 of file:/home/alexis/crap/SE-Schema-2.0/filter/2.0/filterCapabilities.xsd
compiling a schema...
[INFO] generating codee
unknown location
Without it :
xjc se/2.0/All.xsd
parsing a schema...
[WARNING] java.net.SocketException: Unexpected end of file from server
line 23 of file:/home/alexis/crap/SE-Schema-2.0/ows/2.0/ows19115subset.xsd
[WARNING] java.net.SocketException: Unexpected end of file from server
line 22 of file:/home/alexis/crap/SE-Schema-2.0/ows/2.0/owsExceptionReport.xsd
compiling a schema...
The following output just contains the name and location of the generated files.
I have forgotten to say that this xsd couldn't be compiled with the xjc shipped with Java 6. Last tried has been made with JAXB 2.1.10.I can't reproduce this behaviour now, as I'm now working with Java 7.
EDIT2 :
I've just tried to customize the binginds, as suggested in comments. My binding file is the following :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jxb:bindings jxb:version="1.0"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
<jxb:bindings schemaLocation="schema.xsd"
node="//xsd:complexType[#name='CategorizeType']">
<jxb:bindings
node="xsd:complexContent/xsd:extension/xsd:sequence/xsd:element[#ref='se:Value'][position()=1]">
<jxb:property name="FirstValue"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
The first value instance is indeed replaced by a firstValue attribute in the Java code
#XmlElement(name = "Value", required = true)
protected ParameterValueType firstValue;
#XmlElements({
#XmlElement(name = "Threshold", type = LiteralType.class),
#XmlElement(name = "Value", type = ParameterValueType.class)
})
protected List<Object> thresholdAndValue;
public ParameterValueType getFirstValue() {
return firstValue;
}
public void setFirstValue(ParameterValueType value) {
this.firstValue = value;
}
public List<Object> getThresholdAndValue() {
if (thresholdAndValue == null) {
thresholdAndValue = new ArrayList<Object>();
}
return this.thresholdAndValue;
}
Unfortunately, I still obtain the same result - I still can't see my values in the list returned by getThresholdAndValues(). I'm still exploring the customization way...
Update: Sorry I had to give up on this, I just couldn't get it to work either (it would be so much easier if you could change your schema!). I was using the Codehaus JAXB maven plugin. I'm pretty sure it's a conflict caused by the two Value elements, which I tried to fix with an xjb customisation:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jxb:bindings jxb:version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<jxb:bindings schemaLocation="../xsd/example.xsd" node="/xsd:schema">
<jxb:schemaBindings>
<jxb:package name="com.example" />
<jxb:nameXmlTransform>
<jxb:elementName suffix="Element"/>
</jxb:nameXmlTransform>
</jxb:schemaBindings>
</jxb:bindings>
</jxb:bindings>
It had absolutely no effect. I tried <jxb:typeName suffix="Element"/>, and it renamed all of the JAXB classes, so I assume there's a bug with the jxb:elementName feature.
Original Post:
I've been looking at this and I'm able to replicate your problem.
I took a few liberties with your schema to simplify things, but it still contains the essential elements. Here is what I've been using:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:se="http://com.example/example"
targetNamespace="http://com.example/example"
elementFormDefault="qualified">
<xsd:element name="Categorize" type="se:CategorizeType" />
<xsd:complexType name="FunctionType">
</xsd:complexType>
<xsd:simpleType name="Value">
<xsd:restriction base="xsd:string"/>
</xsd:simpleType>
<xsd:simpleType name="Threshold">
<xsd:restriction base="xsd:string"/>
</xsd:simpleType>
<xsd:complexType name="CategorizeType">
<xsd:complexContent>
<xsd:extension base="se:FunctionType">
<xsd:sequence>
<xsd:element name="Value" type="se:Value" />
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element name="Threshold" type="se:Threshold" />
<xsd:element name="Value" type="se:Value" />
</xsd:sequence>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
I've removed any elements/attributes not related to the issue, used name/type instead of ref, and defined the types missing from your provided schema.
My generated JAXB CategorizeType class looks like:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "CategorizeType", propOrder = {
"value",
"thresholdAndValue"
})
public class CategorizeType
extends FunctionType
{
#XmlElement(name = "Value", required = true)
protected String value;
#XmlElementRefs({
#XmlElementRef(name = "Value",
namespace = "http://com.example/example", type = JAXBElement.class),
#XmlElementRef(name = "Threshold",
namespace = "http://com.example/example", type = JAXBElement.class)
})
protected List<JAXBElement<String>> thresholdAndValue;
...
}
When I unmarshall your XML, my Categorize.Value is 0.8 (instead of the expected 0.3), and the values of each ThresholdAndValue (all Strings in my case) are 30.0, 40.0, 45.0, etc. The 0.4, 0.45, etc are missing.
When I remove the first Value element from the schema and then unmarshall, I get all of the expected values, so there's definitely a conflict!
However, when I marshall using the following JAXB setup:
ObjectFactory factory = new ObjectFactory();
CategorizeType catType = factory.createCategorizeType();
catType.setValue("0.3");
JAXBElement<String> thresh = factory.createCategorizeTypeThreshold("30.0");
JAXBElement<String> threshVal = factory.createCategorizeTypeValue("0.4");
JAXBElement<String> thresh2 = factory.createCategorizeTypeThreshold("40.0");
JAXBElement<String> threshVal2 = factory.createCategorizeTypeValue("0.45");
catType.getThresholdAndValue().add(thresh);
catType.getThresholdAndValue().add(threshVal);
catType.getThresholdAndValue().add(thresh2);
catType.getThresholdAndValue().add(threshVal2);
JAXBElement<CategorizeType> element = factory.createCategorize(catType);
// marshall to XML here!
I get the expected output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Categorize xmlns="http://com.example/example">
<Value>0.3</Value>
<Threshold>30.0</Threshold>
<Value>0.4</Value>
<Threshold>40.0</Threshold>
<Value>0.45</Value>
</Categorize>
I'll keep looking into this!
i think you need a complexType element around
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="se:Threshold"/>
<xsd:element ref="se:Value"/>
</xsd:sequence>
Can you insert an XSLT transformation to add a ComplexType to the schema definition before running xjc?
Related
I'm new to using xml, and having trouble figuring this out. I found a schema for the RSS spec online, and I can generate java classes from that self-contained schema using xjc without issues.
I want to add fields from simpledc.xsd because in RSS feeds, I'm seeing tags like dc:creator on <items>, and I'd like to set it up so code generation for that can work too. In my attempt, I added the xsd:include for the dc schema, and added a field to the item definition.
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!-- My addition -->
<xsd:include schemaLocation="simpledc.xsd" />
<xsd:element name="rss" type="rss" />
<xsd:complexType name="rss">
<xsd:sequence>
<xsd:element name="channel" type="channel" maxOccurs="1"
minOccurs="1" />
...
<xsd:complexType name="item">
<xsd:sequence>
<xsd:element name="title" type="xsd:string" maxOccurs="1" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
The title of the item.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
...
<!-- My addition -->
<xsd:element name="creator" type="dc:creator" maxOccurs="1" minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
Intellij provides the error:
Cannot resolve symbol 'dc:creator'
And xjc also provides a similar error:
$ xjc -p com.test.generated -d src/main/java/ src/main/resources/schemas/rss.xsd
parsing a schema...
[ERROR] s4s-att-invalid-value: Invalid attribute value for 'type' in element 'element'. Recorded reason: UndeclaredPrefix: Cannot resolve 'dc:creator' as a QName: the prefix 'dc' is not declared.
line 391 of file:/<project>/src/main/resources/schemas/rss.xsd
How do I set this up properly so that I can add elements with the dc namespace in my xml schema, and have codegen work properly?
I figured out how to do this. I used an include where I should have used an import because I was referencing a different namespace. And then for the element from the different namespace, I need to use a ref to link to them:
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<xsd:import schemaLocation="dc.xsd" namespace="http://purl.org/dc/elements/1.1/"/>
...
<xsd:complexType name="item">
<xsd:sequence>
...
<!-- My addition -->
<xsd:element minOccurs="0" ref="dc:creator" />
</xsd:sequence>
</xsd:complexType>
I'm not sure what the intent of the simpledc.xsd provided by the dublin core website. Using dc.xsd seems to work for generating the schema.
Unfortunately, when you're trying to unmarshall xml according to this schema, it seems that the rss feed author needs to add xmlns fields at the top level <rss> element, and they mostly do not.
I am trying to unMarshall XML data from a file with the following Schema file, using NetBeans 8.2, in a java Web Application.
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xml.netbeans.org/schema/xSchema"
xmlns:tns="http://xml.netbeans.org/schema/xSchema"
elementFormDefault="qualified">
<xsd::complexType name="xItem">
<xsd:sequence>
<xsd:element name="item1" type="xsd:string"/>
<xsd:element name="item2" type="xsd:string"/>
<xsd:element name="item3" type="xsd:int"/>
<xsd:element name="x-price">
<xsd:complexType>
<xsd:sequence>
<xsd:element name = "item4" type="xsd:string"/>
<xsd:element name = item5" type = "xsd:float"/>
<xsd:element name = "item6" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:element name = "xList">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="x_details" type="tns:xItem" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
I created an XML Document using NetBeans and populated that with data, matching the Schema file.
The XML schema is bound to the Java Web Application using Jaxb. I have created the unmarshalling code using the jaxbu method, which looks like this
xList currentx = new xList();
//UnMarshal data from XML to Object
try {
javax.xml.bind.JAXBContext jaxbCtx = javax.xml.bind.JAXBContext.newInstance(currentx.getClass().getPackage().getName());
javax.xml.bind.Unmarshaller unmarshaller = jaxbCtx.createUnmarshaller();
currentx = (xList) unmarshaller.unmarshal(fileHandle); //NOI18N
} catch (javax.xml.bind.JAXBException ex) {
// XXXTODO Handle exception
java.util.logging.Logger.getLogger("global").log(java.util.logging.Level.SEVERE, null, ex); //NOI18N
}
The resulting ArrayList currentx, contains all the instances of item1, item2 and item 3. It does not however appear to contain items 4 and 5. 'fileHandle' is a FILE object, and is obviously pointing to the correct file.
The generated files include classes for xItem and a nested static class for x-price, but whenever I try to retrieve data from the nested class, I get a null pointer exception for items4, 5 and 6, but can read items 1,2 and 3. The unmarshalling function appears to perform without any exceptions being created.
Am I using the right methods for unmarshalling all the data or am I missing something to deal with the x-price ( items 4, 5 and 6)? How is that done ?
XLM first data record and header:
<ns1:xList
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:ns1='http://xml.netbeans.org/schema/xSchema'
xsi:schemaLocation='http://xml.netbeans.org/schema/xSchema xSchema1.xsd'>
<ns1:x_details>
<ns1:item1>AA</ns1:item1>
<ns1:item2>AA</ns1:item2>
<ns1:aitem3>212</ns1:item4>
<ns1:x-price>
<ns1:item4>GBP</ns1:item4>
<ns1:item5>75.26</ns1:item5>
<ns1:item6>04/12/2018</ns1:item6>
</ns1:x-price>
</ns1:x_details>
In your example Schema your schema seems to be invalid:
<xsd:element name = item5" type = "xsd:float"/>
and should be
<xsd:element name = "item5" type = "xsd:float"/>
also it is hard to help if your real data is missing (your XML). Could you add a full XML example?
In my Java (Maven) project I'm using JAXB 2.2.11 to rebuild instances of a class from an XML payload received by our servers. I have an .xsd schema defining the class, which works great in conjunction with JAXB to rebuild an instance of the type I want. The issue I'm having is that those payloads can (without any notice or warning) have extra elements which I don't really care about.
One of the places where those extra elements can appear is within an xs:all tag. I do like having the functionality of said xs:all tag:
The all element specifies that the child elements can appear in any
order and that each child element can occur zero or one time.
However, I don't want to get a parsing error while processing an XML payload that contains extra attributes. An xs:any tag inside the xs:all would work great, but it's not permitted in XSD 1.0 (according to w3schools and this other SO answer) and apparently, JAXB doesn't support XSD 1.1. Also, the way JAXB treats the any or the anyAttribute is very interesting, because it puts all the unknown nodes into a map, so I can log it saying "Hey! We are receiving an attribute that we don't really care about as of now, but maybe you'll find it somehow useful in the future?"
I've read about Xsom, that supports XSD 1.1, but apparently, it doesn't return an instance of the class you want, but more generic set of hash-maps and lists, therefore losing my type checking, which is something I don't want to.
So... Is there any way of pretending to have an xs:any within an xs:all?
Correct. XSD 1.0 does not allow xsd:any within xsd:all; XSD 1.1 does.
Workarounds for XSD 1.0 not allowing xsd:any in xsd:all
Confine xsd:any to a fixed wrapper element such as expansion with xsd:all:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="root">
<xsd:complexType>
<xsd:all>
<xsd:element name="a"/>
<xsd:element name="b"/>
<xsd:element name="expansion">
<xsd:complexType>
<xsd:sequence>
<xsd:any maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:all>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Abandon the unordered allowance of xsd:all and let the xsd:any elements follow in sequence:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="root">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="a"/>
<xsd:element name="b"/>
<xsd:any maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
I'm trying to specify a union schema type allowing either a string value or a reference to an existing element for usage in Jaxb. Here's an minimal example schema:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="property" >
<xsd:complexType>
<xsd:attribute name="id" type="xsd:ID" />
<xsd:attribute name="value" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:complexType name="customerType">
<xsd:attribute name="property" type="propType" />
</xsd:complexType>
<xsd:simpleType name="propType">
<xsd:union memberTypes="xsd:IDREF xsd:string" />
</xsd:simpleType>
<xsd:element name="customer" type="customerType" />
</xsd:schema>
Here the property attribute can contain the property value directly or reference a defined property element from the xml-document.
As union types are automatically mapped to java-Strings, I used the XmlConversion-Annotation (from this example: EclipseLink Example) to provide a mapping to the allowed schema-types. This is working perfectly for the allowed types, i.e. decimal and string values, from the example:
public class CustomerCustomizer implements DescriptorCustomizer {
#Override
public void customize(ClassDescriptor descriptor) throws Exception {
XMLDirectMapping attributeMapping = new XMLDirectMapping();
...
XMLUnionField unionField = new XMLUnionField();
unionField.addSchemaType(XMLConstants.DECIMAL_QNAME);
unionField.addSchemaType(XMLConstants.STRING_QNAME);
...
}
}
I've tested this example using EclipseLink Moxy 2.5.2.
Unfortunately I wasn't able to find a way to provide the capability for specifying a reference in the conversion, i.e. to look whether the property attribute specifies a valid and present ID from the xml-document and if true, use this as property-value. If not, use the given string directly.
Is there a way of using ID-References in a union in EclipseLink Moxy??
Or any other suggestion how to achieve the desired behavior of having either a reference (if available in the document) or a string value for an attribute??
Thanks for any help!
I'm having a problem generating java source code based on XSD file.
Please notice that the XSD file was generated based on XML example.
XML Example
<resposta_importacao>
<RetornoEnvio xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<num_apolice xmlns="compuletra">202476600001</num_apolice>
<cod_retorno xmlns="compuletra">651</cod_retorno>
<mensagem xmlns="compuletra">Erro de layout de dadosobrigatórios: cod_cobertura</mensagem>
<id_validacao xmlns="compuletra">0</id_validacao>
</RetornoEnvio>
<RetornoEnvio xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<num_apolice xmlns="compuletra">202476600002</num_apolice>
<cod_retorno xmlns="compuletra">651</cod_retorno>
<mensagem xmlns="compuletra">Erro de layout de dados obrigatórios: cod_cobertura</mensagem>
<id_validacao xmlns="compuletra">0</id_validacao>
</RetornoEnvio>
</resposta_importacao>
Generated XSD
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="RetornoEnvio">
<xsd:sequence>
<xsd:element name="num_apolice" type="xsd:integer" xmlns="compuletra" />
<xsd:element name="cod_retorno" type="xsd:int" xmlns="compuletra" />
<xsd:element name="mensagem" type="xsd:string" xmlns="compuletra" />
<xsd:element name="id_validacao" type="xsd:int" xmlns="compuletra" />
</xsd:sequence>
</xsd:complexType>
<xsd:element name="resposta_importacao">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="unbounded" type="RetornoEnvio" name="RetornoEnvio" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Generated Java Class
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "RetornoEnvio", propOrder = {
"numApolice",
"codRetorno",
"mensagem",
"idValidacao"
})
public class RetornoEnvio {
#XmlElement(name = "num_apolice", required = true)
protected BigInteger numApolice;
#XmlElement(name = "cod_retorno")
protected int codRetorno;
#XmlElement(required = true)
protected String mensagem;
#XmlElement(name = "id_validacao")
protected int idValidacao;
The problem here is that the XML has the
xmlns="compuletra"
But the java class don't.
I know I can just insert the namespace attribute to the XmlElement annotation but it would be nicer if the code generation could insert it for me.
Thank you
The xmlns attribute in the element defintion in the XML Schema has nothing to do with the namespace qualification of the element. This is why JAXB isn't doing anything with it.
<xsd:element name="cod_retorno" type="xsd:int" xmlns="compuletra" />
Well, just to answer mine own question, so that it does not go unanswered..
I could achieve this namespace difference with the most obvious solution, after thinking of it a little more. Basically using two XSD files with two different namespaces and importing them in a third XSD file.
It all worked as expected.
Thank you,
Thiago