Celles-ci ont été discutées récemment sur le RelaxNG list (j'ai posé la question comme cela arrive). La restriction que vous essayez de codifier dans le premier cas est quelque chose du genre «permettre zéro ou un chacun d'un ensemble d'éléments», je pense. Il n'y a pas de bonne façon de le faire mais vous pouvez faire quelque chose. Si vous avez beaucoup d'éléments enfants possibles, c'est pour le moins fastidieux (j'ai huit dans mon schéma et c'est suffisamment de douleur honnêtement). Quelque chose comme ceci devrait fonctionner pour le cas 1.
J'ai utilisé des modèles nommés pour rendre cela plus lisible.
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)
}
Cela nécessite l'un des éléments plus zéro ou l'un de chacun des deux autres.
Pour appliquer une séquence, vous pouvez faire une chose semblable, mais utiliser le « » opérateur à la place que vous avez fait:
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?)
}
Si vous allez obtenir plus complexe que cela, je envisager sérieusement d'écrire beaucoup plus simple qui correspond simplement aux éléments appropriés et ensuite utiliser une règle de Schematron pour appliquer les comptes. Donc, pour votre deuxième exigence:
<?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>
ou, dans la syntaxe compacte (annotations ne sont pas assez en 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)+ }
Cela ne validerait également aucun élément. Dans l'exemple, 'Mise en page' devrait être non vide. – Javier
Bon point. Pour exclure cela, vous avez besoin d'un choix contenant N sous-modèles pour les N types d'éléments enfants, quelque chose comme "(haut & centre? & Bas?) | (Haut & centre & bas?) | (Haut & centre & bas?) ", ou la même chose avec des virgules au lieu d'ampersands si vous voulez commander.Au moins c'est seulement une explosion linéaire, pas une combinatoire. –