【问题标题】:Recursion in an XML schema?XML 模式中的递归?
【发布时间】:2010-09-14 00:30:47
【问题描述】:

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

XML 示例:

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

验证它的最佳方法是什么?递归?

【问题讨论】:

    标签: xsd


    【解决方案1】:

    其他解决方案非常适合使根元素递归。但是,为了使非根元素递归而不在过程中将其变成有效的根元素,需要一种稍微不同的方法。

    假设您要定义一种 XML 消息格式,用于在分布式应用程序中的节点之间交换结构化数据。它包含以下元素:

    • &lt;message&gt; - 根元素;
    • &lt;from&gt; - 消息的来源;
    • &lt;to&gt; - 消息的目的地;
    • &lt;type&gt; - 消息中编码的数据结构类型;
    • &lt;data&gt; - 消息中包含的数据。

    为了支持复杂的数据类型,&lt;data&gt; 是一个递归元素。这使得可以编写如下消息,用于发送例如给飞行无人机的 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>
    

    上述架构的问题在于它使&lt;data&gt; 成为根元素,这意味着它还验证了下面的文档:

    <?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>
    

    为了避免这种副作用,我们不是直接在全局级别定义&lt;data&gt;元素,而是先定义一个data类型,然后在message内部定义一个该类型的data元素:

    <?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>
    

    请注意,我们最终不得不定义 &lt;data&gt; 元素两次——一次在 data 类型内,另一次在 &lt;element&gt; 内——但除了一些工作重复之外,这没什么大不了的。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      【解决方案3】:

      如果您需要递归类型声明,下面是一个可能有帮助的示例:

      <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”的节点,可以任意深。

      【讨论】:

        猜你喜欢
        • 2022-01-23
        • 1970-01-01
        • 1970-01-01
        • 2014-09-19
        • 2011-03-23
        • 2015-09-12
        • 2014-01-12
        • 2012-09-20
        • 2018-06-11
        相关资源
        最近更新 更多