我想使用RELAX NG紧凑语法来验证一个XML元素,其子元素是一组n个特定元素中的一个,两个,三个或n个。例如,如果元素是'Layout'并且有一组三个特定元素:'top','center'和'bottom',则以下XML元素定义将是有效的:
<Layout>
<top/>
<center/>
<bottom/>
</Layout>
<Layout>
<top/>
</Layout>
<Layout>
<center/>
</Layout>
<Layout>
<bottom/>
</Layout>
<Layout>
<top/>
<center/>
</Layout>
我想知道如何编写两种模式: 1)让孩子们处于任何秩序。 2)限制儿童按特定顺序(例如:顶部,中部,底部)。
到目前为止,我对XML示例和有序模式的解决方案是:
element Layout {
(
element top { text },
element center { text }?
) |(
element top { text }?,
element center { text }?,
element bottom { text }
) |(
element center { text }
)
}
对于超过3个元素和/或无序模式,我没有一个好的解决方案。
答案 0 :(得分:1)
最近在RelaxNG list讨论了这些问题(我问过这个问题)。在第一种情况下,你试图编纂的限制是“我认为允许零或一组元素中的每一个”。没有简洁的方法可以做到这一点,但你可以做点什么。如果你有很多可能的子元素,那至少可以这么说(我的模式中有八个,而且说实话就足够了)。这样的事情应该适用于案例1.
我使用了命名模式使其更清晰。
start = e.layout
e.top = element top { text }
e.center = element center { text }
e.bottom = element bottom { text }
e.layout = element Layout {
(e.top & e.center? & e.bottom?) |
(e.top? & e.center & e.bottom?) |
(e.top? & e.center? & e.bottom)
}
这需要任何一个元素加上其他两个元素中的零个或一个。
为了强制执行序列,您可以执行类似的操作,但使用','运算符代替:
start = e.layout
e.top = element top { text }
e.center = element center { text }
e.bottom = element bottom { text }
e.layout = element Layout {
(e.top, e.center?) |
(e.top, e.center, e.bottom?) |
(e.top, e.center, e.bottom) |
(e.top, e.bottom?)
}
如果你要比这更复杂,我会认真考虑编写一个更简单的,简单地匹配相应的元素,然后使用Schematron规则来强制执行计数。所以,对于你的第二个要求:
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
xmlns:sch="http://purl.oclc.org/dsdl/schematron">
<start>
<ref name="e.Layout"/>
</start>
<define name="e.top">
<element name="top">
<text/>
</element>
</define>
<define name="e.center">
<element name="center">
<text/>
</element>
</define>
<define name="e.bottom">
<element name="bottom">
<text/>
</element>
</define>
<define name="e.Layout">
<sch:pattern name="check no more than one of each">
<sch:rule context="Layout/*">
<sch:assert test="count(../*[local-name(.) eq local-name(current())]) = 1">You may only have one <name/> element as a child of Layout.</sch:assert>
</sch:rule>
</sch:pattern>
<element name="Layout">
<oneOrMore>
<group>
<ref name="e.top"/>
<ref name="e.center"/>
<ref name="e.bottom"/>
</group>
</oneOrMore>
</element>
</define>
</grammar>
或者,在紧凑的语法中(注释在rnc中并不常见):
namespace sch = "http://purl.oclc.org/dsdl/schematron"
start = e.Layout
e.top = element top { text }
e.center = element center { text }
e.bottom = element bottom { text }
[
sch:pattern [
name = "check no more than one of each"
"\x{a}" ~
" "
sch:rule [
context = "Layout/*"
"\x{a}" ~
" "
sch:assert [
test = "count(../*[local-name(.) eq local-name(current())]) = 1"
"You may only have one " rng:name [ ] " element as a child of Layout"
]
"\x{a}" ~
" "
]
"\x{a}" ~
" "
]
]
e.Layout = element Layout { (e.top, e.center, e.bottom)+ }
答案 1 :(得分:1)
我不确定它是否会对你有帮助,但我们使用了它。
我们的问题:两个元素,任何顺序,都可以出现1到n次
解:
<interleave>
<oneOrMore>
<ref name="a.class"/>
</oneOrMore>
<oneOrMore>
<ref name="b.class"/>
</oneOrMore>
</interleave>
如需订购,只需删除<interleave>
即可。对于0到n次出现,请使用<zeroOrMore>
。
答案 2 :(得分:0)
您可以使用“element top {text} ?, element center {text} ?, element bottom {text}?”按所述顺序获得零或一个
或使用“element top {text}?&amp; element center {text}?&amp; element bottom {text}?”以任何顺序获得零或一个。
这两种模式都可以扩展到任意多种元素。