XSD,顺序无关紧要,必须考虑到xml的变化

时间:2015-09-24 20:12:46

标签: xml xsd xsd-validation

我已经考虑了几种方法来做到这一点,似乎没有一种方法适合我。

我有以下xml示例:

 <Entry>
      <Node1></Node1>
      <Node2></Node2>
      <Node3></Node3>
 </entry>

我需要xsd来解释以下更改而不会破坏:

1)新节点添加到xml的末尾:

 <Entry>
      <Node1></Node1>
      <Node2></Node2>
      <Node3></Node3>
      <Node4></Node4>
 </Entry>

2)在xml中间添加了新节点:

 <Entry>
      <Node1></Node1>
      <Node4></Node4>
      <Node2></Node2>
      <Node3></Node3>
 </Entry>

3)两者结合:

 <Entry>
      <Node1></Node1>
      <Node2></Node2>
      <Node5></Node5>
      <Node3></Node3>
      <Node4></Node4>
 </Entry>

我目前使用的XSD是<xs:sequence>的构建,显然是失败的。我已经尝试了<xs:any><xs:all><xs:choice>,但似乎都没有正确验证。

用例如下:如果开发人员更新并返回上述XML的API,我不想创建新的XSD并重新编译应用程序以允许更改。

非常感谢任何和所有信息。

这是我正在使用的xsd。

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="APIName">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="entry" maxOccurs="unbounded" minOccurs="0">
          <xs:complexType>
              <xs:element type="xs:string" name="Node1"/>
              <xs:element type="xs:string" name="Node2"/>
              <xs:element type="xs:string" name="Node3"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
      <xs:attribute type="xs:string" name="NextPageLink"/>
    </xs:complexType>
  </xs:element>
</xs:schema>

3 个答案:

答案 0 :(得分:2)

简短的回答是:这不能在XSD中完成。

无法做到这一点的原因是因为你违反了Unique Particle Attribute constraint,这是说你的数据模型不确定的一种昂贵的方式。

假设您有一个允许的XSD:

<Entry>
   <any node>
   <Node1>
   <any node>
</Entry>

并且您只想要Node1存在。假设现在有人发给你了:

<Entry>
   <Node1>
   <Node2>
   <Node1>
</Entry>

数据映射如何确定第一个或第二个Node1是否正确?

你可能会争辩说你想要要求其他元素具有不同的名称,但是这样的约束是不可能的(从技术角度来说,它被授予,但在XSD中没有这样的机制),除非你设计了可扩展性,这需要额外的元素在不同的命名空间中。 XFront有an excellent article on some methods to create such an extensibilityVariable Content Containers上的另一篇文章,这是我在你的案例中选择的方式。它们读得很好,我强烈推荐它们。

那么可以你做什么?

  1. 确保您要构思的模型具有确定性
    1. 即,您可以要求所有不符合要求的元素位于开头,结尾或中间
    2. 这需要您期望的元素,minOccurrence高于零。
  2. 选择其他模式语言,您可以在RelaxNG或Schematron
  3. 中表达
  4. 使用xs:assert摆脱自动映射并使用XSD 1.1构建架构,这允许以您希望的方式进行验证,但需要您手动创建模型到对象的映射(之后)所有,它变得不确定,所以世界上没有任何程序可以自动为你映射它)
  5. 转到“XSD方式”并使用上述链接中的最佳做法之一。这将要求人们仅使用其他命名空间进行扩展(无论如何这绝对是一个更好的主意!),但您仍然可以验证并映射XSD。
  6. 简化您的模型,添加一个内容模型extensions的可选元素xs:any,这将要求您的数据提供商在其中添加任何额外的内容。

答案 1 :(得分:1)

严格地说,你没有提供足够的信息让别人能够可靠地回答你的问题,所以我不同意@Abel的简短回答。

让我们采用这种模式:

<?xml version="1.0" encoding="utf-8" ?>
<!-- XML Schema generated by QTAssistant/XSD Module (http://www.paschidev.com) -->
<xsd:schema targetNamespace="http://tempuri.org/XMLSchema.xsd" xmlns="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xtm="http://paschidev.com/schemas/metadata/xtm">
    <xsd:element name="root">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:any minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
    <xsd:element name="node1" type="xsd:string"/>
    <xsd:element name="node2" type="xsd:int"/>
    <xsd:element name="node3" type="xsd:date"/>
</xsd:schema>

诀窍是用于xsd:any的 processContents =“lax”。通过查看您的测试用例,上述内容将满足您的要求:node1,2和3将以您可能想到的任何顺序正确验证,散布或不散布新内容或现有内容。我必须提醒你,某些类型的更改不起作用,例如:更改节点的内容模型(node2从int到string等)

真正的答案必须考虑很多事情,包括您用来处理XML的技术以及您真正想要做多少验证。例如,某些XSD到代码绑定技术已内置支持忽略新的XML,“附加”在由用于生成代码的模式版本定义的内容模型的“末尾”(.NET XML)解串器)。其他堆栈(例如JAXB)支持使用自定义错误处理程序,允许用户控制未知内容的解组。基于XPath的处理模型甚至可能不那么敏感,甚至允许您在节点级别进行选择性验证。

我会说正确的答案是:“这取决于”;我希望我的示例模式和技术参考可以让您了解您可能想要澄清的其他内容,以帮助我们为您提供更准确的答案。

根据您的更新:

此架构:

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="APIName">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="entry" maxOccurs="unbounded" minOccurs="0">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
            <xs:attribute type="xs:string" name="NextPageLink"/>
        </xs:complexType>
    </xs:element>
    <xs:element type="xs:string" name="Node1"/>
    <xs:element type="xs:string" name="Node2"/>
    <xs:element type="xs:string" name="Node3"/>
</xs:schema>

将验证:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<APIName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" NextPageLink="NextPageLink1">
    <entry>
        <Node2>s2</Node2>
        <Node5>s5</Node5>
        <Node1>s1</Node1>
        <Node3>s3</Node3>
    </entry>
</APIName>

而且:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<APIName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" NextPageLink="NextPageLink1">
    <entry>
        <Node2>s2</Node2>
        <Node1>s1</Node1>
        <Node2>s2</Node2>
        <Node5>s5</Node5>
        <Node3>s3</Node3>
    </entry>
</APIName>

同样,您的架构设置的期望也不会得到满足,因为它需要Node3:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!-- Sample XML generated by QTAssistant (http://www.paschidev.com) -->
<APIName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" NextPageLink="NextPageLink1">
    <entry>
        <Node1>s1</Node1>
        <Node2>s2</Node2>
        <Node5>s5</Node5>
    </entry>
</APIName>

这是XSD 1.0达到限制的地方。 XSD 1.1可以帮助您。如果您不能使用它,我仍然会使用XSD 1.0,并使用快速检入代码进行补偿,以确保每个节点1,2和3都有一个实例;在工作方面击败所有其他建议。根据我的个人经验,对于它可以做的事情,XSD比手动编写等效代码更有效。

答案 2 :(得分:-1)

节点需要具有该名称吗?我建议将节点作为元素,并将索引或数字指定为属性或子元素

<Entry> <Node order="1"></Node1> <Node order="2"></Node2> <Node order="5"></Node5> <Node order="3"></Node3> <Node order="4"></Node4> </Entry>

<Entry> <Node><order>1</order></Node> <Node><order>2</order></Node> <Node><order>5</order></Node> <Node><order>3</order></Node> <Node><order>4</order></Node> </Entry>