Read XML with XSD schema in java (android) - java

I am receiving a XML string from a webserver that contains a XSD schema-definition in the beginning looking like this:
...
<xs:sequence>
<xs:element name="" .../>
<xs:element name="" .../>
...
</xs:sequence>
...
The attribute name defines the tags of a dataset in the xml part of the string that is underneath the schema-definition, looking like this:
...
<DataSet id="DataSet1">
<name1>value</name1>
<name2>value</name2>
...
</DataSet>
<DataSet id="DataSet2">
<name1>value</name1>
<name2>value</name2>
...
</DataSet>
...
Can someone give me an advice how to parse this.
PS: The number of elements defining the names is variable and can be different everytime so these tags are not static.

I guess that you don't just want to parse it, you also want to process it after parsing (unfortunately this misuse of the word "parse" is becoming endemic). Parsing should be trivial assuming that the file as a whole is well-formed XML (which you haven't said). Processing depends entirely on what you want to do with the data. For example, some kinds of processing might need the schema information, other kinds might not.

Related

Unmarshalled object is null if namespace prefix is not set

I have the following XSD:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:x="MY_NAMESPACE"
targetNamespace="MY_NAMESPACE">
<xs:element name="response" type="x:responseType"/>
<xs:complexType name="responseType">
<xs:all>
<xs:element name="param" type="x:responseParam"/>
</xs:all>
</xs:complexType>
<xs:complexType name="responseParam">
<xs:all>
<xs:element name="value" type="xs:string"/>
</xs:all>
</xs:complexType>
</xs:schema>
I use it to generate JAXB classes for unmarshalling a payload like the following:
<x:response xmlns:x="MY_NAMESPACE">
<param>
<value>OK</value>
</param>
</x:response>
via getWebServiceTemplate().marshalSendAndReceive in Spring. Problem is, I also want to unmarshal payloads without the namespace prefix, like this:
<response xmlns="MY_NAMESPACE">
<param>
<value>OK</value>
</param>
</response>
In this case, the response tag is parsed correctly, but the object reference representing param is always null. How can I edit my XSD to make things work? I already tried setting elementFormDefault="qualified" in the schema, or even form="qualified" on the param element.
Additional info that comes to mind (I might edit and add more depending on comments):
The unmarshaller is a Jaxb2Marshaller.
The XML documents
I think you probably know this, but removing that namespace prefix affects the entire document (because the 'param' and 'value' tags do not have any prefix and therefore inherit the default namespace binding). Becauses of this, in the first document the root tag 'response' is in namespace 'MY_NAMESPACE' and the other tags do not have any namespace. In the second document, all of the tags are in namespace 'MY_NAMESPACE'.
The XML Schema
The elementFormDefault attribute defaults to 'unqualified' so your schema should match the first document and reject the second. Your experiments confirm this.
If you set elementFormDefault to 'qualified' then it will reject the first document and match the second one.
There is no value of elementFormDefault that will make the XSD match both XML documents. The namespace is an integral part of the identity of the element.
Possible solution
If you are determined to construct an XSD that matches both documents then it could be done as follows:
explicitly set elementFormDefault to 'unqualified' (optional, but you're about to rely on that setting)b
wrap the current (globally-declared) contents of responseType in a choice group
add a second branch in the choice group containing a local declaration of element 'param' and all of its descendants. Because those are locally declared, they will be in noTargetNamespace.
This is not a general solution to the problem of making JAXB ignore namespaces, and I don't think you will find one (although I'm happy to be corrected by somebody who knows more than I do about JAXB).
Having said all of the above...I think you are probably solving the wrong problem. The JAXB standard is based on XML Schema. An XSD is not meant to tolerate the wrong namespaces. The second XML document is therefore invalid, and should be corrected by whoever is generating it.

Jaxb customization of nillable attribute value for a specific field

