Relax NG 的模式(如 DTD 和 XSD 的内容模型)本质上是正则表达式;他们在元素名称集和text
. 您似乎正在寻找的 a/b 匹配需要上下文无关语法;因此,它不能在 Relax NG 中定义。
当然,它可以近似。如果您希望在实践中您永远不会有超过五个 a/b 对(或者,更准确地说:永远不会超过五个a
您尚未看到匹配的元素b
),您可以定义以下任一语言。
第一的:
pair0 = (a, b)*
pair1 = (a, pair0, b)*
pair2 = (a, pair1, b)*
pair3 = (a, pair2, b)*
pair4 = (a, pair3, b)*
pair5 = (a, pair4, b)*
pair6 = (a, pair5, b)*
pair7 = (a, pair6, b)*
pair8 = (a, pair7, b)*
pair9 = (a, pair8, b)*
pair = (a, pair9, b)*
这定义了您的语言的子集,它严格执行您的两条规则,但不能处理嵌套超过 10 个深度的 a/b 对。(或 11 个,取决于您的计数。)此定义接受的每个文档都将是您实际想要的语言的成员,但并非该语言的每个成员都会被接受。
如果拒绝语言的有效实例是不可接受的,您可以如上所述定义模式,但将 pair0 重新定义为:
pair0 = (a, (a|b)*, b)*
这定义了语言的超集,其中对 a/b 对强制执行规则,直到嵌套的最大级别,但是一旦嵌套级别超过该最大值,规则就会被放弃。在这种情况下,所需语言的每个成员都将被接受,但一些不应该接受的垃圾也会被接受。
这些近似值在您的应用程序中是否有用,我留给您决定。
如果不能接受近似值,您可能会发现通过以不同方式定义 XML 更容易获得所需内容。
一个简单的更改是将每个匹配项包装a
在b
一个元素中(我将调用它e
):
element line { pair* }
a = element a { empty }
b = element b { empty }
pair = element e { a, pair*, b }
现在,文档的有效性提供了一个非常简单的保证,即a
元素和b
元素按要求配对,并且每个都a
在匹配之前b
。
鉴于a
andb
是空的,每个a
紧跟在 开始标签e
之后,并且每个b
紧跟在同一元素的结束标签之前e
,您可以将a
andb
元素完全替换为 的开始标签e
和结束标签e
,分别,并声明line
为
element line { e* }
e = element e { e* }
SAX 接口、DOM 接口、XSLT、XQuery 以及我所知道的处理 XML 的所有其他方法使得将动作与元素的开始和结束关联起来就像将动作与空元素关联起来一样简单。
您的有效示例将变为:
<line><e></e></line>
<line><e><e></e></e></line>
<line><e><e></e><e></e></e></line>
并且您的无效示例成为非格式良好的数据。