I have a question about retrieving data values which are sent from a web service. I have a web service which receives data from a client and then does something with it. It worked all perfectly.
But now I wanted to add an extra element to the xsd which handles the message the webservice receives. I've added tests to another complexType which also exists of other elements. The element tests isn't required, but users can add one or more tests in their XML file.
<xs:element name="tests">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="999">
<xs:element name="test">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element name="code" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="value" type="xs:string" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
Whole XSD: http://pastebin.com/TuvYiQzE
I am using JAXB to handle the webservice messages which are send from the client. JAXB automatically generated some code for me:
public Message.Algemeen.TestCode.Tests getTests(){
return tests;
}
And
public List<Message.Algemeen.TestCode.Tests.test> getTest() {
if (test== null) {
test= new ArrayList<Message.Algemeen.TestCode.Tests.test>();
}
return this.test;
}
Now I want to return code and value per element test, the problem is Test and tests are a returned as an object and at the moment I have no idea how to read their value. The method toString() just returns cp.jaxb.classes.Message$Algemeen$Testcode$Tests$test#dcd76a
What am I doing wrong? If you need more code to understand my problem please tell me.
Thanks,
Jef
PS. English isn't my native language, I tried my best to explain my problem.
This line <xs:sequence minOccurs="1" maxOccurs="unbounded"> in the definition of Test means that you can have several code:value pair in test. is this what you want?
I'm no jaxb expert but I was told when designing schemas that it's easier to used name types in this case.
Here you have an list of "unnamed" object (the code:value pair) in a test. And I guess that makes the retrieval difficult.
What happen if you changed to maxOccurs="1"?
what Happen if you defined a new type for your code:value pair and make a list of this element?
could you try to modify it like this:
<xs:element name="tests">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="999">
<xs:element name="test">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="unbounded">
<xs:element name="singleTest">
<xs:complexType>
<xs:sequence minOccurs="1" maxOccurs="1">
<xs:element name="code" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="value" type="xs:string" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
then you should be able to have something like
List testList = test.getSingleTest()
and iterate to get the code and value for each of them.
What language are you writing your client in? If you're using Java or .Net for example, you should simply be able to invoke your web service method and get a fully formed instance of Test back. As Udo Klimaschewski points out above, this means that you should be able to use something like
getTest().getCode()
To be clear, while it's potentially interesting to look through the XSD, you should not actually need to do this unless your development environment lacks SOAP web service support. The exact mechanism for generating the client side artifacts depends on your language and development environment; as an example, the process for referencing a web service using Netbeans is described here:
http://netbeans.org/kb/docs/websvc/client.html
This should work:
List<Message.Algemeen.TestCode.Tests.test> tests = yourObject.getTest();
for (Message.Algemeen.TestCode.Tests.test test : tests) {
test.getCode(); //Here is test object which contains strings or whatever.
}
Related
I use JAXB to convert an XML to a Java class. I have two Java classes: Milestone and Issue. Both have a unique ID and the ID fields are annotated with "#XMLID".
One milestone consists of several issues, so that it has a field variable "issues" holding a List. Issues and Milestones are both contained in parent class, so that Issues are no children of Milestones, but rather siblings. Using schemagen, I generated an XMLSchema to validate the XML file. The schema works well on everything except the "issues"-field of Milestone. Here, I had to manually change this line:
<xs:element name="issue" type="xs:IDREF" minOccurs="0" maxOccurs="unbounded"/>
to be of type IDREFS instead:
<xs:element name="issue" type="xs:IDREFS" minOccurs="0" maxOccurs="unbounded"/>
Now, it works perfectly. My question is: How do I have to annotate my field "issues" in the Milestone class so that I don't have to change the XMLSchema manually afterwards? I tried #XMLIDREFS but this does not seem to be valid.
Here are relevant parts of my code:
XMLSchema of Issue and Milestone
<xs:complexType name="issue">
<xs:element name="id" type="xs:ID" minOccurs="0"/>
</xs:complexType>
<xs:complexType name="milestone">
<xs:sequence>
<xs:element name="id" type="xs:ID" minOccurs="0"/>
<xs:element name="issue" type="xs:IDREFS" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
Java class Milestone with current annotation
public class Milestone {
private String id;
private List<Issue> issues = new LinkedList<>();
#XmlElement(name = "issue")
public List<Issue> getIssues() {
return issues;
}
Example XML
<RootElement>
<issue>
<id>IssueID1</id>
</issue>
<issue>
<id>IssueID2</id>
</issue>
<milestone>
<id>MilestoneID1</id>
<issue>IssueID1</issue>
<issue>IssueID2</issue>
</milestone>
</parent>
I have the following schema (fragment):
<xs:complexType name="partnerPaymentsItemType">
<xs:sequence>
<xs:element name="changeTime" type="dateTime"/>
<xs:element name="statusId" type="shortId"/>
<xs:element name="paymentPointId" type="shortString"/>
<xs:element name="money" type="currency"/>
<xs:element name="paymentDestination" type="shortString"/>
<xs:element name="paymentDestinationType" type="shortId"/>
<xs:element name="subagentId" type="shortId" minOccurs="0"/>
<xs:element name="discountCardNumber" type="xs:string" minOccurs="0"/>
<xs:element name="amountAll" type="currency" minOccurs="0"/>
<xs:element name="rewardPercent" type="percentAmount" minOccurs="0"/>
<xs:element name="rewardPercentValue" type="percentAmount" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="paymentTime" use="required" type="dateTime"/>
<xs:attribute name="externalId" use="required" type="id"/>
<xs:attribute name="registeredId" use="required" type="id"/>
</xs:complexType>
I use JibX Codegen tool to generate sources from it, and then to compile binding that should allow me to unmarshal XML to Java objects. Here is my codegen settings:
<schema-set xmlns:xs="http://www.w3.org/2001/XMLSchema"
delete-annotations="true"
prefer-inline="false"
generate-all="true"
show-schema="true"
type-substitutions="xs:date xs:string"
package="here.lays.my.package">
<class-decorator class="org.jibx.schema.codegen.extend.SerializableDecorator"/>
</schema-set>
Later, I try to parse an XML document which has namespace prefixes for both tags and attributes, which results an exception saying
Missing required attribute "paymentTime"
Debugging through JiBX sources shown that it tries to look for attribute with no namespace and name "paymentTime" in a document, while a document has an attribute with a namespace mapped to URL, and not able to find it of course.
I have decompiled binding with JAD and it searches for attribute with null namespace:
public static PartnerPaymentsItemType JiBX_beeline_binding_unmarshalAttr_1_93(PartnerPaymentsItemType arg1, UnmarshallingContext arg2)
throws JiBXException
{
arg2.pushTrackedObject(arg1);
arg1;
arg1.setPaymentTime(arg2.attributeText(null, "paymentTime"));
arg1.setExternalId(Utility.parseLong(WhitespaceConversions.trim(arg2.attributeText(null, "externalId"))));
arg1.setRegisteredId(Utility.parseLong(WhitespaceConversions.trim(arg2.attributeText(null, "registeredId"))));
arg2.popObject();
return arg1;
}
I would be grateful for any advise that could help resolving the issue - like, why JiBX generated such mapping, how to make it respect attribute namespace, and so on.
JiBX behavior was actually correct, namespace prefixes for attributes were not intended based on xsd.
Actual solution was to replace JiBX with XJC/JAXB and separate schema for the entity where I needed namespace prefixes for attributes.
Apologies if this is a duplicate question, but I could not find anything for my situation. So here goes:
I have the following in an xsd file:
<xs:complexType name="Allocation">
<xs:annotation>
<xs:documentation>Links its owner to an xs:id.</xs:documentation>
</xs:annotation>
<xs:attribute name="idRef" type="xs:IDREF"/>
</xs:complexType>
<xs:complexType name="XYZ">
<xs:sequence>
<xs:element name="SomeAllocation" type="Allocation"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ABC">
<xs:sequence>
<xs:element name="SomeAllocation" type="Allocation"/>
</xs:sequence>
</xs:complexType>
I am try to generate fields/getters and setters in java that are of specific types for example XYZ.getSomeAllocation() should return type Object1 and ABC.getSomeAllocation() should return type Object2. The problem I am facing is that xjc is generating one Allocation class and the XYZ and ABC classes with the methods mentioned below returning java.lang.Object types.
Obviously creating to different Allocation types which are then used in the different objects solves the problem but I would like to reuse the object holding the xs:IDREF.
Your help is highly appreciated!
Thanks!
Question is , for some reason. the xsd doesn't/can't define all logic vars other than basic properties and setters and getters, so we've tried to 'inject code' by xsd definition which are actually discussed by other folks couple of times. I have no problem with 'simple injection' with 'simple java method' which won't need any 'import' statement on top of class def.
yet somehow if we want to use it. it looks to me there is no way we could take or import any packages other than setter or getters. , see below for details
xsd definition test.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://company.com/schema/response"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:test="http://company.com/schema/response"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.1"
xmlns:ci="http://jaxb.dev.java.net/plugin/code-injector"
jaxb:extensionBindingPrefixes="ci">
<xs:element name="client">
<xs:complexType>
<xs:annotation>
<xs:appinfo>
<ci:code>
<![CDATA[
private String str;
public String returnStr() {
Locations locationCls =this.getLocations();
List<String> locationids = new ArrayList<String>();
// get a list of locationid into locationids (list)
List<Location> locationList = locationCls.getLocation();
for (Location loc : locationList) {
locationids.add(String.valueOf(loc.getId()));
}
// return string like loc1,loc2,loc3
return StringUtils.join(locationids, ',');
}
]]>
</ci:code>
</xs:appinfo>
</xs:annotation>
<xs:sequence>
<xs:element name="name" type="xs:NCName" />
<xs:element name="pass" type="xs:NCName" />
<xs:element ref="test:locations" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="locations">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="test:location" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="location">
<xs:complexType>
<xs:attribute name="id" use="required" type="xs:string" />
<xs:attribute name="address" use="required" type="xs:string" />
<xs:attribute name="biz" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:schema>
run jaxb ri command :
xjc.bat test.xsd -Xinject-code -extension
observe below code snippet in the Client.java successfully
private String str;
public String returnStr() {
Locations locationCls =this.getLocations();
List<String> locationids = new ArrayList<String>();
// get a list of locationid into locationids (list)
List<Location> locationList = locationCls.getLocation();
for (Location loc : locationList) {
locationids.add(String.valueOf(loc.getId()));
}
// return string like loc1,loc2,loc3
return StringUtils.join(locationids, ',');
}
As a consequence, we know jdk complains the compilation error as StringUtils in Apache commons ( or other 3rd part util tools like google collections to help in other scenarios) are not imported in generated file. understand there are some google projects which use jaxb plugin to insert or invoke method into generated java files. just want to spend day or so to see if we could make it by xsd itself only without any plugin. any idea would be appreciated .
You could specify the fully classified class name within the code that you want to inject, e.g.:
return org.apache.commons.lang.StringUtils.join(locationids, ',');
I want to write an xsd for the xmlrpc spec (and generate java classes out of it using jaxb). The xmlrpc spec allows values like:
<value><int>123</int></value>
<value><boolean>1</boolean></value>
But at the same time it requires:
If no type is indicated, the type is string.
Which means i could receive something like this:
<value>test123</value>
which is equivalent to
<value><string>test123</string></value>
Is there a way to define this in an xsd.
Yes, set a mixed content model on value:
<xs:complexType name="valuetype" mixed="true">
<xs:sequence>
<xs:element name="int" type="xs:int"/>
<xs:element name="boolean" type="xs:boolean"/>
...
</xs:sequence>
</xs:complexType>