I am trying to unmarshall the following XML using JAXB:
<Works>
<Work>
<Composers>
<Composer>
<Name>A name</Name>
</Composer>
<Composer>
<Name>A name 2</Name>
</Composer>
</Composers>
</Work>
</Works>
I have generated all of the classes using XJC. If I want to access the Composers collection, I have to do this:
List<Composer> composers = work.getComposers().getComposer();
Is there any way I can do the following instead?
List<Composer> composers = work.getComposers();
I appreciate the need for a Composers object as it derived from the XML, but when dealing in Java, having an intermediate POJO that stores the collections seems a bit redundant.
My XSD is:
<xsd:complexType name="Works">
<xsd:sequence>
<xsd:element name="Work" type="Work" maxOccurs="unbounded" minOccurs="0"></xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Work">
<xsd:sequence>
<xsd:element name="Composers" type="Composers"></xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Composers">
<xsd:sequence>
<xsd:element name="Composer" type="Composer" maxOccurs="unbounded" minOccurs="0"></xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Composer">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string"></xsd:element>
</xsd:sequence>
</xsd:complexType>
The #XmlElementWrapper plugin does exactly what you want.
For anybody who can not or does not want to use the plugin:
If you can live with a different XML structure, it's possible to avoid generating the extra wrapper classes by simply using maxoccurs="unbounded" and leaving out the containing element. Using the original example:
<xsd:element name="Work" type="Work" maxOccurs="unbounded" minOccurs="0"/>
<xsd:complexType name="Work">
<xsd:sequence>
<xsd:element name="Composer" type="Composer" maxOccurs="unbounded" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Composer">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string"></xsd:element>
</xsd:sequence>
</xsd:complexType>
will produce a structure like this:
<Work>
<Composer>
<Name>A name</Name>
</Composer>
<Composer>
<Name>A name 2</Name>
</Composer>
</Work>
This will put a method on the Work type that returns a List<Composer> object. Unfortunately the method is called getComposer instead of getComposers, but you can use annotations or custom bindings to fix that problem.
Related
So I have a task to complete for Friday involving creating a shares system and I'm completely lost in Netbeans. I've used it once before and did reasonably well but I've been stuck on this same issue for 2 hours now.
I've obviously gotta create the XML and accompanying schema for this project but started from a blank XSD now, I can't validate the code and also have troubles to create the constrained XML document from the XSD as there isn't a primary Element. If anyone could point me in the right direction that would be a great help. Me and Netbeans do not seem to get along. The XSD is as follows and yes, it's probably something completely obvious.
<xs:schema version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xsd:element name="shares">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="CompanyName" type="xsd:string"/>
<xsd:element name="CompanySymbol" type="xsd:string"/>
<xsd:element name="AvailableShares" type="xsd:string"/>
<xsd:element name="Updated" type="xsd:date"/>
<xsd:complexType>
<xsd:element name="Currency" type="xsd:float"/>
<xsd:element name="Value" type="xsd:float"/>
</xsd:complexType>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
The xml only declared the namespace xmlns:xs="http://www.w3.org/2001/XMLSchema" but uses instead the prefix xsd.
Also the closing </xsd:schema> is missing.
Here is the fixed xml:
<xsd:schema version="1.0"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xsd:element name="shares">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="CompanyName" type="xsd:string"/>
<xsd:element name="CompanySymbol" type="xsd:string"/>
<xsd:element name="AvailableShares" type="xsd:string"/>
<xsd:element name="Updated" type="xsd:date"/>
<xsd:complexType>
<xsd:element name="Currency" type="xsd:float"/>
<xsd:element name="Value" type="xsd:float"/>
</xsd:complexType>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
I have a problem with the following sequence of a wsdl file
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" name="allowCaseWithNewContract" type="xsd:boolean">
</xsd:element>
<xsd:choice minOccurs="0">
<xsd:element name="validationError" type="mnp:ErrorType"/>
<xsd:element name="internalError" type="mnp:ErrorType"/>
<xsd:element name="businessError" type="mnp:ErrorType"/>
<xsd:element name="externalError" type="mnp:ErrorType"/>
</xsd:choice>
</xsd:sequence>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" name="allowCaseWithExistingContract" type="xsd:boolean">
</xsd:element>
<xsd:choice minOccurs="0">
<xsd:element name="validationError" type="mnp:ErrorType"/>
<xsd:element name="internalError" type="mnp:ErrorType"/>
<xsd:element name="businessError" type="mnp:ErrorType"/>
<xsd:element name="externalError" type="mnp:ErrorType"/>
</xsd:choice>
</xsd:sequence>
I tried to use jaxb binding customization :
<?xml version="1.0" encoding="UTF-8"?>
<jxb:bindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">
<jxb:globalBindings>
<xjc:simple />
</jxb:globalBindings>
</jxb:bindings>
I'm trying to avoid jaxb - xjc from generating my fields as a List<JAXBElement<?>> validationErrorsAndAllowCaseWithExistingContractsAndInternalErrors, is there anyway I could accomplish that?
I advise you to simplify the schema if possible. I would put the allowCaseWithNewContract and allowCaseWithExistingContract as attributes in the enclosing element. I guess then, the remaining choice would have the type ErrorType.
I am not allowed to comment, but I believe this question has been solved here and here - basically your best shot is to use the JAXB2 Simplify Plugin as JAXB will prevent you from doing what you want as it wants the (de-)serialization to be consistent from XML to Java and back (i.e. you need to preserve the order).
I have below xsd elements.
<xsd:element name="requestOne" type="tns:RequestOne"/>
<xsd:complexType name="RequestOne">
<xsd:annotation>
<xsd:documentation>some comment</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="id" type="xsd:string" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="requestTwo" type="tns:RequestTwo"/>
<xsd:complexType name="RequestTwo">
<xsd:annotation>
<xsd:documentation>other comment</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="id" type="xsd:string" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
It has two complex elements but inside them there is duplicated code. How can i refactor above code?
Thanks!
Instead of creating a new element you can use ref to refer to an existing one, tns in the sample below refers to the name space defined by the schema
<xsd:element name="id" type="xsd:string"/>
...
<xsd:complexType name=RequestOne">
<xsd:sequence>
<xsd:element ref="tns:id" minOccurs="1" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
...
Though, this does not really reduces the number of characters to write, in that simple case. You might even have a look at how to define abstract types which, similar to object orientated languages, get inherited by children:
<xsd:complexType name="AbstractType" abstract="true">
<xsd:sequence>
<xsd:element name"BaseType">
<xs:complexType>
<xsd:sequence>
<xsd:element name="id" type="xsd:string" minOccurs="1" maxOccurs="1" >
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
the children now need to inherit from the abstract type in the following manner:
<xsd:complexType name="ChildOne">
<xsd:complexContent>
<xsd:extension base="tns:AbstractType">
<xsd:element name="newElement" type="xsd:string" />
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
Where newElement is just a new element defined by the child.
Edit: to be more precise, the id element is not really inherited like in an object oriented language but you achieve the same effect. The difference is, that you have to add the base-type within the XML of the concrete realization.
<ChildOne>
<BaseType>
<id>someId</id>
</BaseType>
<!-- elements defined by child one goes here -->
<newElement>new Element</newElement>
</ChildOne>
<xsd:element name="loginResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="loginReturn" type="tns:test"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="test">
<xsd:sequence>
<xsd:element minOccurs="0" maxOccurs="1" name="tx" type="xsd:int"/>
<xsd:element minOccurs="0" maxOccurs="1" name="result" type="xsd:int"/>
<xsd:element minOccurs="0" maxOccurs="1" name="name_space" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
I just want to ask why is the type tns:test used? How can I get the tx, result, namespace values in complextype name="test", because that's the response should I get based on the api they given to me.
tns is the target namespace prefix, which should be defined at the top of your WSDL or XSD file (which includes test).
You didn't wrote how you do access the values, but I assume that your code is working in a different namespace, so that test cannot be indentified. Most likely there is a method which allows you to get values by element name and namespace. Note that in that case, the namespace isn't tns but rather the URL which is defined at top of source file.
If you're not familiar with namespaces: Each XML element is associated with a namespace, like a class in Java is part of a package. In XML there is no import statement, so you have to name an element by name and namespace. To keep the files readable you can define namespace prefixes (probably as an abbreviation).
Using this simplified XSD (simplified, but still verbose as all XSDs tend to be):
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="[redacted]">
<xsd:element name="Statement" type="BILLINGSTATEMENTTYPEType"/>
<xsd:complexType name="BILLINGSTATEMENTTYPEType">
<xsd:sequence>
<xsd:element name="AccountSection" type="ACCOUNTSECTIONTYPEType"/>
<xsd:element name="DataSection" type="DATASECTIONTYPEType"/>
<xsd:element name="Summary" type="SUMMARYTYPEType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ACCOUNTSECTIONTYPEType">
<xsd:sequence>
<xsd:element name="Foo" type="xsd:string" maxOccurs="unbounded" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DATASECTIONTYPEType">
<xsd:sequence>
<xsd:element name="Bar" type="xsd:string" maxOccurs="unbounded" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="SUMMARYTYPEType">
<xsd:sequence>
<xsd:element name="Baz" type="xsd:string" maxOccurs="unbounded" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
I generated a JAR file (using the <xmlbean> Ant task from xmlbeans), and everything appears to look great, I get all the right types and whatnot. But when I have it parse this simplified document:
<Statement>
<AccountSection>
<Foo>bar</Foo>
</AccountSection>
<DataSection>
</DataSection>
<Summary>
</Summary>
</Statement>
Using this code:
public class XmlTest {
public static void main(String[] args) throws Exception {
File xmlFile = new File("./data/test.xml");
FileInputStream xmlStream = new FileInputStream(xmlFile);
BILLINGSTATEMENTTYPEType statement = BILLINGSTATEMENTTYPEType.Factory.parse(xmlStream);
ACCOUNTSECTIONTYPEType acctSection = statement.getAccountSection();
System.out.println(statement.xmlText());
System.out.println("acctSection is null:" + (acctSection == null));
}
}
The acctSection (and any of the child sections I've tried) are always null, even though it is fully parsing the document.
Output:
<Statement>
<AccountSection>
<Foo>bar</Foo>
</AccountSection>
<DataSection>
</DataSection>
<Summary>
</Summary>
</Statement>
acctSection is null:true
Why is it null? Why are they all null? Did I improperly define something somewhere in my XSD? I've used xmlbeans before successfully and never had this issue, which is why I'm sure I'm missing something but I've been unable to find it.
I'm not an export in xmlbeans myself, but I noticed that you used the Factory of the complex type to parse the xml. Can you try to use StatementDocument.Factory instead?
My problem was solved by adding elementFormDefault="qualified" in the namespace of my .xsd file.