Jesse van Bekkum
Jesse van Bekkum

Reputation: 1526

Two different but identically named elements in jaxb

I am trying to use JAXB to parse the following XML. I removed irrelevant parts. Unfortunately the original XML is generated by a third party application and I do not have the DTD or an XSD file available, so I am building my JAXB code by hand.

<add>
  <add-attr attr-name="UserName">
    <value type="string">User1</value>
  </add-attr>
  <add-attr attr-name="Name">
    <value type="structured">
      <component name="familyName">Doe</component>
      <component name="givenName">John</component>
    </value>
  </add-attr>
</add>

The problem is of course the <value> element. This can be a element with plain text, or if its attribute type is "structured, a list of <component> elements.

I have created two classes (value1 and value2) which implement the two options, but I cannot tell JAXB which one to use, because the elements are both named "value". Is there any solution?

Upvotes: 1

Views: 469

Answers (2)

bdoughan
bdoughan

Reputation: 149047

Option #1 - One Value Class

You could have one Value class that includes a String property annotated with @XmlMixed.

package forum13232991;

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Value {

    @XmlAttribute
    String type;

    @XmlMixed
    List<String> value;

    @XmlElement(name="component")
    List<Component> components;

}

Option #2 - Multiple value Classes Via XmlAdapter

If you want them to be separate classes you could leverage an XmlAdapter for this:

ValueAdapter

package forum13232991;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class ValueAdapter extends XmlAdapter<Value, Object> {

    @Override
    public Value marshal(Object object) throws Exception {
        Value value = new Value();
        if(object instanceof StructuredValue) {
            StructuredValue structuredValue = (StructuredValue) object;
            value.type = "structured";
            value.components = structuredValue.components;
        } else {
            StringValue stringValue = (StringValue) object;
            value.value.add(stringValue.value);
        }
        return value;
    }

    @Override
    public Object unmarshal(Value value) throws Exception {
        if("string".equals(value.type)) {
            StringValue stringValue = new StringValue();
            StringBuilder strBldr = new StringBuilder();
            for(String string : value.value) {
                strBldr.append(string);
            }
            stringValue.value = strBldr.toString();
            return stringValue;
        } else {
            StructuredValue structuredValue = new StructuredValue();
            structuredValue.components = value.components;
            return structuredValue;
        }
    }

}

AddAttr

package forum13232991;

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

public class AddAttr {

    @XmlJavaTypeAdapter(ValueAdapter.class)
    Object value;

}

For More Information

Upvotes: 2

Pace
Pace

Reputation: 43937

One approach would be to create an XSL transformation which added an xsi:type attribute to the value elements based on the type attribute. All your Value elements could then extend from the same BaseValue class and the add-attr element could have a reference to this BaseValue.

Upvotes: 1

Related Questions