Дочерний тип переопределяет только один элемент из родительского типа

В файле XSD необходимо определить:

  • родительский тип (который содержит 10 узлов).
  • 7 дочерних типов (каждый дочерний тип содержит одинаковые 10 узлов, но тип 2-го узла отличается).

Это можно сделать, определив дочерние типы ограничением родительского типа (родительский тип будет базовым типом для дочерних типов). Проблема: в дочерних типах мне приходится заново прописывать все узлы родительского типа (а не только 2-й узел). Вопрос: Могу ли я написать только тот узел, который переопределяю (второй узел)?

Пример: если я определяю следующий родительский тип:

<xs:complexType name="Parent">
    <xs:sequence>
        <xs:element name="Node1" type="type1" />
        <xs:element name="Node2" type="type2" />
        <xs:element name="Node3" type="type3" />
        ...
        <xs:element name="Node10" type="type10" />
    </xs:sequence>
</xs:complexType>

тогда я должен определить дочерние элементы по ограничению родителя:

<xs:complexType name="Child1">
    <xs:complexContent>
        <xs:restriction base="Parent">
            <xs:sequence>
                <xs:element name="Node1" type="type1" />
                <xs:element name="Node2" type="type2_derived_1" />
                <xs:element name="Node3" type="type3" />
                ...
                <xs:element name="Node10" type="type10" />
            </xs:sequence>
        </xs:restriction>
    </xs:complexContent>
</xs:complexType> 

<xs:complexType name="Child2">
    <xs:complexContent>
        <xs:restriction base="Parent">
            <xs:sequence>
                <xs:element name="Node1" type="type1" />
                <xs:element name="Node2" type="type2_derived_2" />
                <xs:element name="Node3" type="type3" />
                ...
                <xs:element name="Node10" type="type10" />
            </xs:sequence>
        </xs:restriction>
    </xs:complexContent>
</xs:complexType> 

...
(same for all the 10 childs)

Это много написанного и ДУБЛИРУЕМОГО кода (для каждого дочернего элемента мне приходится СНОВА писать все исходные узлы, которые уже есть у родителя). Я бы предпочел написать только узел, который я переопределяю, примерно так:

<xs:complexType name="Child1">
    <xs:complexContent>
        <xs:restriction base="Parent">
            <xs:changed>
                <xs:element name="Node2" type="type2_derived_1" />
            </xs:changed>
        </xs:restriction>
    </xs:complexContent>
</xs:complexType> 

<xs:complexType name="Child2">
    <xs:complexContent>
        <xs:restriction base="Parent">
            <xs:changed>
                <xs:element name="Node2" type="type2_derived_2" />
            </xs:changed>
        </xs:restriction>
    </xs:complexContent>
</xs:complexType> 

...
(same for all the 10 childs)

Есть ли способ избежать дублирования кода? Я использую XSD 1.1, поэтому могу использовать все его расширенные функции.

Я знаю, что могу использовать расширение вместо ограничения: например, я мог бы исключить 2-й узел из родительского типа и добавить его по расширению в дочерние элементы. Но в этом случае это будет не 2-й узел, а 10-й узел. Я хочу переопределить (или добавить) 2-й узел у дочерних элементов.


Обновление: решено. Мне нравится обходной путь, предложенный Спербергом-Маккуином: группы моделей. Группа моделей похожа на макрос в C, ее содержимое расширяется. Таким образом, я могу определить группу моделей для узлов перед измененным узлом и другую группу моделей для узлов после него. Например:

<xs:group name="g_node_1">
    <xs:sequence>
        <xs:element name="Node1" type="type1"/>
    </xs:sequence>
</xs:group>

<xs:group name="g_nodes_3to10">
    <xs:sequence>
        <xs:element name="Node3" type="type3"/>
        <xs:element name="Node4" type="type4"/>
        <xs:element name="Node5" type="type5"/>
        <xs:element name="Node6" type="type6"/>
        <xs:element name="Node7" type="type7"/>
        <xs:element name="Node8" type="type8"/>
        <xs:element name="Node9" type="type9"/>
        <xs:element name="Node10" type="type10"/>
    </xs:sequence>
</xs:group>

<xs:complexType name="Parent">
    <xs:sequence>
        <xs:group ref="g_node_1"/>
        <xs:element name="Node2" type="type2"/>
        <xs:group ref="g_nodes_3to10"/>
    </xs:sequence>
</xs:complexType>

<xs:complexType name="Child1">
    <xs:complexContent>
        <xs:restriction base="Parent">
            <xs:sequence>
                <xs:group ref="g_node_1"/>
                <xs:element name="Node2" type="type2_derived_1" />
                <xs:group ref="g_nodes_3to10"/>
            </xs:sequence>
        </xs:restriction>
    </xs:complexContent>
</xs:complexType> 

<xs:complexType name="Child2">
    <xs:complexContent>
        <xs:restriction base="Parent">
            <xs:sequence>
                <xs:group ref="g_node_1"/>
                <xs:element name="Node2" type="type2_derived_2" />
                <xs:group ref="g_nodes_3to10"/>
            </xs:sequence>
        </xs:restriction>
    </xs:complexContent>
</xs:complexType> 

Это требует на 2 строки больше (на тип), чем идеальное решение, но это лучше, чем ничего.


person freesoft    schedule 04.06.2014    source источник


Ответы (1)


Не существует простого способа определить нужные отношения без повторения модели содержимого. Есть несколько возможных обходных путей.

Один из способов избежать дублирования: использовать общие сущности для неизменных частей модели контента. (Если вам не повезло застрять с использованием средства проверки XSD, которое не поддерживает использование DTD для документов схемы, вам потребуется расширить сущности с помощью инструмента, такого как xmllint или rxp, или запустить преобразование удостоверения XSLT на документ схемы, прежде чем передать его валидатору.)

Другой способ: использовать именованные группы моделей для неизменных частей модели контента.

Иногда возможен и третий способ, в зависимости от того, как type2, type2_derived_1, type2_derived_2 и т. д. связаны друг с другом: используйте утверждения, чтобы заставить второго потомка принять желаемую форму.

person C. M. Sperberg-McQueen    schedule 04.06.2014