by Eric van der Vlist is published by O'Reilly & Associates (ISBN: 0596004214)


Lists

RELAX NG supports the description of text nodes as lists of whitespace-separated values using the list pattern. This is the only pattern that transforms the structure of the document at validation time by splitting text values into lists of values. The benefit of doing so is that within a list pattern, all the patterns that constrain data values can be combined with the compositors, which lets you constrain the combination of these values.

If you use a list pattern without defining cardinality, you may not get what you expect. An attribute defined as:

<attribute name="see-also">
 <list>
  <data type="token"/>
 </list>
</attribute>

or, using the compact syntax:

attribute see-also {list {token}}

doesn't match a list of tokens (such as see-also="0345442695 0449220230 0449214044 0061075647 0061075612") but rather only a list of exactly one token (such as see-also="0345442695"). This is because the list pattern splits the text value into a list of values. This list is then evaluated against the patterns that are included within the list pattern. If you want a list of any number of tokens, use a zeroOrMore pattern to express that:

<attribute name="see-also">
 <list>
  <zeroOrMore>
   <data type="token"/>
  </zeroOrMore>
 </list>
</attribute>

Here's the compact syntax:

attribute see-also {list {token*}}

This definition treats the see-also attribute as a list of tokens and doesn't add any other constraints (this result is of course different when there are more datatypes). You can use other compositors in the list pattern exactly as in other contexts. To express that, you want a list with one to four tokens, you would write:

<attribute name="see-also">
 <list>
  <data type="token"/>
  <optional>
   <data type="token"/>
  </optional>
  <optional>
   <data type="token"/>
  </optional>
  <optional>
   <data type="token"/>
  </optional>
 </list>
</attribute>

or, using the compact syntax:

attribute see-also {list {token, token?, token?, token?}}

That is certainly verbose, but you've already seen there are no other options for defining the number of occurrences with RELAX NG.

You can also constrain the values of these tokens through an enumeration:

<attribute name="see-also">
 <list>
  <oneOrMore>
   <choice>
    <value>0836217462</value>
    <value>0345442695</value>
    <value>0449220230</value>
    <value>0449214044</value>
    <value>0061075647</value>
   </choice>
  </oneOrMore>
 </list>
</attribute>

or:

attribute see-also {list 
{("0836217462"|"0345442695"|"0449220230"|"0449214044"|"0061075647")+}}

A final point to note is that the list mechanism lets you define different constraints for different members of a list. To illustrate this feature, let's say you wish to give the physical dimension of a book by giving each of its three dimensions a unit, such as:

<book id="b0836217462" available="true" dimensions="0.38 8.99 8.50 inches">

In this case, you can define the dimensions attribute as:

    <attribute name="dimensions">
     <list>
      <data type="token"/>
      <data type="token"/>
      <data type="token"/>
      <choice>
       <value>inches</value>
       <value>cm</value>
       <value>mm</value>
      </choice>
     </list>
    </attribute>

or:

attribute dimensions {list {token, token, token, ("inches"|"cm"|"mm")}}

This text is released under the Free Software Foundation GFDL.