Question

I am attempting to use JAXB to unmarshall an XML files whose schema is defined by a DTD (ugh!).

The external provider of the DTD has specified one of the element attributes as xml:lang:

<!ATTLIST langSet
id ID #IMPLIED
xml:lang CDATA #REQUIRED
>

This comes into the xjc-generated class (standard generation; no *.xjb magic) as:

@XmlAttribute(name = "xml:lang", required = true)
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
protected String xmlLang;

However, when unmarshalling valid XML files with JAXB, the xmlLang attribute is always null.

When I edited the XML file, replacing xml:lang with lang and changed the @XmlAttribute to match, unmarshalling was successful (i.e. attributes were non-null).

I did find this http://old.nabble.com/unmarshalling-ignores-element-attribute-%27xml%27-td22558466.html. But, the resolution there was to convert to XML Schema, etc. My strong preference is to go straight from an un-altered DTD (since it is externally provided and defined by an ISO standard).

Is this a JAXB bug? Am I missing something about "namespaces" in attribute names?

FWIW, java -version = "build 1.6.0_20-b02" and xjc -version = "xjc version "JAXB 2.1.10 in JDK 6""

Was it helpful?

Solution

Solved the issue by changing replacing xml: with a namespace declaration in the JAXB-generated class:

@XmlAttribute(name = "lang", namespace="http://www.w3.org/XML/1998/namespace", required = true)

Which makes sense, in a way.

Without this kind of guidance, how would JAXB know how to interpret the otherwise-undefined namespace xml:? Unless, of course, it implemented some special-case internal handling to xml: as done in http://java.sun.com/javase/6/docs/api/javax/xml/stream/XMLStreamReader.html#getNamespaceURI%28java.lang.String%29 (see the first NOTE:)

Whether it's a bug in xjc's generation of the annotated objects or a bug in the unmarhaller, or simply requires a mapping somewhere in the xjc process is still an open question in my mind.

For now, it's working and all it requires is a little xjc magic, so I'm reasonably happy.

OTHER TIPS

Disclaimer: Although 8 years late, I am adding this answer for lost souls such as myself trying to understand auto generation of java files from a DTD.

You can set project wide namespaces for the unmarshaller to work with directly in the project-info.java file via the @XmlSchema option.

This file should be automatically generated by xjc when generating classes from a schema, however it appears xjc does not automatically generate the package-info.java file when generating from a DTD!

However, you can manually make this file, and add it to the same package as the files generated by xjc.

The file would look like the following:

package-info.java :

@XmlSchema(
    elementFormDefault=XmlNsForm.QUALIFIED, 
    xmlns = {
            @XmlNs(prefix="xlink", namespaceURI="http://www.w3c.org/1999/xlink"),
            @XmlNs(prefix="namespace2", namespaceURI="http://www.w3c.org/1999/namespace2")
    }) 

package your.generated.package.hierarchy;
import javax.xml.bind.annotation.*;

You can add as many namespaces as required, simply add a new line in the form:

@XmlNs(prefix="namespace", namespaceURI="http://www.uri.to.namespace.com")

The benefit of doing it this way, rather than compared to editing the generated @XmlAttribute is that you do not need to change each generated XmlAttribute, and you do not need to manually remove the namespaces from the XmlAttribute name variable.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top