我正在使用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>
我怎样才能做到这一点?
答案 0 :(得分:2)
您可以使用@XmlElementRef和JAXBElement的组合来生成动态元素名称。
这个想法是:
Characteristic
设为JAXBElement
的子类,并覆盖getName()
方法,以根据characteristic
属性返回名称。characteristics
注释@XmlElementRef
。@XmlRegistry
(ObjectFactory
)提供@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):
<强>特性强>
我们将在此处使用@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)实施。
<强>特性强>
我们将使用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<Characteristic> 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<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 **/
}
编辑:如果您希望属性是动态的,那么您可以参考以下链接