【问题标题】:How to handle forward references of XML IDREF with JAXB XmlAdapter during unmarshal?如何在解组期间使用 JAXB XmlAdapter 处理 XML IDREF 的前向引用?
【发布时间】:2011-11-28 20:25:39
【问题描述】:

是否可以在解组过程中处理 JAXB XmlAdapter 中 XML IDREF 元素的前向引用?例如,我有以下 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-type 元素。我目前在编组时使用 XmlAdapter,以便第一次编组对象时,它由包含编组,并且该对象的任何后续出现都通过引用进行编组。请参阅mine 的上一个问题。但是,由于我的 XML 实例文档的创建方式,Person 元素的第一次出现可能在 IDREF 出现之后发生。

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

【问题讨论】:

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


    【解决方案1】:

    我对您的related question 有一个回答我概述了如何使用XmlAdapter 来实现对象的第一次出现通过包含/嵌套编组并且所有其他事件通过引用编组的用例:

    选项 #1 - @XmlID/@XmlIDREF

    如果您的所有Person 对象都通过嵌套表示,并且您想引入一些基于键的关系,那么您最好使用@XmlID 将字段/属性标记为键,并使用@XmlID 进行映射字段/属性作为外键。你的 Person 类看起来像:

    @XmlAccessorType(XmlAccessType.FIELD)
    public class Person {
    
        @XmlID
        private String id;
    
        @XmlIDREF
        private Person guardian;
    }
    

    更多信息

    选项 #2 - 使用 XmlAdapter

    如果您将我的previous answer 中的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>
    

    【讨论】:

    • option 1 & option 2step 1 & step 2?
    • 好问题。似乎只要您不使用 XMLAdapters,前向引用就可以开箱即用。只有使用 XMLAdapter,您才需要关心自己。
    猜你喜欢
    • 2021-08-23
    • 1970-01-01
    • 2011-10-19
    • 2017-06-05
    • 2016-02-02
    • 1970-01-01
    • 2021-07-23
    • 2013-01-17
    相关资源
    最近更新 更多