如何使用JAXB使类字段成为标记名称?

我正在使用Java和JAXB进行XML处理。

我有以下课程:

public class Characteristic { private String characteristic; private String value; @XmlAttribute public String getCharacteristic() { return characteristic; } public void setCharacteristic(String characteristic) { this.characteristic = characteristic; } @XmlValue public String getValue() { return value; } public void setValue(String value) { this.value = value; } } public static void main(String[] args) { Characteristic c = new Characteristic(); c.setCharacteristic("store_capacity"); c.setValue(40); Characteristic c2 = new Characteristic(); c2.setCharacteristic("number_of_doors"); c2.setValue(4); } 

这是我得到的结果:

 40 4 

我想得到以下结果:

 40 4 

我怎样才能做到这一点?

您可以使用@XmlElementRef和JAXBElement的组合来生成动态元素名称。

这个想法是:

  • 使Characteristic成为JAXBElement的子类,并覆盖getName()方法以基于characteristic属性返回名称。
  • 使用@XmlElementRef注释characteristics
  • @XmlRegistryObjectFactory )提供@XmlElementDecl(name = "characteristic")

以下是工作测试 。

测试本身(没什么特别的):

 @Test public void marshallsDynamicElementName() throws JAXBException { JAXBContext context = JAXBContext.newInstance(ObjectFactory.class); final Characteristics characteristics = new Characteristics(); final Characteristic characteristic = new Characteristic( "store_capacity", "40"); characteristics.getCharacteristics().add(characteristic); context.createMarshaller().marshal(characteristics, System.out); } 

生产:

  40 

让我们从characteristics根元素类开始。 它有一个使用@XmlElementRef注释的characteristics属性。 这意味着内容应该是JAXBElement@XmlRootElement -annotated类实例。

 @XmlRootElement(name = "characteristics") public class Characteristics { private final List characteristics = new LinkedList(); @XmlElementRef(name = "characteristic") public List getCharacteristics() { return characteristics; } } 

为了使其工作,您还需要一个ObjectFactory或带有@XmlRegistry注释的具有相应@XmlElementDecl

 @XmlRegistry public class ObjectFactory { @XmlElementDecl(name = "characteristic") public JAXBElement createCharacteristic(String value) { return new Characteristic(value); } } 

回想一下, characteristics属性必须包含@XmlRootElement -annotated类实例或JAXBElement@XmlRootElement不合适,因为它是静态的。 但JAXBElement是动态的。 您可以JAXBElement并覆盖getName()方法:

 public class Characteristic extends JAXBElement { private static final long serialVersionUID = 1L; public static final QName NAME = new QName("characteristic"); public Characteristic(String value) { super(NAME, String.class, value); } public Characteristic(String characteristic, String value) { super(NAME, String.class, value); this.characteristic = characteristic; } @Override public QName getName() { final String characteristic = getCharacteristic(); if (characteristic != null) { return new QName(characteristic); } return super.getName(); } private String characteristic; @XmlTransient public String getCharacteristic() { return characteristic; } public void setCharacteristic(String characteristic) { this.characteristic = characteristic; } } 

在这种情况下,我重写了getName()方法以动态确定元素名称。 如果设置了characteristic属性,则其值将用作名称,否则方法将选择默认characteristic元素。

测试代码可在GitHub上获得 。

如果您使用EclipseLink MOXy作为JAXB(JSR-222)提供程序,那么您可以利用我们的@XmlVariableNode扩展来处理此用例(请参阅: http : @XmlVariableNode schema.html ):

Java模型

特点

我们将在此处利用@XmlVariableNode扩展。 此批注指定引用类中的字段/属性以用作元素名称。

 import java.util.List; import javax.xml.bind.annotation.*; import org.eclipse.persistence.oxm.annotations.XmlVariableNode; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Characteristics { @XmlVariableNode("characteristic") private List characteristics; } 

特性

我们需要将characteristic字段/属性标记为@XmlTransient因此它不会显示为子元素。

 import javax.xml.bind.annotation.*; @XmlAccessorType(XmlAccessType.FIELD) public class Characteristic { @XmlTransient private String characteristic; @XmlValue private String value; } 

jaxb.properties

要将MOXy指定为JAXB提供程序,您需要在类路径上安装EclipseLink,并在域模型所在的包中包含一个名为jaxb.properties的文件, jaxb.properties包含以下内容(请参阅: http : //blog.bdoughan.com/2011/ 05 / specified-eclipselink-moxy-as-your.html )。

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

演示代码

演示

这是一些将读/写所需XML的演示代码。 请注意如何使用标准JAXB API。

 import java.io.File; import javax.xml.bind.*; public class Demo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Characteristics.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); File xml = new File("input.xml"); Characteristics characteristics = (Characteristics) unmarshaller.unmarshal(xml); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(characteristics, System.out); } } 

input.xml中/输出

   40 4  

以下方法适用于任何JAXB(JSR-222)实现。

Java模型

特点

我们将利用XmlAnyElement注释。 这个注释为我们提供了很多灵活性,可以保存什么类型的数据,包括DOM节点。 我们将使用XmlAdapterCharacteristic实例转换为DOM节点。

 import java.util.List; import javax.xml.bind.annotation.*; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Characteristics { @XmlAnyElement @XmlJavaTypeAdapter(CharacteristicAdapter.class) private List characteristics; } 

特性

就JAXB而言,这个类不再是我们模型的一部分。

 public class Characteristic { String characteristic; String value; } 

CharacteristicAdapter

这个XmlAdapterCharacteristic对象转换为DOM节点,从而允许我们根据需要构造它。

 import javax.xml.bind.annotation.adapters.XmlAdapter; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.*; public class CharacteristicAdapter extends XmlAdapter { private Document doc; public CharacteristicAdapter() { try { doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); } catch(Exception e) { throw new RuntimeException(e); } } @Override public Characteristic unmarshal(Object v) throws Exception { Element element = (Element) v; Characteristic characteristic = new Characteristic(); characteristic.characteristic = element.getLocalName(); characteristic.value = element.getTextContent(); return characteristic; } @Override public Object marshal(Characteristic v) throws Exception { Element element = doc.createElement(v.characteristic); element.setTextContent(v.value); return element; } } 

演示代码

演示

下面是一些将读/写所需XML的代码。 请注意, Marshaller上的setAdapter调用不是必需的,但是性能会提高,因为它会导致重用XmlAdapter

 import java.io.File; import javax.xml.bind.*; public class Demo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Characteristics.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); File xml = new File("input.xml"); Characteristics characteristics = (Characteristics) unmarshaller.unmarshal(xml); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.setAdapter(new CharacteristicAdapter()); marshaller.marshal(characteristics, System.out); } } 

input.xml中/输出

   40 4  

您可以将您的class级指定为:

 @XmlRootElement(name = "Characteristic") public class Characteristic { @XmlElement(name = "store_capacity") protected String storeCapacity; @XmlElement(name = "number_of_doors") protected String numberOfDoors; /** getters and setters of above attributes **/ } 

编辑 :如果您希望属性是动态的,那么您可以参考下面的链接

在Jaxb中获取元素的Dynamic属性