我正在尝试找到验证以下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不能做到这一点”?
答案 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="*">