XML验证 - 如果那么

时间:2015-02-26 19:19:31

标签: xml xslt xsd dtd xsd-validation

我正在尝试找到验证以下XML文档的最佳方法。到目前为止,我已经研究过三种方法:

DTD - 看起来没有足够的选择来实现它。

XSD - 几乎可以工作,但我似乎无法找到像If Then

这样的方法

XSL - 关于同样的问题,我可以做If,但我似乎无法想办法让它对这个文件起作用。

这个想法是这样的:根元素是<Answers>。下面是1个或更多<Answer>。它们有一个ID属性,用于标记它对应的问题编号(在别处处理,不重要)。 每个问题可能有0个或更多答案,现在正在编写为<A1><A2> ... 每个答案都有一个或多个元素,<E1><E2> ...

示例文档如下所示:

<Answers>

  <Answer ID="1a">
    <A1>
      <E1>Element 1</E1>
      <E2>Element 2</E2>
      <E3>Element 3</E3>
      <E4>Element 4</E4>
    </A1>
    <A2>
      <E1>Element 1</E1>
      <E2>Element 2</E2>
      <E3>Element 3</E3>
      <E4>Element 4</E4>
    </A2>
  </Answer>

  <Answer ID="1b">
    <A1>
      <E1>Element A</E1>
      <E2>Element B</E2>
      <E3>Element C</E3>
    </A1>
  </Answer>

  <Answer ID="2">
    <A1>
      <E1>Element 1</E1>
      <E2>Element 2</E2>
      <E3>Element 3</E3>
      <E4>Element 4</E4>
      <E5>Element 5</E5>
    </A1>
    <A2>
      <E1>Element 1</E1>
      <E2>Element 2</E2>
      <E3>Element 3</E3>
      <E4>Element 4</E4>
      <E5>Element 5</E5>
    </A2>
    <A3>
      <E1>Element 1</E1>
      <E2>Element 2</E2>
      <E3>Element 3</E3>
      <E4>Element 4</E4>
      <E5>Element 5</E5>
    </A3>

  </Answer>
</Answers>

元素中的内容是任何字符串,内容并不重要,只要它不是空的。

我需要验证的是,对于每个答案(由ID表示),对于每个<A*>,存在一定数量的元素。在这个例子中,1a有4个元素,1b有3个,2有5个。

格式很灵活,所以如果需要,我可以将内容更改为:                    元素A.           元素B.           元素C.          或类似的东西。

我已尝试过各种各样的组合,但根据答案ID,我似乎无法找到需要X量<E*>的方法。

有没有人有任何想法,或者他们是否可以指出我正确的方向,即使它只是说“是的,XSD可以做到这一点”,或者“不,XSL不能做到这一点”?

1 个答案:

答案 0 :(得分:3)

您想要执行的验证类型(“if then”语句)称为断言。正如@kjhughes所指出的,XML Schema 1.1有断言,您可以使用XSD 1.1在XML文档中实现这种复杂的关系。

或者,您可以使用不真正执行验证的XSLT转换,但在某种程度上,只将输入XML转换为不满足约束的情况。尽管如此,XSLT还不是一种验证语言。

我认为有人最终会提供XSLT答案 - 所以我想提出其他建议:Schematron。以下Schematron规则是完全定义所需约束的断言。

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">

    <pattern>
        <title>Content of the answer element.</title>
        <rule context="Answer">
            <assert test="*[starts-with(name(),'A')]" xml:lang="en">The <name/> element must contain at least 1 A* element.</assert>
        </rule>
    </pattern>

    <pattern>
        <title>Count number of child elements E* of elements A*</title>
        <rule context="Answer[@ID = '1a']/*[starts-with(name(),'A')]">
            <assert test="count(*[starts-with(name(),'E')]) = 4" xml:lang="en">If the @ID attribute of the Answer element is "1a",
                then all child elements A* must have exactly 4 child elements E*.</assert>
        </rule>
        <rule context="Answer[@ID = '1b']/*[starts-with(name(),'A')]">
            <assert test="count(*[starts-with(name(),'E')]) = 3" xml:lang="en">If the @ID attribute of the Answer element is "1b",
                then all child elements A* must have exactly 3 child elements E*.</assert>
        </rule>
        <rule context="Answer[@ID = '2']/*[starts-with(name(),'A')]">
            <assert test="count(*[starts-with(name(),'E')]) = 5" xml:lang="en">If the @ID attribute of the Answer element is "2",
                then all child elements A* must have exactly 5 child elements E*.</assert>
        </rule>
    </pattern>

</schema>

如果输入文档包含以下结构:

<Answer ID="1a">
    <A1>
        <E1>Element 1</E1>
        <E2>Element 2</E2>
        <E4>Element 4</E4>
    </A1>
</Answer>

验证申请会抱怨,说

E [ISO Schematron] If the @ID attribute of the Answer element is "1a", then all child elements A* must have exactly 4 child elements E*.

Schematron文件可以使用Schematron Reference Implementation - XSLT样式表 - 或像Oxygen这样的环境来解释。


除了注意:将上述SCH规则转换为XSLT并不太难,因为它们非常相似。您必须替换以下内容,例如:

SCH                                 | XSLT equivalent
-----------------------------------------------------------------------------
<sch:rule context="...">            | <xsl:template match="...">
<sch:assert test="*">               | <xsl:if test="not(*)">
<sch:report test="*">               | <xsl:if test="*">