Как использовать значение атрибута как дискриминатор для выбора полиморфного типа XML? - PullRequest
3 голосов
/ 23 февраля 2010

Я пытаюсь написать XML-схему по существующему описанию формата XML (то есть, документ - описание множества элементов и типов в свободной форме). Моя последняя идея - передать такой XSD в генератор кода и получить классы привязки.

Вот пример, с которым я не могу справиться:

packet1.xml:

<?xml version="1.0" ?>
<packet kind="type1">
    <field1>value1</field1>
    <field2>value2</field2>
</packet>

packet2.xml:

<?xml version="1.0" ?>
<packet kind="type2">
    <field1>value3</field1>
    <field3>value4</field3>
</packet>

Таким образом, вместо имени элемента в значении атрибута определяется тип. type1 и type2 однозначно определяют тип пакета, т.е. тип определяет набор и типы вложенных полей.

Моя идея состоит в том, чтобы использовать полиморфные типы в XML и набросок схемы XML выглядит следующим образом:

schema.xsd:

<?xml version="1.0"?>
<xsd:schema>
    <xsd:complexType name="protocol_abstract" abstract="true"/>
    <xsd:element name="protocol" type="protocol_abstract"/>

    <xsd:complexType name="protocol_type1"/>
        <xsd:complexContent>
            <xsd:extension base="protocol_abstract"/>
                <xsd:sequence>
                    <xsd:element name="field1" type="xsd:string"/>
                    <xsd:element name="field2" type="xsd:string"/>
                </xsd:sequence>
                <xsd:attribute name="kind" type="xsd:NMTOKEN" fixed="type1"/>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:complexType name="protocol_type2"/>
        <xsd:complexContent>
            <xsd:extension base="protocol_abstract"/>
                <xsd:sequence>
                    <xsd:element name="field1" type="xsd:string"/>
                    <xsd:element name="field3" type="xsd:string"/>
                </xsd:sequence>
                <xsd:attribute name="kind" type="xsd:NMTOKEN" fixed="type2"/>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>
</xsd:schema>

Это почти помогает, но требует спецификации xsi: type:

packet21.xml:

<?xml version="1.0" ?>
<packet kind="type1" xsi:kind="packet_type1">
    <field1>value1</field1>
    <field2>value2</field2>
</packet>

packet22.xml:

<?xml version="1.0" ?>
<packet kind="type2" xsi:kind="packet_type2">
    <field1>value3</field1>
    <field3>value4</field3>
</packet>

При таком определении валидатор подтверждает, что XML верен. Но это не очень удобно, входящие сообщения не содержат xsi: type.

Можно ли избавиться от xsi: type и использовать только мой атрибут kind ? Есть ли другой способ сделать это, кроме предварительной обработки? (преобразовать значение атрибута в имя элемента)

Спасибо за любые идеи заранее.

1 Ответ

3 голосов
/ 23 февраля 2010

Нет. xsi:type - единственный способ сделать это. Кроме этого, XML-схема не поддерживает условную проверку.

Если вам нужна дополнительная проверка таких ограничений, вам нужно их кодировать или использовать что-то вроде Schematron.

...