我想在我的文档中强制执行<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语法完成吗?
答案 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属性。