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.
Related
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.
I'm not new to SOAP and turning WSDL's into POJO's. I've managed to connect to the web service and retrieve the data I need.
The problem rests in traversing the object hierarchy that the WSDL created.
Most of the variables stored in the generated classes are of the type JAXBElement<NameOfJavaClassHere>. So when ever I want that object I need to issue a call like ListOfEntitiesType loe = ents.getListOfEntities().getValue(); The .getValue() is where I have my issue.
Does there exist a way of making this a smoother integration? If I have to keep doing a getValue() it's going to be a death of 1000 cuts.
It feels like they left in a level of indirection at the client level that they didn't need to.
I've tried to unmarshal the xml with a JAXBContent object, there are a lot of examples on the net on how to do this, but it didn't work in this case. My object came out as null.
Should the WSDL not make POJO's that don't need all this casting about with generics?
Did I use the wrong settings on my wsimport command that came with java 1.7?
Should I use a different wsimport-ish program altogether to generate my POJO's?
If I have to stick with the .getValue() thing, I think I'd much rather make an xpath interface to the raw XML or turn the whole thing into Hashtables and ArrayLists than deal with this.
At least then, I'd have direct access to the info I want.
This XML schema has probably been developed under the influence of some bureaucratic rule. Consider, e.g.
<xs:element minOccurs="0" name="DUNSNumber" nillable="true" type="xs:string"/>
which results in a field
protected JAXBElement<String> dunsNumber;
causing the highly circumstantial get and set procedure you have (rightly) complained about. - What does the XML Schema entry mean? It says the element is a string, can be omitted and it must be possible to distinguish between an empty string and an absent string even when the element is present.
Here is a little experiment:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="1.0">
<xs:element name="root" type="RootType"/>
<xs:complexType name="RootType">
<xs:sequence>
<xs:element maxOccurs="unbounded" name="elem" type="ElemType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ElemType">
<xs:sequence>
<xs:element minOccurs="0" name="str01" type="xs:string"/>
<xs:element minOccurs="1" name="str1" type="xs:string"/>
<!-- The following element compiles to a JAXBElement<String> -->
<xs:element minOccurs="0" name="str01nil" nillable="true" type="xs:string"/>
<xs:element minOccurs="1" name="str1nil" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
And here is an XML file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
<elem>
<str01></str01>
<str1></str1>
<str01nil></str01nil>
<str1nil></str1nil>
</elem>
<elem>
<str1>must be there</str1>
<str01nil xsi:nil="true"></str01nil>
<str1nil>must be there</str1nil>
</elem>
</root>
And here is what is printed by an unmarshalling routine:
str01 []
str1 []
str01Nil []
str1Nil []
str01 [null]
str1 [must be there]
str01Nil [null]
str1Nil [must be there]
What happens if you omit <str01nil xsi:nil="true"></str01nil> completely? The outcome will be the same, method JAXBElement.getValue() will return null, and that's it.
Now (sorry for the length of the answer) we can discuss what you can do to return to "sane" Java code generated from the XML schema. I would simply remove nillable="true" and use the resulting code. If you marshal, a null in a field will not produce an element. On unmarshal, there's the weak chance that you see an empty element with an xsi:nil="true". (It is essential to retain minOccurs="0", though.)
There are a few use cases where a JAXBElement is required to be able to round trip XML as defined in the XML Schema. If you are seeing alot of JAXBElement in your generated model then several of these conditions are probably true.
An element is both nillable="true" and minOccurs="0". In this case what does null on the mapped field/property mean? When the property is JAXBElement a null value means the element isn't present and a JAXBElement wrapping null means an XML element with xsi:nil="true".
There are 2 global elements with the same named complex type. Since in JAXB classes correspond to complex types a way is needed to capture which root element was encountered.
http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html
There is a choice structure where either foo or bar elements can occur and they are the same type. Here a JAXBElement is required because simply encountering a String value isn't enough to indicate which element should be marshalled.
An element with xsi:nil is encountered in the document that contains attributes. In this example the object corresponding to that element can still be unmarshalled to hold the attribute values, but JAXBElement can stil indicate that the element was null.
Mechanisms to Reduce the Number of JAXBElement in the Model
Binding file with generateElementProperty set to false.
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb" xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
version="2.1">
<globalBindings>
<generateElementProperty>false</generateElementProperty>
</globalBindings>
</bindings>
Simple plugin for XJC - https://jaxb.java.net/2.1.2/docs/vendorCustomizations.html#simple
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb" xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
version="2.1">
<globalBindings>
<xjc:simple />
</globalBindings>
</bindings>
I've been trying to write junit test cases that figure check the syntax of an XML file, make sure all tags are closed, etc.
I am currently Using a dom parser in the test, as it throws an exception on invalid XML but it isn't working when I have an extra closing tag for my XML
eg: if i have
private static final String OM_APPLICATION_STRG = "<abc>**>**\r\n" +
"</abc>\r\n" +
"";
instead of
private static final String OM_APPLICATION_STRG = "<abc>\r\n" +
"</abc>\r\n" +
"";
Please let me know if there is any other way to test xml validity including extra closing tag
An "extra closing tag" is not a concept that exists. It is just a "greater-than" symbol in a text node in an XML file, and it's perfectly valid to have them. You don't need to check for them in your validator.
For example, this is completely valid xml:
<?xml version="1.0"?>
<xml>></xml>
May be there is another way —— SchemaFactory
You can define a .xsd file for your xml string, then use SchemaFactory to validate your xml string by the .xsd file.
Like this example
String xml = xmlFile.toString();
try {
URL schema = Resources.getResource("/XXX.xsd");
Validator validator = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema").newSchema(schema)
.newValidator();
Source source = new StreamSource(new CharArrayReader(xml.toCharArray()));
validator.validate(source);
} catch (Exception e) {
// the xml is not valid for your .xsd defination
}
<abc>**>**</abc>
is valid XML.
What you need to do is define a schema for XML and set restrictions on the content of text nodes.
A simple example would be schema.xsd
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="abc">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:pattern value="[\sa-zA-Z0-9\*]*" />
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
The regular expression
[\sa-zA-Z0-9\*]*
defines the set of character allowed in the text node inside of the element <abc>
The following document would validate
<?xml version="1.0"?>
<abc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="schema.xsd">
hello ** world
</abc>
If you add a > charcter
hello ** > ** world
the XML will no longer validate against the schema.
For validating against a schema see RomanticNerd's answer.
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.
This is my existing XSD schema in foo.xsd, that declares just the type:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0"
targetNamespace="foo">
<xs:complexType name="alpha">
<!-- skipped -->
</xs:complexType>
</xs:schema>
This is another schema, that declares the element:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0"
targetNamespace="foo">
<xs:import schemaLocation="foo.xsd" namespace="foo" />
<xs:element name="RootElement" type="alpha"/>
</xs:schema>
This is what I'm getting from SAX parser in Java:
"The namespace attribute 'foo' of an <import> element information
item must not be the same as the targetNamespace of the schema it exists in."
What am I doing wrong?
When the targetNamespace (tns) attributes of the involved XSDs are specified and the same, only xsd:include is allowed (a targetNamespace attribute cannot have empty string as its value).
However, one may include a schema (s1) without a tns from a schema (s2) that has a tns; the net effect is s1 components assume the namespace of the s2 schema. This usage is often referred to as chameleonic composition.
A reference on SO describing the difference between the two, is here.
From #Petru Gardea I am making it simpler for people who find it difficult to understand.
In root xsd where you want to import another XSD, Just use include tag as below. namespace not required here.
<xs:include schemaLocation="Child.xsd" />
targetNamespace is not mandatory.