XML模式中的递归?

时间:2008-09-29 14:41:38

标签: xsd

我需要创建一个验证XML文档树结构的XML模式。我不确切知道树的出现次数或深度级别。

XML示例:

<?xml version="1.0" encoding="utf-8"?>
<node>
  <attribute/>
  <node>
    <attribute/>
    <node/>      
  </node>
</node> 

哪种验证方法最好?递归?

3 个答案:

答案 0 :(得分:66)

如果您需要递归类型声明,这里有一个可能有用的示例:

<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”的节点可以根据需要进行深入。

答案 1 :(得分:39)

XSD确实允许元素的递归。这里is a sample for you

<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的子元素。

答案 2 :(得分:0)

其他解决方案对于使根元素递归非常有用。但是,为了使非根元素递归而不在该过程中将其转换为有效的根元素,需要一种略有不同的方法。

假设您要定义一种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>内部内,但除了一点重复的工作外,这没有任何意义