XSD/JAXB: последовательность нескольких элементов, ограниченных элементами с одинаковыми именами.

Мой элемент модели может содержать несколько дочерних элементов разных типов. Для каждого типа может присутствовать только 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". Если я переименую два элемента «журнала» в «logBefore» и «logAfter», каждый элемент получит свое собственное свойство, поэтому очевидно, что проблема в том, что JAXB не может различать два «журнала».

Я понимаю, что сам XSD не совсем точен: он допускает один дочерний элемент типа «журнал», и в этом случае он не определен, следует ли считать его элементом «до» или «после». В моем текущем (написанном вручную) классе чтения у меня есть явный код для обнаружения этого случая и интерпретации одного элемента «журнала» как элемента «до».

Я ищу способ сообщить JAXB по-разному относиться к двум элементам журнала, либо с помощью сопоставлений xjb, либо, возможно, с более конкретным XSD.


person Marian Schedenig    schedule 01.07.2013    source источник


Ответы (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

Для получения дополнительной информации

person bdoughan    schedule 02.07.2013
comment
Это именно то, что я искал. Я пытался использовать индексы XPath в моем файле привязок JAXB, но XJC не мог их различить. Было бы еще лучше, если бы я мог указать свойства XmlPath в своих XML-привязках и получить автоматически созданные классы, но на данный момент у меня нет проблем с созданием классов из слегка упрощенной схемы, а затем копированием и ручным изменением их в мои статические исходники. - person Marian Schedenig; 03.07.2013