I'm working with an XSD schema file (that I cannot change) that defines element XXX as following:
<xsd:element name="XXX" type="Date" minOccurs="0"/>
This produces a java.util.Date in the generated class.
I would need to change how the field is marshalled to XML: if the attribute is null, I would like to produce an empty tag, like if the xsd was:
<xsd:element name="XXX" type="Date" minOccurs="0" nillable=true/>
This produces a JaxbElement in the generated class.
Is it possible to do something like this via Jaxb bindings?
Regards
Giulio
Suggestions:
Pre-process your schema with an XSLT to add nillable where you need it.
Use the jaxb2-simplify-plugin and customize your element with simplify:as-reference-property. I have actually never tried that but maybe it'll work.
Write an XJC plugin.
ps. I'm the author of the mentioned jaxb2-simplify-plugin.
Yes you can.. but isn't a good practice.
<bindings node="//xs:element[#name='XXX']">
<property name="xxx">
<baseType>
<javaType name= "javax.xml.bind.JAXBElement<java.util.Date>"/>
</baseType>
</property>
</bindings>
you should add also below attributes within <javaType> See here Documentation
parseMethod is the name of the parse method to be called during
unmarshalling.
printMethod is the name of the print method to be
called during marshalling.

set limit to number of children in an element in xml

I have an XML file as follows
<abc>
<property>
<Recentlyopenedfiles>
<File Path="c:\hai.txt" />
<File Path="C:\old.java" />
</Recentlyopenedfiles>
</property>
</abc>
I am using jdom2 SAXBuilder to parse the xml in java.I need to save all recently opened files in <Recentlyopenedfiles>. At the maximum this has to hold only three paths(i.e) 3 recently opened files path.
So,I need to know
Are there any mechanism to set limit to child nodes?
How to index child and perform stack operation so that last opened file
saved in first file path.
Thanks.
Jon's answer is closest to what I would recommend. The mecahinics of it are easier than it sounds though:
Document doc = saxbuilder.build(....);
Element abc = doc.getRootElement();
Element recentelement = abc.getChild("properties").getChild("Recentlyopenedfiles");
List<Element> recentfiles = recentelement.getChildren("File");
recentfiles.add(0, new Element("File").setAttribute("Path", filepath));
while (recentfiles.size() > 3) {
recentfiles.remove(3);
}
XMLOutputter xout = new XMLOutputter(Format.getPrettyFormat());
xout.output(doc, outputstream);
There are declarations in XSD to limit the number of child elements, but I don't think that's relevant in your particular case. When it comes to parsing and then modifying the XML, you'll just need to perform the limiting by hand.
In terms of "stacking" - if you just always add items to the start of the element rather than at the end (using parent.addContent(0, newChild)) , you'll end up with the last one you add being the first in the document. You can then count how many you've got, and remove any extra ones.
You can limit number of child nodes by using XSD schema and validate your XML file against it. Here you can find how to set max number of nodes.
You can use DOM parser. You can iterate through all nodes in XML on the same level and count number of "File" nodes.
If you need to parser HUGE XML file, DOM parser may be not appropriate. In this case StAX parser can be a better choice. Just count number of times "File" open tag occurred and handle a case if it occurs more than 3 times.
Setting limit to the child nodes. Assuming that you do not create the XMLs that you parse, you can define the number of child elements in schema (XSD)
Something like:
<xs:element name="pets">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="dog" type="xs:string"/>
<xs:element name="cat" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
If you then add the elements from the code then just add them always on top:
Use addContent with index=0 as described here
elem.addContent(0, newChild);

Can one teach JAXB to generate Java classes including comments? [duplicate]

