在XSD中,我可以根据父元素的内容设置必需的子元素吗?

时间:2012-01-15 08:11:37

标签: xml xsd

我有一个XML& XSD耦合包括类似于以下内容的'House'元素:

<root>
...
<House>
    <id>1</id>
    <type>Cottage</type>
    <imageSrc> image.jpg </imageSrc>
</House>
<House>
    <id>2</id>
    <type>Private</type>
</House>    

我想通过我的XSD强制执行所有类型为“Cottage”的房屋必须有强制标签,但其他房屋则没有。 (或者另一种方式aruond - 唯一的'私有'做。有没有办法做到这一点?

2 个答案:

答案 0 :(得分:2)

您可能需要考虑使用类似Schematron之类的内容来表达超出XML Schema功能的其他验证规则。 Schematron是一个开放(ISO)标准,允许您表达有关XML文档中应存在的模式的断言。例如,您可以使用它来表达约束,例如:

  • 如果元素A存在,则禁止元素B。如果AB是兄弟姐妹,则可以使用XML架构中的xs:choice来执行此操作,但如果这两个元素不是兄弟,则此方法在XML架构中不起作用。< / LI>
  • 如果元素A具有特定值的属性,则它必须包含子元素B
  • 元素A必须等于元素BC的总和。

在您的具体示例中,我将假设imageSrc是强制标记,您希望在“Cottage”类型的House上强制执行,并禁止其他类型。

表达这些断言的简单Schematron模式的一个例子是:

<schema xmlns="http://purl.oclc.org/dsdl/schematron">
  <pattern>
    <!-- Houses of type 'Cottage' must contain an imageSrc element -->
    <rule context = "/root/House[type/text() = 'Cottage']">
      <assert test = "imageSrc">Cottages must have an image</assert>
    </rule>

    <!-- Houses not of type 'Cottage' must not contain an imageSrc element -->
    <rule context = "/root/House[type/text() != 'Cottage']">
      <assert test = "not(imageSrc)">Non-cottages must not have an image</assert>
    </rule>
  </pattern>
</schema>

在这里,我将模式表达为两个单独的规则,分别针对您要求的两个部分。

每个rule都有一个context属性,这是一个XPath表达式。当此表达式的计算结果为true时,规则“触发”。因此,第一条规则触发House元素,其中type子元素的文本内容等于'Cottage'。

当规则触发时,然后通过评估test元素的assert属性来检查断言。同样,这是一个XPath表达式,但用于评估测试表达式的上下文节点是由rule元素匹配的节点(在本例中为House)。当测试表达式求值为true时,断言通过(即文档对于该断言是有效的)。如果它的计算结果为false,则断言失败。 assert元素的文本内容通常是可以传递给最终用户的断言的人类可读描述。 Schematron还提供其他工具(称为“诊断”),以将其他技术消息链接到断言。

http://www.schematron.com/implementation.html提供了一个公开的基于XSLT的Schematron实现。典型的验证管道将涉及首先针对定义文档的基本结构要求的XML模式验证文档(例如元素层次结构,基数,数据类型,模式等)。然后,一旦文档通过了这个基本的验证级别,您就可以根据Schematron模式验证文档,以验证其他基于模式的约束。此管道可以以编程方式实现,也可以使用(例如)批处理文件,Ant脚本或XProc处理器实现。

答案 1 :(得分:0)

虽然XSD确实不支持这种行为,但你可以简单地定义两种House类型,一种是强制节点,另一种是没有。