如何强制XML文件中存在某个元素?

时间:2016-03-10 08:15:41

标签: xml dtd

我想在我的文档中强制执行<a-special/>元素至少一次。对于这样的语法,这样的文档是有效的(因为<a-special/>发生):

<my-container>
    text <a id="1" type="B"/> text text <a-special/>
    text text <a id="5" type="B"/> text <a id="24" type="B"/>
    text <a id="5" type="C"/>
</my-container>

虽然这会被视为无效(因为<a-special/> 会发生):

<my-container>
    <a id="1" type="B"/> text text
    text <a id="5" type="B"/> text <a id="24" type="B"/>
    text <a id="5" type="C"/>
</my-container>

我在下面的语法中尝试了不同的东西,但似乎无法让它按照我需要的方式工作。

<!ELEMENT my-container ( #PCDATA | a | a-special | b )*>

<!ELEMENT a-special EMPTY>

<!ELEMENT a EMPTY>
    <!ATTLIST a id CDATA #REQUIRED>
    <!ATTLIST a type CDATA #REQUIRED>

<!ELEMENT b EMPTY>
    <!ATTLIST b id CDATA #REQUIRED> 
    <!ATTLIST a type CDATA #REQUIRED>

我知道这是错的,但我在考虑这样的事情:

<!ELEMENT my-container 
              a-special+ ( #PCDATA | a | b | a-special )*                           
            | ( #PCDATA | a | b )+ a-special+ ( #PCDATA | a | b | a-special )*
            >

第一部分将解析以a-special开头的任何内容,第二部分将解析任何期望在中间或末尾某处a-special的任何内容。这可以用DTD语法完成吗?

2 个答案:

答案 0 :(得分:0)

无法使用XML DTD声明要强制执行的约束。

如果您的最外层元素实际上只是一系列字符数据和空子元素,那么您提到的类似内容模型的表达式(在提供缺少的逗号之后)会准确捕获约束:

((#PCDATA | a | b)*, a-special, (#PCDATA | a | b | a-special)*)

这在SGML中是合法的(或者我认为,但我还没有检查过)。但XML DTD中混合内容的唯一允许形式是

(#PCDATA)
(#PCDATA | x | y | ... |z)*
(#PCDATA)*

所描述的约束可以在XSD或Relax NG中表达。

如果允许除文档元素之外的任何元素非空,则使用我所知的任何模式语言中的内容模型不能表达约束:内容模型用作一种无上下文语法,并且要求文档中存在a-special元素某处需要一种上下文敏感的形式。

在评论中观察到@potame,Schematron可以制定约束条件;因此,XSD 1.1中的断言可以附加到文档元素的声明中。

一种可能的解决方法:以不同的方式标记元素的特殊性,例如通过指向文档中的一些a元素:

<!ELEMENT my-container (#PCDATA|a|b)* >
<!ATTLIST my-container specials IDREFS #REQUIRED >
<!ELEMENT a EMPTY >
<!ATTLIST a id ID #IMPLIED>
<!ELEMENT b EMPTY>

由于需要my-container/@specials,因此必须在文档中至少命名一个元素。由于唯一定义了ID的元素类型是a,因此specials命名的元素保证为a个元素。

答案 1 :(得分:0)

如果您使用XSD而不是DTD,则可以在元素中使用minOccurs属性。