我想知道是否可以对我的类进行注释,以便第一次编组遇到一个对象,它会生成一个相应类型的XML元素,但是任何其他任何后续对该对象的引用都将具有XML IDREF条目创建?
答案 0 :(得分:11)
您可以利用JAXB的XmlAdapter
概念执行以下操作:
<强> input.xml中强>
以下是我将用于此示例的XML文档。第3个phone-number
条目是对第1个phone-number
条目的引用,第5个phone-number
条目是对第4个条目的引用。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
<phone-number id="A">
<number>555-AAAA</number>
</phone-number>
<phone-number id="B">
<number>555-BBBB</number>
</phone-number>
<phone-number id="A"/>
<phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W">
<number>555-WORK</number>
<extension>1234</extension>
</phone-number>
<phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W"/>
</customer>
<强>客户强>
customer类维护一组PhoneNumber
个对象。 PhoneNumber的相同实例可能会在集合中多次出现。
package forum7587095;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Customer {
private List<PhoneNumber> phoneNumbers;
@XmlElement(name="phone-number")
public List<PhoneNumber> getPhoneNumbers() {
return phoneNumbers;
}
public void setPhoneNumbers(List<PhoneNumber> phoneNumbers) {
this.phoneNumbers = phoneNumbers;
}
}
<强> ******中国强>
这是一个可以出现在文档本身或作为参考的类。这将使用XmlAdapter
来处理。使用@XmlJavaTypeAdapter
注释配置XmlAdapter。由于我们在类型/类级别指定了此适配器,因此它将应用于引用PhoneNumber
类的所有属性:
package forum7587095;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlJavaTypeAdapter(PhoneNumberAdapter.class)
public class PhoneNumber {
private String id;
private String number;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
@Override
public boolean equals(Object arg0) {
if(null == arg0 || arg0.getClass() != this.getClass()) {
return false;
}
PhoneNumber test = (PhoneNumber) arg0;
if(!equals(id, test.getId())) {
return false;
}
return equals(number, test.getNumber());
}
protected boolean equals(String control, String test) {
if(null == control) {
return null == test;
} else {
return control.equals(test);
}
}
@Override
public int hashCode() {
return id.hashCode();
}
}
<强> WorkPhoneNumber 强>
根据您的评论,我添加了PhoneNumber
的子类。
package forum7587095;
public class WorkPhoneNumber extends PhoneNumber {
private String extension;
public String getExtension() {
return extension;
}
public void setExtension(String extension) {
this.extension = extension;
}
@Override
public boolean equals(Object arg0) {
if(!super.equals(arg0)) {
return false;
}
return equals(extension, ((WorkPhoneNumber) arg0).getExtension());
}
}
<强> PhoneNumberAdapter 强>
以下是XmlAdapter
的实施。请注意,如果之前看过PhoneNumber对象,我们必须维护。如果有,我们只填充id
对象的AdaptedPhoneNumber
部分。
package forum7587095;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class PhoneNumberAdapter extends XmlAdapter<PhoneNumberAdapter.AdaptedPhoneNumber, PhoneNumber>{
private List<PhoneNumber> phoneNumberList = new ArrayList<PhoneNumber>();
private Map<String, PhoneNumber> phoneNumberMap = new HashMap<String, PhoneNumber>();
@XmlSeeAlso(AdaptedWorkPhoneNumber.class)
@XmlType(name="phone-number")
public static class AdaptedPhoneNumber {
@XmlAttribute public String id;
public String number;
public AdaptedPhoneNumber() {
}
public AdaptedPhoneNumber(PhoneNumber phoneNumber) {
id = phoneNumber.getId();
number = phoneNumber.getNumber();
}
public PhoneNumber getPhoneNumber() {
PhoneNumber phoneNumber = new PhoneNumber();
phoneNumber.setId(id);
phoneNumber.setNumber(number);
return phoneNumber;
}
}
@XmlType(name="work-phone-number")
public static class AdaptedWorkPhoneNumber extends AdaptedPhoneNumber {
public String extension;
public AdaptedWorkPhoneNumber() {
}
public AdaptedWorkPhoneNumber(WorkPhoneNumber workPhoneNumber) {
super(workPhoneNumber);
extension = workPhoneNumber.getExtension();
}
@Override
public WorkPhoneNumber getPhoneNumber() {
WorkPhoneNumber phoneNumber = new WorkPhoneNumber();
phoneNumber.setId(id);
phoneNumber.setNumber(number);
phoneNumber.setExtension(extension);
return phoneNumber;
}
}
@Override
public AdaptedPhoneNumber marshal(PhoneNumber phoneNumber) throws Exception {
AdaptedPhoneNumber adaptedPhoneNumber;
if(phoneNumberList.contains(phoneNumber)) {
if(phoneNumber instanceof WorkPhoneNumber) {
adaptedPhoneNumber = new AdaptedWorkPhoneNumber();
} else {
adaptedPhoneNumber = new AdaptedPhoneNumber();
}
adaptedPhoneNumber.id = phoneNumber.getId();
} else {
if(phoneNumber instanceof WorkPhoneNumber) {
adaptedPhoneNumber = new AdaptedWorkPhoneNumber((WorkPhoneNumber)phoneNumber);
} else {
adaptedPhoneNumber = new AdaptedPhoneNumber(phoneNumber);
}
phoneNumberList.add(phoneNumber);
}
return adaptedPhoneNumber;
}
@Override
public PhoneNumber unmarshal(AdaptedPhoneNumber adaptedPhoneNumber) throws Exception {
PhoneNumber phoneNumber = phoneNumberMap.get(adaptedPhoneNumber.id);
if(null != phoneNumber) {
return phoneNumber;
}
phoneNumber = adaptedPhoneNumber.getPhoneNumber();
phoneNumberMap.put(phoneNumber.getId(), phoneNumber);
return phoneNumber;
}
}
<强>演示强>
为了确保整个XmlAdapter
和marshal
操作使用unmarshal
的相同实例,我们必须在Marshaller
和Unmarshaller
上专门设置XmlAdapter的实例。 package forum7587095;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Customer.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setAdapter(new PhoneNumberAdapter());
File xml = new File("src/forum7587095/input.xml");
Customer customer = (Customer) unmarshaller.unmarshal(xml);
System.out.println(customer.getPhoneNumbers().get(0) == customer.getPhoneNumbers().get(2));
System.out.println(customer.getPhoneNumbers().get(3) == customer.getPhoneNumbers().get(4));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setAdapter(new PhoneNumberAdapter());
marshaller.marshal(customer, System.out);
}
}
:
true
true
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
<phone-number id="A">
<number>555-AAAA</number>
</phone-number>
<phone-number id="B">
<number>555-BBBB</number>
</phone-number>
<phone-number id="A"/>
<phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W">
<number>555-WORK</number>
<extension>1234</extension>
</phone-number>
<phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W"/>
</customer>
<强>输出强>
{{1}}
了解更多信息