Lawrence Tierney
Lawrence Tierney

Reputation: 898

JAXB - DO NOT unmarshall nested elements - possible?

I've inherited a project which uses JAXB heavily to map XML messages onto Java objects. The problem I have is that some of the data which I receive (in this case nested XML of unknown form) has NOT to be unmarshalled, rather captured as a String.

An example will help

<a>
   <b></b>
   <c></c>
   <d>
       <!-- "Unknown" XML here -->
       <maybeE></maybeE>
       <maybeF></maybeF>
       <!-- etc etc -->
   <d/>
</a>

So I would want the JAXB to unmarshall "b" and "c" but "d" it would capture the nested XML as a string i.e. not parsed.

So calling:

getD()

Would return string:

"<maybeE></maybeE><maybeF></maybeF>"

Upvotes: 4

Views: 4344

Answers (4)

bdoughan
bdoughan

Reputation: 149007

You can keep unknown XML using the @XmlAnyElement annotation. By default this will keep it as a DOM. If you want it stored in another format (such as String) then you can specify a DomHandler:

Full Example

Upvotes: 0

fuemf5
fuemf5

Reputation: 351

@Andrew B: Your code can even be improved:

public String getOperationsAsString() throws Exception{
    StringWriter writer = new StringWriter();
    Transformer transformer = TransformerFactory.newInstance().newTransformer();
    transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
    for (Node node: operations) {
        transformer.transform(new DOMSource(node), new StreamResult(writer));
    }
    return writer.toString();
}

That way, you create the Transformer only once and you do not need the StringBuilder. StringWriter already writes into a StringBuffer internally.

Upvotes: 1

Andrew B
Andrew B

Reputation: 1668

I found the above very useful; I had a similar mapping issue where I had HTML which was not escaped or encoded stored in an xml file - and I wanted to map this to a String property.

I used the annotation:

@XmlElementWrapper(name="operations")
@XmlAnyElement
private List<Node> operations;

Then used a transformer to print the node tree:

public String getOperationsAsString() throws Exception{
    StringBuilder builder = new StringBuilder();
    for (Node node: operations) {
        StringWriter writer = new StringWriter();
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        transformer.transform(new DOMSource(node), new StreamResult(writer));
        builder.append(writer.toString());
    }
    return builder.toString();
}

Upvotes: 1

skaffman
skaffman

Reputation: 403481

You can't capture the nested content as a String, but you can capture it as a DOM, e.g.

@XmlRootElement(name="a")
public class A {

   @XmlElement
   private String b;

   @XmlElement
   private String c;

   @XmlAnyElement
   private List<Element> content;
}

Whatever <a> contains, which does not match <b> or <c>, will be stored under content. You can then convert those Element objects into Strings, if you so wish.

Upvotes: 4

Related Questions