In Java, Handler class contains method which name is startElement.this method has prototype:
public void startElement(String uri, String localName, String qName, Attributes attributes)
I have read on Oracle Java website, but I still not understand what different between localName and qName parameter.Here they explain:
localName - The local name (without prefix), or the empty string if
Namespace processing is not being performed.
qName - The qualified XML 1.0 name (with prefix), or the empty string if qualified names are not available.
In above definition, I don't know some concepts: prefix (prefix of what ?) Namespace
Who can explain for me (as most simple as you can) about these parameter, please.
thanks :)
As an example, I'm going to refer to the following XML sample:
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="note">
<xs:complexType>
<xs:sequence>
<xs:element name="to" type="xs:string"/>
<xs:element name="from" type="xs:string"/>
<xs:element name="heading" type="xs:string"/>
<xs:element name="body" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Namespace
A namespace is the logical container in which an element is defined. The XML Schema namespace (with uri: http://www.w3.org/2001/XMLSchema). In the above document, it is being referenced on line 2. XML document processing may occur using an XML parser which is either namespace-aware or not, but documents using namespaces will typically need to be parsed by namespace-aware parsers.
Namespaces are defined so that a) they can be cataloged by the parser and b) so that elements with the same name in different namespaces can exist in the same document without becoming ambiguously-defined.
Prefix
A prefix is the short-hand key used to refer to a namespace. In the above example, xs is used to refer to the XML Schema namespace.
Local Name (Part)
An element in a document has a name as it is defined in the namespace. In the above example, you can find schema, element, complexType, sequence, and element as local names. Local names can be ambiguous if you have multiple namespaces referenced in your document and one or more of those namespaces define elements with the same name.
Qualified Name (qName)
A qualified name consists of the prefix for the namespace (optionally, some implementations can use the namespace uri), followed by a :, followed by the element's local name. In the above example, you can find xs:schema, xs:element, xs:complexType, xs:sequence, and xs:element as qualified names. These names are unambiguous, and can be processed by the parser and validated.
Ryan's answer is excellent. The only other piece of information you need is that the exact details of what gets reported on the startElement event in SAX depend on various configuration settings of the SAX parser. Sadly, I don't have time to give the meticulous detail that Ryan has done.
In sax parser there are local name ,qname and namespace
qname is name of tag along with namespace while local name is only tag name. local name may be ambiguous but qname never.
QNames (Qualified Name) were introduced by XML Namespaces in order to be used as URI references. QName defines a valid identifier for elements and attributes. QNames are generally used to reference particular elements or attributes within XML documents and provide a mechanism for concisely identifying a {URI, local-name} pair. Namespaces can also be declared in the XML root element
Example:
<?xml version='1.0'?>
<doc xmlns:x="http://example.com/ns/foo">
<x:p/>
</doc>
The QName x:p is a concise, unambiguous name for the {URI, local-name} pair {"http://example.com/ns/foo", "p"}. Where doc is local name.
Java Analogy:
com.prem.java.Employee employee; //creating object using fully qualified name i.e. QName
Student student; //create an object using local name
Related
When a complexType is marked with mixed="true" in XSD, the generated Java class produces a List with either a "String" type or a JAXBElement wrapper around the actual value. Without mixed="true", the JAXBElement is not produced and the value is directly mapped to the type class. Eg:
<xs:complexType name="div" mixed="true">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="a" minOccurs="0" maxOccurs="unbounded" type="anchorType"/>
</xs:sequence>
...
</complexType>
Here the div type would contain a a List getContent() method that either returns a String or a JAXBElement for AnchorType.
I wanted it to return just either String or AnchorType without the JAXBElement.
Consider this XML which contains a div tag and some child tags:
<parentTag>
<div>myPlainTextValue<a/><a/></div>
</parentTag>
But the mixed content in an XML document does not necessarily occur in a single block.
This XML is also valid according to the XSD:
<parentTag>
<div>my<a/>Plain<a/>Text<a/>Value</div>
</parentTag>
In both cases, the text content of the tag 'div' is 'myPlainTextValue'. But in the second example it is distributed in 4 smaller chunks in between the child tags. JAXB needs to generate code that can handle the general case, so I would not expect it to have a special mode for your case.
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 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.
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.