【问题标题】:JAXB : how to read the xsi:type value when unmarshallingJAXB:解组时如何读取 xsi:type 值
【发布时间】:2013-06-03 18:42:52
【问题描述】:

我在 XSD / XML 到 Java 方向中使用 JAXB。我的 XSD 包含派生类型,而我必须解组的 XML 包含 xsi:type 属性。查看生成的代码 JAXB(默认的 Sun 实现)(用于解组)似乎没有获取这些属性的方法。

是因为我总是可以对未编组的 Java 对象执行 getClass() 并找到实际的类吗?

不过,根据我提供给JAXBContext.newInstance 的包或类,不是可以实例化某些基类吗? (对应于 xsi:type 属性的实际值的类的超类)。在这种情况下,可能需要能够读取出现在 XML 实例中的实际属性的值。

【问题讨论】:

    标签: java xml jaxb xsd


    【解决方案1】:

    JAXB (JSR-222) 实现将为您处理一切。 JAXB 认为每个类都对应一个复杂类型。它有一个计算类型名称的算法,但您可以使用 @XmlType 注释覆盖它。如果元素包含xsi:type 属性,则当它被解组时,JAXB 将查看是否存在与该类型关联的类。如果存在,它将实例化该类型的类,如果不存在,它将根据通过注释提供的映射元数据实例化与该元素对应的类型。

    更多信息


    更新

    下面是一个可能有帮助的例子:

    schema.xsd

    在下面的 XML 模式中,复杂类型 canadianAddress 扩展了 complexType address

    <?xml version="1.0" encoding="UTF-8"?>
    <schema 
        xmlns="http://www.w3.org/2001/XMLSchema" 
        targetNamespace="http://www.example.org/customer" 
        xmlns:tns="http://www.example.org/customer" 
        elementFormDefault="qualified">
    
        <element name="customer">
            <complexType>
                <sequence>
                    <element name="address" type="tns:address"/>
                </sequence>
            </complexType>
        </element>
    
        <complexType name="address">
            <sequence>
                <element name="street" type="string"/>
            </sequence>
        </complexType>
    
        <complexType name="canadianAddress">
            <complexContent>
                <extension base="tns:address">
                    <sequence>
                        <element name="postalCode" type="string"/>
                    </sequence>
                </extension>
            </complexContent>
        </complexType>
    
    </schema>
    

    演示

    在下面的演示代码中,XML 将被转换为从上述 XML 模式生成的 JAXB 模型,然后再转换回 XML。

    import java.io.File;
    import javax.xml.bind.*;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance("org.example.customer");
    
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            File xml = new File("src/org/example/customer/input.xml");
            Customer customer = (Customer) unmarshaller.unmarshal(xml);
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(customer, System.out);
        }
    
    }
    

    input.xml/Output

    下面是 XML。 address 元素用xsi:type 限定,表示它拥有canadianAddress 的实例,而不仅仅是address

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <customer xmlns="http://www.example.org/customer">
        <address xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="canadianAddress">
            <street>1 A Street</street>
            <postalCode>Ontario</postalCode>
        </address>
    </customer>
    

    【讨论】:

    • 实际上,我在发布之前查看了您的博客文章,但它似乎侧重于 Java 到 XML 的方向。所以基本上,xsi:type 无法在解组中幸存下来?
    • @MarcusJuniusBrutus - 确实如此。有没有对应xsi:type属性值的类?
    • 是的,有对应的类。我只是推测,如果这样的类在 JAXBContext 中不可用,那么 JAXB 可能会实例化一个超类,在这种情况下我们会有某种“信息丢失”。但我没有尝试重现最后的假设情况。
    • @MarcusJuniusBrutus - 创建 JAXBContext 时是否使用包名(即 JAXBContext.newInstance("com.example.foo");
    • 在这种特殊情况下,是的,一个以冒号分隔的包名称列表。其他时候我使用了对象工厂,甚至是所有类的完整详细枚举(当我遇到这个问题时:java.net/jira/browse/JAXB-962
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多