How to deal with JAXB ComplexType with MixedContent data?

Oscar Jara picture Oscar Jara · Sep 24, 2012 · Viewed 13.6k times · Source

I got this XML structure:

<Tax>
  <Money currency="USD">0.00</Money>
  <Description xml:lang="en">
     17.5% Non-Recoverable
    <ShortName>vatspecial</ShortName>
  </Description>
</Tax>

Notice that Description node has MixedContent (composed with text and XML) and this is the XSD part regarding Description node:

<xsd:complexType name="TaxDescriptionType">
  <xsd:sequence>
    <xsd:element name="ShortName" type="xsd:string" />
  </xsd:sequence>
  <xsd:attribute ref="xml:lang" />
</xsd:complexType>

Everything is ok at this point, XJC outputs the generated classes like this one regarding TaxDescriptionType:

package org.com.project;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

/**
 * <p>Java class for TaxDescriptionType complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType name="TaxDescriptionType">
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="ShortName" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *       &lt;/sequence>
 *       &lt;attribute ref="{http://www.w3.org/XML/1998/namespace}lang"/>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "TaxDescriptionType", propOrder = {
    "shortName"
})
public class TaxDescriptionType {

    @XmlElement(name = "ShortName", required = true)
    protected String shortName;
    @XmlAttribute(name = "lang", namespace = "http://www.w3.org/XML/1998/namespace")
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    @XmlSchemaType(name = "NCName")
    protected String lang;

    /**
     * Gets the value of the shortName property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getShortName() {
        return shortName;
    }

    /**
     * Sets the value of the shortName property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setShortName(String value) {
        this.shortName = value;
    }

    /**
     * Gets the value of the lang property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getLang() {
        return lang;
    }

    /**
     * Sets the value of the lang property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setLang(String value) {
        this.lang = value;
    }

}

Then, with the above class I am able to work around with the elements like this:

taxDescriptionType.setLang("en");
taxDescriptionType.setShortName("vatspecial");
/* missing value: 17.5% Non-Recoverable */

But the problem is that I can't found a way to get or set the 17.5% Non-Recoverable text of the MixedContent-ComplexType from the above XML example.


This is what I tried and it's not working:

  • Used mixed="true" attribute like this:

<xsd:complexType name="TaxDescriptionType" mixed="true">

(I think XJC is ignoring the last attribute)


Doing some research, I found this:

JAXB XJC compiler disregarding mixed=true on XML Schema documents

But I am not sure if this is the way to solve this. One of the answers said that this is a bug and in the other one shows a code that transforms the MixedContent into a List<Serializable> and maybe the next situation will be about how to deal with this:

taxDescriptionType.getContent().add(Serializable element);

(And I really don't know how to deal with a Serializable element)

Answer

bdoughan picture bdoughan · Sep 24, 2012

As you mentioned you need to add the mixed attribute to indicate that your type supports mixed content. Without this specified your XML content is invalid:

<xsd:complexType name="TaxDescriptionType" mixed="true">
    <xsd:sequence>
        <xsd:element name="ShortName" type="xsd:string" />
    </xsd:sequence>
    <xsd:attribute ref="xml:lang" />
</xsd:complexType>

The generated TaxDescriptionType class will have the following property. Essentially this means that all of the non-attribute content will be stored in a List. This is necessary because you need a mechanism that indicates where the text nodes are wrt the element content.

@XmlElementRef(name = "ShortName", namespace = "http://www.example.org/schema", type = JAXBElement.class)
@XmlMixed
protected List<Serializable> content;

You will populate this list with instances of String (representing text nodes) and JAXBElement (representing element content).


ALTERNATIVELY

Mixed content generally makes life more complicated than it needs to be. If possible I would recommend an alternate XML representation.

<Tax>
  <Money currency="USD">0.00</Money>
  <Description xml:lang="en" ShortName="vatspecial">
    17.5% Non-Recoverable
  </Description>
</Tax>

Or

<Tax>
  <Money currency="USD">0.00</Money>
  <Description xml:lang="en">
    <LongName>17.5% Non-Recoverable</LongName>
    <ShortName>vatspecial</ShortName>
  </Description>
</Tax>