2

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

使事情复杂化的是上述规则的一个例外:在子元素列表的开头和结尾附近可能分别出现 0 或 1 个 X 类型的元素,并且这些元素都具有相同的名称。

这是我当前现实生活中 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>

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

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

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

4

1 回答 1

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;

}

绑定.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

了解更多信息

于 2013-07-02T17:10:08.967 回答