XML 验证 - 如果那么
XML Validation - If Then
我正在尝试找到验证以下 XML 文档的最佳方法。到目前为止,我已经研究了三种方法:
DTD - 似乎没有足够的选择来实现它。
XSD - 几乎可以工作,但我似乎无法找到一种方法来做 If Then
XSL - 关于同样的问题,我可以做 If's,但我似乎无法想出一种方法来使其适用于此文档。
思路是这样的:根元素是<Answers>
。下面是 1 个或多个 <Answer>
。它们有一个 ID 属性,标记它对应的问题编号(在别处处理,不重要)。
每个问题可能有 0 个或多个答案,现在写为 <A1>
、<A2>
...
每个答案都有 1 个或多个元素,<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>
进入Elements的是任意字符串,内容不重要,只要不为空即可。
我需要验证的是,对于每个答案(用 ID 表示),每个 <A*>
,都有一定数量的元素。在本例中,1a 有 4 个元素,1b 有 3 个,2 有 5 个。
格式很灵活,所以如果需要我可以将内容更改为:
元素A
B元素
C元素
或者类似的东西。
我已经尝试了各种组合,但我似乎无法找到一种方法来根据答案 ID 要求 X 数量的 <E*>
。
有没有人有任何想法,或者他们能给我指出正确的方向,即使只是说 "Yes, XSD can do this" 或 "No, XSL cannot do this"?
您想要执行的验证类型("if then" 语句)称为 assertion。正如@kjhughes 所指出的,XML Schema 1.1 有断言,您可以在 XML 文档中使用 XSD 1.1.
实现此类复杂关系
或者,您可以使用 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="*">
我正在尝试找到验证以下 XML 文档的最佳方法。到目前为止,我已经研究了三种方法:
DTD - 似乎没有足够的选择来实现它。
XSD - 几乎可以工作,但我似乎无法找到一种方法来做 If Then
XSL - 关于同样的问题,我可以做 If's,但我似乎无法想出一种方法来使其适用于此文档。
思路是这样的:根元素是<Answers>
。下面是 1 个或多个 <Answer>
。它们有一个 ID 属性,标记它对应的问题编号(在别处处理,不重要)。
每个问题可能有 0 个或多个答案,现在写为 <A1>
、<A2>
...
每个答案都有 1 个或多个元素,<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>
进入Elements的是任意字符串,内容不重要,只要不为空即可。
我需要验证的是,对于每个答案(用 ID 表示),每个 <A*>
,都有一定数量的元素。在本例中,1a 有 4 个元素,1b 有 3 个,2 有 5 个。
格式很灵活,所以如果需要我可以将内容更改为: 元素A B元素 C元素 或者类似的东西。
我已经尝试了各种组合,但我似乎无法找到一种方法来根据答案 ID 要求 X 数量的 <E*>
。
有没有人有任何想法,或者他们能给我指出正确的方向,即使只是说 "Yes, XSD can do this" 或 "No, XSL cannot do this"?
您想要执行的验证类型("if then" 语句)称为 assertion。正如@kjhughes 所指出的,XML Schema 1.1 有断言,您可以在 XML 文档中使用 XSD 1.1.
实现此类复杂关系或者,您可以使用 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="*">