【问题标题】:Validate XML element with XSD使用 XSD 验证 XML 元素
【发布时间】:2012-10-31 15:05:50
【问题描述】:

我有以下 XML:

<?xml version="1.0" encoding="utf-8"?>
<MainElement>
    <id>1</id>
    <name>John</name>
    <custom>
        <age>43</age>
        <sex>male</sex>
    </custom>
</MainElement>

还有另一个 XML 文件:

<?xml version="1.0" encoding="utf-8"?>
<MainElement>
    <id>2</id>
    <name>Dave</name>
    <custom>
        <age>51</age>
        <county>England</country>
        <city>London</city>
    </custom>
</MainElement>

两个 XML 文件的主要结构相同,只是 &lt;custom&gt; 元素具有不同的实现。我已经有一个 XSD 文件来检查像“id”和“name”这样的元素,其中&lt;custom&gt; 元素的类型是 xs:anyType。是否可以创建另一个 XSD 文件,它只验证 &lt;custom&gt; 元素而不查看所有其他存在的元素?

【问题讨论】:

  • 您必须回答的第一件事是您将如何确定您应该获得哪个custom 元素。如果您计划使用相同的标记但具有不同的内容模型,那么在 XSD 1.0 中没有自定义 XML 预处理和适当 XSD 的动态加载(这称为悬空定义)或使用附加到您的自定义元素的 xsi:type 属性。如果“自定义”元素是指任何命名元素,那么事情可能会变得更容易或更复杂,具体取决于您想要设置的约束。如果您可以提供更多详细信息...
  • 自定义元素将始终具有名称“自定义”并且是可选元素。例如,有三个客户将向我发送 XML 文件,根据客户的不同,我将需要使用相应的 XSD 文件来验证来自“自定义”元素的所有子元素。对于所有三个客户,我将使用相同的 XSD 来验证 xml 文件的其余部分,例如“id”和“name”元素。知道这是否可以仅使用 XSD 完成,还是我需要使用其他技术?

标签: xml xsd


【解决方案1】:

我将为两个客户说明。第一个 XSD 是应该捕获所有公共部分的基础 XSD,除了我们引用但未定义的 custom;我们让它“悬空”。

下面是common.xsd:

<?xml version="1.0" encoding="utf-8"?>
<!--XML Schema generated by QTAssistant/XML Schema Refactoring (XSR) Module (http://www.paschidev.com)-->
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="MainElement">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="id" type="xsd:unsignedByte" />
        <xsd:element name="name" type="xsd:string" />
        <xsd:element ref="custom"/>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

然后我们开始为每个custom 定义一个 XSD。对于第一个 XML (custom-1.xsd):

<?xml version="1.0" encoding="utf-8"?>
<!--XML Schema generated by QTAssistant/XML Schema Refactoring (XSR) Module (http://www.paschidev.com)-->
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="custom">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="age" type="xsd:unsignedShort"/>
                <xsd:element name="sex" type="xsd:string"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

对于第二个,custom-2.xsd:

<?xml version="1.0" encoding="utf-8"?>
<!--XML Schema generated by QTAssistant/XML Schema Refactoring (XSR) Module (http://www.paschidev.com)-->
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="custom">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="age" type="xsd:unsignedShort"/>
                <xsd:element name="country" type="xsd:string"/>
                <xsd:element name="city" type="xsd:string"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

然后您必须通过适当地加载 XSD 为每个客户创建一个模式集:第一个集将包括 common + custom-1,然后是 common + custom-2,等等。

这就是我使用 QTAssistant “可视化”这些集合的方式:

当然,Common 本身是无效的。

Error occurred while loading [file:///.../validate-xml-element-with-xsd-2.xsd], line 9 position 10.
The 'custom' element is not declared.

但是,每个其他集合都是有效的,因为集合中的附加 XSD 会将缺少的定义纳入范围。现在您可以验证每个供应商的 XML 及其关联集。您可以维护跨供应商的通用定义的完整性,因为您确实共享一个通用 XSD,并且您可以使用悬空定义摆脱 XSD 1.0 中的“限制”。我认为这并不是真正的限制;这可能是一种“不那么优雅”的方法......

从处理的角度来看,编译和加载常见 XSD 的次数与供应商的次数一样多。

如果这成为一种负担,您还可以使用另一种策略,一旦您的 XML 预处理得到回报。您可以将 custom 定义为 anyType,甚至可以将其替换为 xsd:any。一旦验证了公共节点,您就可以提取节点(XSLT 或 DOM API 或 DOM 节点阅读器之上的验证阅读器等)并使用适当的 XSD 独立验证它。

后一种方法的优点是您不会在 XSD 方面产生任何开销。当然,权衡可能会增加处理过程中的占用空间。

XSD 1.1、XSD 1.0 + Schematron、RelaxNG 是涉及另一种模式语言的解决方案,它们各有优缺点。我认为以上内容至少应该可以帮助您了解您拥有的一些选项...

【讨论】:

    【解决方案2】:

    对于 XSD,您不能使用 ANY 的字面意思!

    因此,您需要以一种或其他方式声明所有作为 XML 的一部分......

    我对您使用 import/include 的方法表示赞赏 .. 这很干净,可以进一步扩展要求 .. 但您仍然应该知道 ANY 元素的可能名称..

    虽然这不是必需的,但您将有兴趣了解另一种使用 Sequencechoice 来实现您的要求的方法,只需一个 XSD

    这是验证 XML1 和 XML2 的代码:

    <?xml version="1.0" encoding="utf-8"?>
    <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="MainElement">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="id" type="xs:unsignedByte" />
            <xs:element name="name" type="xs:string" />
            <xs:element name="custom">
              <xs:complexType>
                <xs:sequence>
                  <xs:choice>
                    <xs:element name="age" type="xs:unsignedByte" />
                  </xs:choice>
                  <xs:choice>
                    <xs:sequence>
                      <xs:element name="sex" type="xs:string" />
                    </xs:sequence>
                    <xs:sequence>
                      <xs:element name="country" type="xs:string"/>
                      <xs:element name="city" type="xs:string"/>
                    </xs:sequence>
                  </xs:choice>
                </xs:sequence>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>
    

    这对你现在可能没有用,但将来可能会......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-09
      • 1970-01-01
      • 1970-01-01
      • 2019-01-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多