XSD: один элемент должен быть разрешен в разных формах - PullRequest
2 голосов
/ 15 марта 2012

Используя XSD, я хочу определить сложный элемент, который может появляться в трех разных формах:

<Scope Name="foo" />  <!-- no children -->
<Scope Name="foo" Src="bar" /> <!-- When Src is present, there must be no children! -->
<Scope Name="foo"><!-- other children --></Scope>

В третьем случае хорошо определено, что может выглядеть как дочерние элементы (например, все три типа «Scope»). Важной частью является то, что элемент Scope с атрибутом «Src» должен быть пустым!

Кроме того, в разных местах я хочу разрешить только определенные типы элементов. Например, внутри корневого тега я хочу разрешить ровно один элемент Scope третьего типа; в большинстве случаев я позволяю себе все случаи. И вот в чем проблема: как это решить?

Что я сделал до сих пор: я создал сложный тип для каждого из 3 случаев, которые я могу использовать внутри. Однако я не могу использовать:

<xs:choice minOccurs="0" maxOccurs="unbounded">
    <xs:element name="Scope" type="type_Scope_WithSrc" />
    <xs:element name="Scope" type="type_Scope_WithContent" />
    <xs:element name="Scope" type="type_Scope_Base" />
</xs:choice>

Я пытался создать их объединение, но объединения допускаются только для простых типов.

Я также попытался определить общий тип "type_Scope", который использует xs: choice, чтобы включить их. Но xs: choice будет включать xs: elements, для которых в этом случае также потребуется имя: - (

Можете ли вы сказать мне, как я могу справиться с этим?

Пожалуйста, не говорите мне, что это невозможно с XSD :-(: - (

Спасибо

С уважением DIVB

1 Ответ

2 голосов
/ 15 марта 2012

Вы можете получить разные ответы в зависимости от того, хотите ли вы достичь этого с помощью XSD 1.1 или XSD 1.0; Я бы предположил, что вы используете решение 1.0, которое я опишу здесь (я не верю, что 1.1 пока еще практично).

Если вы хотите сохранить имя элемента и изменить его содержимое, единственный вариант здесь - использовать xsi: type. Вместо выбора просто используйте один элемент Scope; сделать его тип сложным, с атрибутом «Имя». Пусть другие два типа будут расширяться от этого базового типа. И все готово.

Примечание: я использовал базовый абстрактный тип в качестве механизма информирования людей о том, что другие типы, как ожидается, будут там использоваться; реальность такова, что он будет работать даже без него, используя type_Scope_Base с самого начала.

Type hierarchy

XSD:

<?xml version="1.0" encoding="utf-8" ?>
<xsd:schema targetNamespace="http://tempuri.org/XMLSchema.xsd"
elementFormDefault="qualified"
xmlns="http://tempuri.org/XMLSchema.xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <xsd:complexType name="type_Scope_BaseA" abstract="true">
    </xsd:complexType>  

    <xsd:complexType name="type_Scope_Base">
        <xsd:complexContent>
            <xsd:extension base="type_Scope_BaseA">
                <xsd:attribute name="Name" type="xsd:string"/>      
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>  

    <xsd:complexType name="type_Scope_WithSrc">
        <xsd:complexContent>
            <xsd:extension base="type_Scope_Base">
                <xsd:attribute name="Src" type="xsd:string"/>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:complexType name="type_Scope_WithContent">
        <xsd:complexContent>
            <xsd:extension base="type_Scope_Base">
                <xsd:sequence>
                    <xsd:any maxOccurs="unbounded" namespace="##other" processContents="lax"/>
                </xsd:sequence>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>

    <xsd:element name="root">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element ref="Scope"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="Scope" type="type_Scope_BaseA"/>

</xsd:schema>

Это три примера XML, все они действительны. Первый с моделью контента от type_Scope_Base.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd">
    <Scope xsi:type="type_Scope_Base" Name="Name1"/>
</root>

Это с моделью контента от type_Scope_WithSrc.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd">
    <Scope xsi:type="type_Scope_WithSrc" Name="Name1" Src="Src1"/>
</root>

И это с моделью контента от type_Scope_WithContent.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema.xsd">
    <Scope xsi:type="type_Scope_WithContent" Name="Name1">
        <me:hello.you xmlns:me="http://paschidev.com"/>
    </Scope>
</root>

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

А потом есть решения на основе XSD 1.1, но я бы держался подальше от всего этого в открытой среде; сегодня не у всех есть совместимый процессор, не говоря уже о самой спецификации, пока не рекомендуется.

...