如何使用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
。 - 为
@XmlRegistry
(ObjectFactory
)提供@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节点。 我们将使用XmlAdapter
将Characteristic
实例转换为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
这个XmlAdapter
将Characteristic
对象转换为DOM节点,从而允许我们根据需要构造它。
import javax.xml.bind.annotation.adapters.XmlAdapter; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.*; public class CharacteristicAdapter extends XmlAdapter
演示代码
演示
下面是一些将读/写所需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属性