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

时间:2014-10-12 12:37:01

标签: java xml 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);
}

这是我得到的结果:

<characteristics characteristic="store_capacity">40</characteristics>
<characteristics characteristic="number_of_doors">4</characteristics>

我想得到以下结果:

<store_capacity>40</store_capacity>
<number_of_doors>4</number_of_doors>

我怎样才能做到这一点?

4 个答案:

答案 0 :(得分:2)

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

这个想法是:

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

下面是working test

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

@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);
}

产地:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<characteristics><store_capacity>40</store_capacity></characteristics>

让我们从characteristics根元素类开始。它具有characteristics属性,注释为@XmlElementRef。这意味着内容应该是JAXBElement s或@XmlRootElement - 带注释的类实例。

@XmlRootElement(name = "characteristics")
public class Characteristics {

    private final List<Characteristic> characteristics = new LinkedList<Characteristic>();

    @XmlElementRef(name = "characteristic")
    public List<Characteristic> getCharacteristics() {
        return characteristics;
    }

}

为了实现此功能,您还需要ObjectFactory或带有@XmlRegistry注释的具有相应@XmlElementDecl的内容:

@XmlRegistry
public class ObjectFactory {

    @XmlElementDecl(name = "characteristic")
    public JAXBElement<String> createCharacteristic(String value) {
        return new Characteristic(value);
    }

}

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

public class Characteristic extends JAXBElement<String> {
    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元素。

测试代码为available on GitHub

答案 1 :(得分:2)

如果您使用EclipseLink MOXy作为JAXB (JSR-222)提供商,则可以针对此用例利用我们的@XmlVariableNode扩展名(请参阅:http://blog.bdoughan.com/2013/06/moxys-xmlvariablenode-json-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<Characteristic> 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的文件,其中包含以下内容(请参阅:http://blog.bdoughan.com/2011/05/specifying-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中/输出

<?xml version="1.0" encoding="UTF-8"?>
<characteristics>
   <store_capacity>40</store_capacity>
   <number_of_doors>4</number_of_doors>
</characteristics>

答案 2 :(得分:1)

以下方法适用于任何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<Characteristic> 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<Object, Characteristic> {

    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的代码。请注意,setAdapter上的Marshaller来电不是必需的,但会带来性能提升,因为它会导致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中/输出

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<characteristics>
    <store_capacity>40</store_capacity>
    <number_of_doors>4</number_of_doors>
</characteristics>

答案 3 :(得分:0)

您可以将您的课程指定为:

@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 **/
}

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

getting Dynamic attribute for element in Jaxb