我需要创建一个 XML 模式来验证 XML 文档的树结构。我不确切知道树的出现次数或深度级别。
XML 示例:
<?xml version="1.0" encoding="utf-8"?>
<node>
<attribute/>
<node>
<attribute/>
<node/>
</node>
</node>
验证它的最佳方法是什么?递归?
我需要创建一个 XML 模式来验证 XML 文档的树结构。我不确切知道树的出现次数或深度级别。
XML 示例:
<?xml version="1.0" encoding="utf-8"?>
<node>
<attribute/>
<node>
<attribute/>
<node/>
</node>
</node>
验证它的最佳方法是什么?递归?
如果您需要递归类型声明,这里有一个可能有帮助的示例:
<xs:schema id="XMLSchema1"
targetNamespace="http://tempuri.org/XMLSchema1.xsd"
elementFormDefault="qualified"
xmlns="http://tempuri.org/XMLSchema1.xsd"
xmlns:mstns="http://tempuri.org/XMLSchema1.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<xs:element name="node" type="nodeType"></xs:element>
<xs:complexType name="nodeType">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="node" type="nodeType"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
如您所见,这定义了一个递归模式,其中只有一个名为“node”的节点,其深度可以根据需要进行。
XSD 确实允许元素的递归。这是给你的样本
<xsd:element name="section">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="title"/>
<xsd:element ref="para" maxOccurs="unbounded"/>
<xsd:element ref="section" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
如您所见,section 元素包含一个类型为 section 的子元素。
其他解决方案非常适合使根元素递归。但是,为了使非根元素递归而不在过程中将其变成有效的根元素,需要一种稍微不同的方法。
假设您要定义一种 XML 消息格式,用于在分布式应用程序中的节点之间交换结构化数据。它包含以下元素:
<message>
- 根元素;<from>
- 消息的来源;<to>
- 消息的目的地;<type>
- 消息中编码的数据结构类型;<data>
- 消息中包含的数据。为了支持复杂的数据类型,<data>
是一个递归元素。这使得可以编写如下消息,例如geometry_msgs/TwistStamped
向飞行的无人机发送消息,指定其线性和角(即旋转)速度:
<?xml version="1.0" encoding="utf-8"?>
<message xmlns="https://stackoverflow.com/message/1.0.0">
<from>controller:8080</from>
<to>drone:8080</to>
<type>geometry_msgs/TwistStamped</type>
<data name="header">
<data name="seq">0</data>
<data name="stamp">
<data name="sec">1</data>
<data name="nsec">0</data>
</data>
<data name="frame_id">base_link</data>
</data>
<data name="twist">
<data name="linear">
<data name="x">1.0</data>
<data name="y">0</data>
<data name="z">1.0</data>
</data>
<data name="angular">
<data name="x">0.3</data>
<data name="y">0</data>
<data name="z">0</data>
</data>
</data>
</message>
我们可以很容易地编写一个 XML 模式来验证这种格式:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="https://stackoverflow.com/message/1.0.0"
elementFormDefault="qualified"
xmlns="https://stackoverflow.com/message/1.0.0"
>
<xs:element name="data">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element ref="data" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="message">
<xs:complexType>
<xs:sequence>
<xs:element name="from" type="xs:string"/>
<xs:element name="to" type="xs:string"/>
<xs:element name="type" type="xs:string"/>
<xs:element ref="data" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
上面架构的问题在于它创建<data>
了一个根元素,这意味着它还验证了下面的文档:
<?xml version="1.0" encoding="utf-8"?>
<data xmlns="https://stackoverflow.com/message/1.0.0" name="twist">
<data name="header">
<data name="seq">0</data>
<data name="stamp">
<data name="sec">1</data>
<data name="nsec">0</data>
</data>
<data name="frame_id">base_link</data>
</data>
<data name="twist">
<data name="linear">
<data name="x">1.0</data>
<data name="y">0</data>
<data name="z">1.0</data>
</data>
<data name="angular">
<data name="x">0.3</data>
<data name="y">0</data>
<data name="z">0</data>
</data>
</data>
</data>
为了避免这种副作用,我们不是<data>
直接在全局级别定义元素,而是先定义一个data
类型,然后data
在内部定义该类型的元素message
:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="https://stackoverflow.com/message/1.0.0"
elementFormDefault="qualified"
xmlns="https://stackoverflow.com/message/1.0.0"
>
<xs:complexType name="data" mixed="true">
<xs:sequence>
<xs:element name="data" type="data" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
<xs:element name="message">
<xs:complexType>
<xs:sequence>
<xs:element name="from" type="xs:string"/>
<xs:element name="to" type="xs:string"/>
<xs:element name="type" type="xs:string"/>
<xs:element name="data" type="data" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
请注意,我们最终不得不定义<data>
元素两次——一次在data
类型内部,一次在内部<element>
——但除了一些工作重复之外,这没有任何意义。