2

我正在尝试编写具有以下规则的 RelaxNG 模式:

  1. 一个line元素可以包含零个或多个a元素b
  2. 每个a元素都必须有一个对应的b元素,反之亦然。
  3. a元素必须始终位于其匹配b元素之前。

所以,以下都应该被认为是有效的:

<line><a/><b/></line>

<line><a/><a/><b/><b/></line>

<line><a/><a/><b/><a/><b/><b/></line>

同时,以下均无效:

<line><b/><a/></line>

<line><a/><a/><b/></line>

<line><a/></line>

<line><b/></line>

这如何在 RelaxNG 中表达?我的第一个想法是创建一个递归引用,如下所示:

element line { pair* }+

pair = a, pair?, b

a = element a { empty }
b = element b { empty }

然而,Jing 认为这是“对‘pair’的错误递归引用”。我无法为我的生活弄清楚如何解决这个问题!有任何想法吗?

4

1 回答 1

1

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 更容易获得所需内容。

一个简单的更改是将每个匹配项包装ab一个元素中(我将调用它e):

element line { pair* }
a = element a { empty }
b = element b { empty }
pair = element e { a, pair*, b }

现在,文档的有效性提供了一个非常简单的保证,即a元素和b元素按要求配对,并且每个都a在匹配之前b

鉴于aandb是空的,每个a紧跟在 开始标签e之后,并且每个b紧跟在同一元素的结束标签之前e,您可以将aandb元素完全替换为 的开始标签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>

并且您的无效示例成为非格式良好的数据。

于 2016-06-03T21:37:45.010 回答