灵活的递归 XML 模式

Flexible recursive XML schema

我正在尝试为此示例创建验证架构 XML。我已经尝试使用递归定义,但找不到合适的方法。请注意,IF 和 ELSE 元素可以嵌套任意次数,并且 ACTIONx 元素可以以任意顺序出现。另请注意,每个元素都有自己可能不同的属性。

<?xml version="1.0" encoding="utf-8"?>
<KEYPRESS Buffer="1">
    <ACTION1 Index="15" />
    <IF Condition="0">
        <IF Condition="1">
            <ACTION1 Index="14" />
            <ELSE>
                <ACTION2 Measure="whatever" />
            </ELSE>
        </IF>
    
        <IF Condition="2">
            <IF Condition="5">
                <ACTION2 Measure="whatelse" />
                <ACTION3 Type="Flag"  />
            </IF>
            <ELSE>
                <ACTION1 Index="0" />
                <ACTION3 Type="Other" />
                <IF Condition="1">
                    <ACTION3 Type="Flag" />
                </IF>
            </ELSE>
        </IF>
    </IF>
</KEYPRESS> 

我们将不胜感激。

*** 编辑 *** 非常感谢Michael Kay,优秀的解决方案! 我在这里发布生成的架构,以防有人感兴趣。

<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid Studio 2021 (https://www.liquid-technologies.com) -->
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="INSTRUCTION" abstract="true"/>

    <xs:element name="ACTION1" substitutionGroup="INSTRUCTION">
        <xs:complexType>
            <xs:attribute name="Index" type="xs:string" use="required" />
        </xs:complexType>
    </xs:element>
    <xs:element name="ACTION2" substitutionGroup="INSTRUCTION">
        <xs:complexType>
            <xs:attribute name="Index" type="xs:string" use="required" />
        </xs:complexType>
    </xs:element>
    <xs:element name="ACTION3" substitutionGroup="INSTRUCTION">
        <xs:complexType>
            <xs:attribute name="Type" type="xs:string" use="required" />
            <xs:attribute name="Index" type="xs:string" use="required" />
            <xs:attribute name="Value" type="xs:string" use="required" />
        </xs:complexType>
    </xs:element>
    <xs:element name="IF" substitutionGroup="INSTRUCTION">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="INSTRUCTION" minOccurs="1" maxOccurs="unbounded"/>
                <xs:element name="ELSE" minOccurs="0" maxOccurs="1"/>
            </xs:sequence>
            <xs:attribute name="Type" type="xs:string" use="required" />
            <xs:attribute name="Index" type="xs:string" use="required" />
            <xs:attribute name="Condition" type="xs:string" use="required" />
        </xs:complexType>
    </xs:element>
    <xs:element name="KEYPRESS" >
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="INSTRUCTION" minOccurs="1" maxOccurs="unbounded"/>
            </xs:sequence>
            <xs:attribute name="KeySeq" type="xs:string" use="required" />
            <xs:attribute name="Buffer" type="xs:string" use="required" />
        </xs:complexType>
    </xs:element>
    <xs:element name="ELSE" >
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="INSTRUCTION" minOccurs="1" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

</xs:schema>

我认为您不能定义具有可变元素名称的架构。

一个 element declaration 需要一个名字。该值是 xs:NCName 类型,它只是一个字符串而不是模式。为了编写模式,您必须找出动作元素的最大数量。而且您必须为每个元素定义一个 complexType。我认为你不想这样做。

您 XML 文件是由对 XML 了解不多的人设计的。你最好告诉他,格式必须重新设计。而不是

<ACTION1 ...>

使用

<ACTION N="1" ...>

模式验证会很容易。

这种结构就是置换组的用途。

定义一个抽象元素INSTRUCTION,然后定义IFACTION1ACTION2ACTION3作为[的替换组成员=10=],每个都有自己的类型定义,定义了允许的属性。 KEYPRESSELSE 的内容模型显示为 INSTRUCTION*(0 个或多个指令的序列),IF 的内容模型显示为 (INSTRUCTION*, ELSE?)(0 个或多个指令的序列,后跟一个 ELSE)。

ELSE不是替换组的成员,因为它不能出现在指令出现的任何地方)。