How to get XmlElement name in list of XmlElements

user63868 picture user63868 · Oct 5, 2013 · Viewed 8.3k times · Source

I am getting XML from a REST service that looks like:

<entity>
  <foo>
    <count>1</count>
    <date>1970-01-01</date>
    <margin>78.67</margin>
  </foo>
  <bar>
    <count>2</count>
    <date>1450-09-17</date>
    <margin>24.56</margin>
  </bar>
  <baz>
    <count>11</count>
    <date>1968-11-12</date>
    <margin>98.76</margin>
  </baz>
</entity>

And I'm parsing with a class Entity.java that has:

@XmlRootElement(name = "entity")
@XmlAccessorType(XmlAccessType.FIELD)
public class Entity implements Serializable {

  @XmlElements({
        @XmlElement(name="foo"),
        @XmlElement(name="bar"),
        @XmlElement(name="baz")
  })
  private List<EntityElement> entityElements;
....

With an EntityElement class like:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class EntityElement implements Serializable {
    @XmlElement(required = true)
    private int count

    @XmlElement(required = true)
    private String date;

    @XmlElement(required = false)
    private long margin;
....

This all works exactly like I expect and I get a list of EntityElements. What I would like to do is add a name field and have it populated with the name of the element that was found (a foo, bar, or baz) but I'm not seeing any way to do this. Any help or suggestions would be appreciated.

Answer

bdoughan picture bdoughan · Oct 5, 2013

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

You could use the @XmlVariableNode that we added to MOXy in EclipseLink 2.5.1 for this use case.

Java Model

Entity

We will use MOXy's @XmlVariableNode on the entityElements field. On the field we specify the field on the target class that represents the element name.

import java.io.Serializable;
import java.util.List;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlVariableNode;

@XmlRootElement(name = "entity")
@XmlAccessorType(XmlAccessType.FIELD)
public class Entity implements Serializable {

    @XmlVariableNode("name")
    private List<EntityElement> entityElements;

}

EntityElement

We will use the @XmlTransient annotation to prevent the value of the name field from being marshalled as a child element.

import java.io.Serializable;
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class EntityElement implements Serializable {

    @XmlTransient
    private String name;

    @XmlElement(required = true)
    private int count;

    @XmlElement(required = true)
    private String date;

    @XmlElement(required = false)
    private long margin;

}

jaxb.properties

To specify MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Demo Code

Demo

Since MOXy is a JAXB (JSR-222) implementation only the standard runtime APIs are required.

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Entity.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum19194567/input.xml");
        Entity entity = (Entity) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(entity, System.out);
    }

}

input.xml/Output

This is the XML document from your question.

<?xml version="1.0" encoding="UTF-8"?>
<entity>
   <foo>
      <count>1</count>
      <date>1970-01-01</date>
      <margin>0</margin>
   </foo>
   <bar>
      <count>2</count>
      <date>1450-09-17</date>
      <margin>0</margin>
   </bar>
   <baz>
      <count>11</count>
      <date>1968-11-12</date>
      <margin>0</margin>
   </baz>
</entity>

For More Information