如何在unmarshal期间使用JAXB XmlAdapter处理XML IDREF的前向引用?

时间:2011-09-30 23:53:24

标签: xml jaxb xml-parsing jaxb2 forward-reference

在解组过程中,是否可以在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发生后发生。

这是可能的吗?或者我需要以不同的方式处理这个问题?谢谢!

1 个答案:

答案 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;
    }

}