在解组过程中,是否可以在JAXB IDREF
中处理XML XmlAdapter
元素的前向引用?例如,我有以下XML complexType
:
<xs:complexType name="person">
<xs:complexContent>
<xs:sequence>
<xs:element name="dateOfBirth" type="xs:dateTime" minOccurs="0"/>
<xs:element name="firstName" type="xs:string" minOccurs="0"/>
<xs:element name="gender" type="xs:string" minOccurs="0"/>
<xs:element name="guardian" type="xs:IDREF" minOccurs="0"/>
<xs:element name="homePhone" type="xs:string" minOccurs="0"/>
<xs:element name="lastName" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexContent>
</xs:complexType>
其中guardian
字段可以引用文档中其他位置的另一个Person
- 类型元素。我正在编组时使用XmlAdapter,以便第一次对象进行编组时,它会被包含编组,并且此对象的任何后续出现都将通过引用进行编组。请参阅上一期mine的问题。但是,由于我的XML实例文档的创建方式,Person
元素的第一次出现可能会在IDREF
发生后发生。
这是可能的吗?或者我需要以不同的方式处理这个问题?谢谢!
答案 0 :(得分:6)
我对你的related question有一个答案我概述了如何使用XmlAdapter
来实现第一次出现的对象通过包含/嵌套编组并且所有其他事件都被编组的用例参考:
选项#1 - @XmlID
/ @XmlIDREF
如果您的所有Person
个对象都是通过嵌套表示的,并且您想要引入一些基于关键字的关系,那么您最好使用@XmlID
将字段/属性标记为键,并且{ {1}}将字段/属性映射为外键。您的@XmlID
课程类似于:
Person
了解更多信息
选项#2 - 使用@XmlAccessorType(XmlAccessType.FIELD)
public class Person {
@XmlID
private String id;
@XmlIDREF
private Person guardian;
}
如果您将XmlAdapter
的{{1}}更新为:
XmlAdapter
然后,您将能够解组首先出现引用的XML文档:
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) {
if(adaptedPhoneNumber.number != null) {
phoneNumber.setNumber(adaptedPhoneNumber.number);
}
return phoneNumber;
}
phoneNumber = adaptedPhoneNumber.getPhoneNumber();
phoneNumberMap.put(phoneNumber.getId(), phoneNumber);
return phoneNumber;
}
}