Как обрабатывать прямые ссылки на XML IDREF с помощью JAXB XmlAdapter во время демаршала?
Можно ли обрабатывать прямые ссылки XML IDREF
элементы в JAXB 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 при маршалинге, чтобы при первом маршалировании объекта он маршалировался путем локализации, а любые последующие вхождения этого объекта маршалировались по ссылке. Смотрите мой предыдущий вопрос. Однако из-за того, как создаются мои экземпляры XML-документов, первое появление Person
элемент может произойти после IDREF
с этим происходит.
Это то, что возможно? Или мне нужно подходить к этому по-другому? Спасибо!
1 ответ
У меня есть ответ на ваш связанный вопрос, я обрисовал, как XmlAdapter
может быть использован для реализации варианта использования, где первое вхождение объекта было маршалировано с помощью локализации / вложенности, а все другие вхождения были маршалированы посредством ссылки:
Опция 1 - @XmlID
/ @XmlIDREF
Если все ваши Person
все объекты представлены через вложение, и вы хотите ввести некоторые ключевые отношения, тогда вам лучше всего использовать @XmlID
пометить поле / свойство как ключ и @XmlID
сопоставить поле / свойство как внешний ключ. Ваш Person
класс будет выглядеть примерно так:
@XmlAccessorType(XmlAccessType.FIELD)
public class Person {
@XmlID
private String id;
@XmlIDREF
private Person guardian;
}
Для дополнительной информации
Вариант № 2 - Использование XmlAdapter
Если вы обновили XmlAdapter
из моего предыдущего ответа будет:
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-документы, которые выглядят следующим образом, где ссылка происходит в первую очередь:
<?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>