XSD / JAXB:由具有相同名称的元素限定的多个元素的序列

时间:2013-07-01 16:04:13

标签: jaxb xsd sequences

我的模型元素可能包含几个不同类型的子元素。对于每种类型,可能只存在0或1个子元素。定义了这些元素的顺序,即类型A的所有元素都在B之前。我的模型类由JAXB生成,因此应该为每种类型的子元素都有一个单独的getter / setter属性。

使事情变得复杂的是上述规则的一个例外:在子元素列表的开头和结尾处,每个元素可能出现0或1个X元素,并且这些元素都具有相同的名称。 / p>

这是我当前现实生活XSD类型的略微简化版本:

<xs:complexType name="Activity">
    <xs:sequence>
        <xs:element name="log" type="DiagnosticLogMessage" minOccurs="0" maxOccurs="1" />
        <xs:element name="inputs" type="Mappings" minOccurs="0" maxOccurs="1" />
        <xs:element name="outputs" type="Mappings" minOccurs="0" maxOccurs="1" />
        <xs:element name="log" type="DiagnosticLogMessage" minOccurs="0" maxOccurs="1" />
        <xs:element name="to" type="DirectConnection" minOccurs="0" maxOccurs="1" />
    </xs:sequence>
</xs:complexType>

“log”是有问题的元素。使用上面的类型定义,“to”正确获取其自己的属性,但其余元素将进入名为“logsAndInputsAndOutputs”的列表中。如果我将两个“log”元素重命名为“logBefore”和“logAfter”,则每个元素都有自己的属性,所以很明显问题是JAXB无法区分这两个“日志”。

我理解XSD本身并不是非常精确:它允许单个“log”类型的子元素,在这种情况下,如果将其视为“before”或“after”元素,则它是未定义的。在我当前(手动编写的)读者类中,我有明确的代码来检测这种情况并将单个“log”元素解释为“before”元素。

我正在寻找一种方法来告诉JAXB以不同方式处理这两个“log”元素,或者通过xjb映射,或者可能使用更具体的XSD。

1 个答案:

答案 0 :(得分:1)

注意:我是EclipseLink JAXB (MOXy)主管,是JAXB (JSR-222)专家组的成员。

以下是利用MOXy @XmlPath扩展程序处理此用例的方法。

XML架构(schema.xsd)

以下是基于您在问题中提供的片段的XML架构。

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="urn:forum17408865" xmlns="urn:forum17408865"
    elementFormDefault="qualified">

    <xs:element name="foo">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="bar" type="Activity"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="Activity">
        <xs:sequence>
            <xs:element name="log" type="DiagnosticLogMessage"
                minOccurs="0" maxOccurs="1" />
            <xs:element name="inputs" type="Mappings" minOccurs="0"
                maxOccurs="1" />
            <xs:element name="outputs" type="Mappings" minOccurs="0"
                maxOccurs="1" />
            <xs:element name="log" type="DiagnosticLogMessage"
                minOccurs="0" maxOccurs="1" />
            <xs:element name="to" type="DirectConnection" minOccurs="0"
                maxOccurs="1" />
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="DiagnosticLogMessage" />

    <xs:complexType name="Mappings" />

    <xs:complexType name="DirectConnection" />

</xs:schema>

<强>活动

MOXy具有@XmlPath扩展名,允许您根据其位置映射到XML元素。无法从XML模式生成此类,因此我们将自己创建它。

package forum17408865;

import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder={"log1", "inputs", "outputs", "log2", "to"})
public class Activity {

    @XmlPath("log[1]")
    private DiagnosticLogMessage log1;

    private Mappings inputs;

    private Mappings outputs;

    @XmlPath("log[2]")
    private DiagnosticLogMessage log2;

    private DirectConnection to;

}

<强> binding.xml

要让JAXB使用我们手动创建的类,我们将利用JAXB绑定文件。

<jxb:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:jxb="http://java.sun.com/xml/ns/jaxb" version="2.1">

    <jxb:bindings schemaLocation="schema.xsd">
        <jxb:bindings node="//xs:complexType[@name='Activity']">
            <jxb:class ref="forum17408865.Activity" />
        </jxb:bindings>
    </jxb:bindings>

</jxb:bindings>

XJC致电

以下是利用绑定文件的XJC调用。请注意我们还需要使用-nv标志来禁用模式验证。

xjc -nv -b binding.xml schema.xs

了解更多信息