I'm currently working with an XML Schema that has <xsd:annotation>/<xsd:documentation> on most types and elements. When I generate Java Beans from this XML Schema, then the Javadoc of those Beans only contains some generic generated information about the allowed content of the type/element.
I'd like to see the content of the <xsd:documentation> tag in the relevant places (for example the content of that tag for a complextType should show up in the Javadoc of the class generated to represent that complexType).
Is there any way to achieve this?
Edit: this XML Schema will be used in a WSDL with JAX-WS, so this tag might be appropriate as well.
Edit 2: I've read about <jxb:javadoc>. From what I understand I can specify that either in a separate JAXB binding file or directly in the XML Schema. That would almost solve my problem. But I'd rather use the existing <xsd:documentation> tag, since Javadoc is not the primary target of the documentation (it's information about the data structure primarily and not about the Java Beans generated from it) and to allow non-JAXB tools to access the information as well. Providing the documentation in both <jxb:javadoc> and xsd:documentation> "feels" wrong, because I'm duplicating data (and work) for no good reason.
Edit 3: Thanks to the answer by Pascal I realized that I already have half a solution: The <xsd:documentation> of complexTypes is written to the beginning of its Javadoc! The problem is still that only that complexTypes is used and simpleTypes (which can also result in a class) and elements are still Javadoc-less.
I've never been able to get regular xsd:documentation to be placed in the java source except if and only if it was a Complex Type. Documentation for elements, simple types,
etc are ignored.
So, I end up using jxb:javadoc. To do so, include the definition of xmlns:jxb="http://java.sun.com/xml/ns/jaxb" in your <xsd:schema> element.
Add a child to <xsd:complexType> or <xsd: element> or <xsd:attribute>:
<xsd:annotation><xsd:appinfo><jxb:XXX><jxb:javadoc>
This is my comment for a class/property
</jxb:javadoc></jxb:XXX></xsd:appinfo></xsd:annotation>
Where XXX is either "class" or "property".
For a package you write a child to xsd:schema
<xsd:annotation><xsd:appinfo><jxb:schemaBindings><jxb:package name="com.acme"><jxb:javadoc>
This is my comment for a package
</jxb:javadoc></jxb:package></jxb:schemaBindings></xsd:appinfo></xsd:annotation>
Writing HTML document requires bracketing with <![CDATA[ --- ]]>
(EDIT: While writing my answer, the question has been edited by the OP so I'm updating it accordingly)
In my case, javadoc was the only target so it was acceptable to use jxb:javadoc. But your update makes perfect sense and, actually, I totally agree with you. Sadly, I never found an ideal solution for the situation you describe (so I'll follow this question very carefully). Maybe you could use something like xframe to generate documentation from xsd:documentation, but this doesn't answer the question.
This just isn't possible with the JAXB reference implementation. Even if you were to try to write an XJC plugin, you'd find that the plugin API is given no reference to the Schema definition, so there's no way to extract this information.
Our only hope is that a future version of JAXB fixes the situation. There's an open feature request here.
I find the following techniques work pretty well for adding JavaDoc headers to Java element classes (generated from XML schemas). I nest the JavaDoc in tags defined in the jax-b namespace, nested within the xml schema annotation and appinfo tags. Note the jaxb namespace defines types of documentation tags; I use two of there: the class and the property tags. defined in the following namespace: xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
1) To document a class, I use a jaxb "class" tag in the following sequence:
<xs:complexType name="Structure">
<xs:annotation>
<xs:appinfo>
<jxb:class>
<jxb:javadoc>
Documentation text goes here. Since parsing the schema
into Java involves evaluating the xml, I escape all
the tags I use as follows <p> for <p>.
</jxb:javadoc>
</jxb:class>
</xs:appinfo>
</xs:annotation>
.
.
.
</xs:complexType>
2) To document an element, I use the "property" tag as follows:
<xs:element name="description" type="rep:NamedString">
<xs:annotation>
<xs:appinfo>
<jxb:property>
<jxb:javadoc>
<p>Documentation goes here.</p>
</jxb:javadoc>
</jxb:property>
</xs:appinfo>
</xs:annotation>
</xs:element>
3) I use the same set of tags to document attributes:
<xs:attribute name="name" type="xs:NCName" use="required">
<xs:annotation>
<xs:appinfo>
<jxb:property>
<jxb:javadoc>
<p>Documentation goes here.</p>
</jxb:javadoc>
</jxb:property>
</xs:appinfo>
</xs:annotation>
</xs:attribute>
4) To document a choice, I use the property jaxb tag, and I document the choice.
<xs:choice maxOccurs="unbounded">
<xs:annotation>
<xs:appinfo>
<jxb:property>
<jxb:javadoc>
<p>Documentation goes here.</p>
</jxb:javadoc>
</jxb:property>
</xs:appinfo>
</xs:annotation>
<xs:element name="value" type="rep:NamedValue" />
<xs:element name="list" type="rep:NamedList" />
<xs:element name="structure" type="rep:NamedStructure" />
</xs:choice>
Attempting to document the individual choices here would fail, since this tag
produces an untyped list.
Especially for that case I wrote XJC plugin xjc-documentation-annotation-plugin.
What it does: <annotation><documentation> -> Java class annotations
Said we have this object described in XSD:
<xs:complexType name="CadastralBlock">
<xs:annotation>
<xs:documentation>Cadastral quarter</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="number" type="xs:string">
<xs:annotation>
<xs:documentation>Cadastral number</xs:documentation>
</xs:annotation>
</xs:element>
</xs:complexType>
We run xjc like:
xjc -npa -no-header -d src/main/generated-java/ -p xsd.generated scheme.xsd
And got class like (getters, setters and any annotations omitted for simplicity):
public class CadastralBlock {
protected String number;
}
But in my case I want known how to class and fields was named in source file! So it what this plugin do!
So you get:
#XsdInfo(name = "Cadastral quarter", xsdElementPart = "<complexType name=\"CadastralBlock\">\n <complexContent>\n <restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n <sequence>\n <element name=\"number\" type=\"{http://www.w3.org/2001/XMLSchema}string\"/></sequence>\n </restriction>\n </complexContent></complexType>")
public class CadastralBlock {
#XsdInfo(name = "Cadastral number")
protected String number;
}
How to use
Manual call in commandline
If you want run it manually ensure jar class with plugin in run classpath and just add option -XPluginDescriptionAnnotation. F.e.:
xjc -npa -no-header -d src/main/generated-java/ -p xsd.generated -XPluginDescriptionAnnotation scheme.xsd
Call from Java/Groovy
Driver.run(
[
'-XPluginDescriptionAnnotation'
,'-d', generatedClassesDir.absolutePath
,'-p', 'info.hubbitus.generated.test'
,'CadastralBlock.xsd'
] as String[]
,new XJCListener() {...}
)
See test XJCPluginDescriptionAnnotationTest for example.
Use from Gradle
With gradle-xjc-plugin:
plugins {
id 'java'
id 'org.unbroken-dome.xjc' version '1.4.1' // https://github.com/unbroken-dome/gradle-xjc-plugin
}
...
dependencies {
xjcClasspath 'info.hubbitus:xjc-documentation-annotation-plugin:1.0'
}
// Results by default in `build/xjc/generated-sources`
xjcGenerate {
source = fileTree('src/main/resources') { include '*.xsd' }
packageLevelAnnotations = false
targetPackage = 'info.hubbitus.xjc.plugin.example'
extraArgs = [ '-XPluginDescriptionAnnotation' ]
}
Complete gradle example in example-project-gradle directory of project.

Parse XML Scheme file and retrieve values in Android

I have an XML Scheme file like the following.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="urn:myNS"
targetNamespace="urn:myNS"
attributeFormDefault="unqualified"
elementFormDefault="qualified">
<xs:element name="some_name">
<xs:complexType>
<xs:all>
...
I need to get the values of targetNamespace and element name into Strings (in Android).
Is there a parser to do it? Can anybody suggest a way to do it?
Coding examples would be appreciated.
Android support some XML parsers used in Java i.e. SAX Parser, DOM Parser and PULL Parser etc. You can use any of them. This link may help you.

Categories

Resources