问题描述
是否可以在解组过程中处理 JAXB XmlAdapter
中 XML IDREF
元素的前向引用?例如,我有以下 XML complexType
:
Is it possible to handle forward references of XML IDREF
elements in JAXB XmlAdapter
during the unmarshal process? For example, I have the following 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,以便第一次编组对象时,它由包含编组,并且此对象的任何后续出现都通过引用编组.请参阅我的的上一个问题.但是,由于我的 XML 实例文档的创建方式,Person
元素的第一次出现可能发生在 IDREF
之后.
where the guardian
field could reference another Person
-type element elsewhere in the document. I am currently using an XmlAdapter when marshalling so that the first time an object is marshalled, it is marshalled by containment, and any subsequent occurances of this object are marshalled by reference. See a previous question of mine. However, due to how my XML instance documents are created, the first occurrence of a Person
element could happen after an IDREF
to it occurs.
这是可能的吗?还是我需要以不同的方式处理这个问题?谢谢!
Is this something that is possible? Or do I need to approach this differently? Thanks!
推荐答案
我对你的相关问题 我概述了如何使用 XmlAdapter
来实现第一次出现一个对象是通过包含/嵌套编组的,所有其他事件都是通过引用编组的:
I have an answer to your related question I outlined how an XmlAdapter
could be used to implement the use case where the first occurrence of an object was marshalled via containment/nesting and all other occurrences were marshalled by reference:
选项 #1 - @XmlID
/@XmlIDREF
如果你所有的 Person
对象都是通过嵌套表示的,并且你想引入一些基于键的关系,那么你最好使用 @XmlID
来标记一个字段/属性作为键,@XmlID
将字段/属性映射为外键.你的 Person
类看起来像:
If all of your Person
objects are all represented through nesting and you want to introduce some key based relationships then you are best of using @XmlID
to mark a field/property as the key, and @XmlID
to map a field/property as a foreign key. Your Person
class would look something like:
@XmlAccessorType(XmlAccessType.FIELD)
public class Person {
@XmlID
private String id;
@XmlIDREF
private Person guardian;
}
了解更多信息
选项 #2 - 使用 XmlAdapter
如果您从我的 是:
If you updated the XmlAdapter
from my previous answer to be:
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;
}
}
然后您将能够解组如下所示的 XML 文档,其中引用首先发生:
Then you will be able to unmarshal XML documents that look like the following where the reference happens first:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
<phone-number id="A"/>
<phone-number id="B">
<number>555-BBBB</number>
</phone-number>
<phone-number id="A">
<number>555-AAAA</number>
</phone-number>
<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>
这篇关于如何在解组期间使用 JAXB XmlAdapter 处理 XML IDREF 的前向引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!