Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAXB Unable To Handle Attribute with Colon (:) in name?

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""

like image 210
Jacob Zwiers Avatar asked Jun 09 '10 13:06

Jacob Zwiers


2 Answers

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.

like image 114
Jacob Zwiers Avatar answered Jan 21 '23 13:01

Jacob Zwiers


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.

like image 44
Joshua Cole Avatar answered Jan 21 '23 14:01

Joshua Cole