假设我有班级人员:
class Person{
String firstName;
String lastName;
String email;
}
XML格式为:
<person>
<firstName value="asd" />
<lastName value="bcd" />
<email value="qwe" />
</person>
我可以使用自己的XmlAdapter实现解组/编组这个类 字段FirstNameAdapter,LastNameAdapter,EmailAdapter。正如您所看到的,每个字段以类似的方式表示 - 字段名称为xml元素,字段值为元素属性。是否有可能创建“通用”适配器,我将能够转移该字段的名称,它将提取该字段的值?
P.S。我知道MOXy JAXB实现,但我想知道是否可以通过引用JAXB实现。
谢谢!
答案 0 :(得分:5)
您可以使用XmlAdapter
这样的内容:
import java.io.*;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.*;
@XmlType
class Valued {
@XmlAttribute(name="value")
public String value;
}
class ValuedAdapter extends XmlAdapter<Valued, String> {
public Valued marshal(String s) {
Valued v = new Valued();
v.value = s;
return v;
}
public String unmarshal(Valued v) {
return v.value;
}
}
@XmlRootElement
class Person {
@XmlJavaTypeAdapter(ValuedAdapter.class)
@XmlElement
String firstName;
@XmlJavaTypeAdapter(ValuedAdapter.class)
@XmlElement
String lastName;
}
class SO12928971 {
public static void main(String[] args) throws Exception {
Person p = new Person();
p.firstName = "John";
p.lastName = "Doe";
JAXBContext jc = JAXBContext.newInstance(Person.class);
StringWriter sw = new StringWriter();
jc.createMarshaller().marshal(p, sw);
String xml = sw.toString();
System.out.println(xml);
StringReader sr = new StringReader(xml);
p = (Person)jc.createUnmarshaller().unmarshal(sr);
assert "John".equals(p.firstName);
assert "Doe".equals(p.lastName);
}
}
这里的想法是XML Schema,因此JAXB明确区分了元素名称和内容类型,即使许多文档都有明确的一对一 - 这两者之间有一个对应。因此,在上面的代码中,类型 Valued
描述了具有value
属性的内容,而不考虑元素名称。要序列化的成员注释为@XmlElement
,该注释中不包含任何名称。因此,他们将生成具有从成员名称派生的名称的元素。 @XmlJavaTypeAdapter
注释会使序列化程序将这些成员视为其类型Valued
。这就是他们的XML内容类型。
上述代码的架构如下所示:
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="person" type="person"/>
<xs:complexType name="person">
<xs:sequence>
<xs:element name="firstName" type="valued" minOccurs="0"/>
<xs:element name="lastName" type="valued" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="valued">
<xs:sequence/>
<xs:attribute name="value" type="xs:string"/>
</xs:complexType>
</xs:schema>
答案 1 :(得分:0)
注意:我是EclipseLink JAXB (MOXy)主管,是 JAXB (JSR-222) 专家组的成员。
P.S。我知道MOXy JAXB的实现,但我想知道它是不是 可以通过参考JAXB实现。
为了比较,我已经添加了如何使用EclipseLink JAXB(MOXy)的@XmlPath
扩展来完成此操作。
<强>人强>
package forum12928971;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
class Person{
@XmlPath("firstName/@value")
String firstName;
@XmlPath("lastName/@value")
String lastName;
@XmlPath("email/@value")
String email;
}
<强> jaxb.properties 强>
要将MOXy指定为JAXB提供程序,您需要在与域模型相同的程序包中添加名为jaxb.properties
的文件,并使用以下条目:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
<强>演示强>
package forum12928971;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Person.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum12928971/input.xml");
Person person = (Person) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(person, System.out);
}
}
<强> input.xml中/输出强>
<?xml version="1.0" encoding="UTF-8"?>
<person>
<firstName value="asd"/>
<lastName value="bcd"/>
<email value="qwe"/>
</person>