JAXB unmarshals incomplete objects when using XSD <choice> element - java

I'm experiencing a problem unmarshalling a element in an XML document using JAXB RI 2.2.1.
The element is defined as follows (the full XSD is too large to post):
<xsd:element name="PatternExpression" type="PatternExpression_Type"/>
<xsd:complexType name="PatternExpression_Type">
<xsd:choice>
<xsd:element ref="Pattern"/>
<xsd:sequence>
<xsd:element ref="PatternOperator"/>
<xsd:choice maxOccurs="unbounded">
<xsd:element ref="Pattern"/>
<xsd:element ref="PatternExpression" minOccurs="0" maxOccurs="unbounded"/>
</xsd:choice>
</xsd:sequence>
</xsd:choice>
</xsd:complexType>
Here is the XML I'm trying to unmarshal:
<PatternExpression>
<PatternOperator tc="2">and</PatternOperator>
<Pattern>
<PropertyName>FirstName</PropertyName>
<PropertyValue>John</PropertyValue>
</Pattern>
<Pattern>
<PropertyName>LastName</PropertyName>
<PropertyValue>Doe</PropertyValue>
</Pattern>
</PatternExpression>
When I run the document through the unmarshaller, the resulting PatternExpression object contains the PatternOperator and a single Pattern, which happens to be the last one in the sequence.
Does anyone have any suggestions as to why the Pattern objects are not being added to the list?
I would think that the presence of the PatternOperator would allow JAXB to determine what choice the element fall into.
FYI, the XML schema is controlled by a 3rd party, so it cannot be modified.

Related

How do I "import" an xml schema for xjb code generation

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.

java unmarshalling complex types in Netbeans

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?

<xs:any> inside an <xs:all> XSD 1.0 workarounds?

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>

JAXB java code generation base on XSD file

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

xsd validation error when importing

We are new users to xsd, and we try to validate a xsd file that needs to import another.
We are trying to do an import from companyInfos.xsd to employmentrecord.xsd.
Here are the two xsd files we are dealing with.
employmentrecord.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:ci="companyInfos.xsd"
targetNamespace="er"
elementFormDefault="qualified">
<xsd:import namespace="ci" schemaLocation="companyInfos.xsd" />
<xsd:element name="employment">
<xsd:complexType>
<xsd:sequence>
<xsd:element type="ci:company"/>
<xsd:element name="position" type="xsd:string"/>
<xsd:element name="duration" type="xsd:string"/>
<xsd:element name="dateStart" type="xsd:date"/>
<xsd:element name="current" type="xsd:booolean"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
companyInfos.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="ci" elementFormDefault="qualified">
<xsd:element name="company">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="companyName" type="xsd:string"/>
<xsd:element name="foundationDate" type="xsd:date"/>
<xsd:element name="field" type="xsd:string"/>
<xsd:element name="employeeCount" type="xsd:integer"/>
<xsd:element name="logo" type="xsd:anyURI"/>
<xsd:element name="description" type="xsd:string"/>
<xsd:element name="httpLink" type="xsd:anyURI"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
We got the following error in the terminal when trying the validity:
org.xml.sax.SAXParseException; systemId: file:///home/jiby/Dropbox/ID2208_shared%20with%20JB/SampleParser/ID2208_hw1/xml/employmentrecord.xsd;
It was detected that 'ci:company' is in namespace 'companyInfos.xsd', but components from this namespace are not referenceable from schema document 'file:///home/jiby/Dropbox/ID2208_shared%20with%20JB/SampleParser/ID2208_hw1/xml/employmentrecord.xsd'. If this is the incorrect namespace, perhaps the prefix of 'ci:company' needs to be changed.
If this is the correct namespace, then an appropriate 'import' tag should be added to 'file:///home/jiby/Dropbox/ID2208_shared%20with%20JB/SampleParser/ID2208_hw1/xml/employmentrecord.xsd'.
(I don't know if it can be useful, but here are the two xml files)
<?xml version="1.0" encoding="UTF-8"?>
<employment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="er"
xmlns:ci="companyInfos.xsd"
>
<ci:company>
<companyName>
Google
</companyName>
<foundationDate>
1995-09-15
</foundationDate>
<field>
Search engine
</field>
<employeeCount>
40000
</employeeCount>
<logo>
http://static3.wikia.nocookie.net/__cb20100520131748/logopedia/images/5/5c/Google_logo.png
</logo>
<description>
Google is an American multinational corporation specializing in Internet-related services and products. These include search, cloud computing, software, and online advertising technologies
</description>
</ci:company>
<position>Chief Finantial Opportunist</position>
<duration>1 year</duration>
<dateStart>2012-01-01</dateStart>
<current>false</current>
</employment>
<?xml version="1.0" encoding="UTF-8"?>
<company xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="ci">
<companyName>
Google
</companyName>
<foundationDate>
1995-09-15
</foundationDate>
<field>
Search engine
</field>
<employeeCount>
40000
</employeeCount>
<logo>
http://static3.wikia.nocookie.net/__cb20100520131748/logopedia/images/5/5c/Google_logo.png
</logo>
<description>
Google is an American multinational corporation specializing in Internet-related services and products. These include search, cloud computing, software, and online advertising technologies
</description>
<httpLink>http://google.com</httpLink>
</company>
We tried to look on the forums for an answer but the proposed solutions didn't seem to work, the file always had some issues for validation.
I think you are confused between namespace prefixes and namespace URIs. The namespace attribute of xs:importSchema and the targetNamespace attribute of xs:schema should both be URIs, and they should match. You should also bind a prefix to this URI and use this prefix in any references to names from the imported schema namespace.

Categories

Resources