[relaxng-user] Recursive structure with restrictions

Tor Helland tor at helland.org
Thu Jun 17 22:14:12 ICT 2004


Hi, I want to model a recursive structure with a choice of say 3 elements,
which again may contain that same choice as subelements. At least this is a
simple test case for the actual structure:

<container-abc>
    <a>
        <b>
            <c/>
        </b>
    </a>
</container-abc>
or
<container-abc>
    <c>
        <b>
            <a/>
        </b>
    </c>
</container-abc>

But I also want to reuse that structure in some other contexts, restricting
the allowed elements, without making a customised copy of the whole
definition:

<container-ab>
    <a>
        <b>
            <!-- <c/> would be illegal -->
        </b>
    </a>
</container-ab>
or
<container-c>
    <c>
        <c>
            <c/>
        </c>
    </c>
</container-c>

Playing with grammars, I found a solution demoed in the three documents at
the end of this email. I like the control I get over the structure, and not
repeating it.

Is there a better way to achieve this, preferrably with one schema file? Is
there a simpler way, something obvious I have overlooked?

-tor

test.xml:
<?xml version="1.0" encoding="UTF-8"?>
<test xmlns="test">
  <container-abc>
    <a>
      <b>
        <c/>
      </b>
    </a>
  </container-abc>
  <container-ab>
    <a>
      <b>
        <b/>
      </b>
    </a>
  </container-ab>
  <container-c>
    <c>
      <c>
        <c/>
      </c>
    </c>
  </container-c>
</test>


test.rng:
<?xml version="1.0" encoding="UTF-8"?>
<grammar ns="test" xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <element name="test">
      <empty/>
      <ref name="container-abc-element"/>
      <ref name="container-ab-element"/>
      <ref name="container-c-element"/>
    </element>
  </start>

  <define name="container-abc-element">
    <grammar>
      <include href="test2.rng"/>

      <start>
        <element name="container-abc">
          <ref name="container-choice"/>
        </element>
      </start>
      <define name="container-choice">
        <choice>
          <ref name="a-element"/>
          <ref name="b-element"/>
          <ref name="c-element"/>
        </choice>
      </define>
    </grammar>
  </define>
  <define name="container-ab-element">
    <grammar>
      <include href="test2.rng"/>

      <start>
        <element name="container-ab">
          <ref name="container-choice"/>
        </element>
      </start>
      <define name="container-choice">
        <choice>
          <ref name="a-element"/>
          <ref name="b-element"/>
        </choice>
      </define>
    </grammar>
  </define>
  <define name="container-c-element">
    <grammar>
      <include href="test2.rng"/>

      <start>
        <element name="container-c">
          <ref name="container-choice"/>
        </element>
      </start>
      <define name="container-choice">
        <choice>
          <ref name="c-element"/>
        </choice>
      </define>
    </grammar>
  </define>

</grammar>


test2.rng:
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">

  <define name="a-element">
    <grammar>
      <start>
        <element name="a">
          <empty/>
          <optional>
            <parentRef name="container-choice"/>
          </optional>
        </element>
      </start>
    </grammar>
  </define>
  <define name="b-element">
    <grammar>
      <start>
        <element name="b">
          <empty/>
          <optional>
            <parentRef name="container-choice"/>
          </optional>
        </element>
      </start>
    </grammar>
  </define>
  <define name="c-element">
    <grammar>
      <start>
        <element name="c">
          <empty/>
          <optional>
            <parentRef name="container-choice"/>
          </optional>
        </element>
      </start>
    </grammar>
  </define>

</grammar>



More information about the relaxng-user mailing list