CIS 97YT Index > Assignment 3 > Solution with Nested Lists

Here is one solution to Assignment 3. It is not the only possible way to solve the problem, but it is reasonably concise and readable.

Notice that this solution uses lots of <define>s. This makes each section easy to read, and the indenting never gets too deep to be confusing. Also, blank lines are used liberally to improve readability.

<grammar datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
  xmlns="http://relaxng.org/ns/structure/1.0">

<!-- 
==================================
    Catalog Relax NG description
	(permits nested <ul> in XHTML subset)
    J. David Eisenberg
    CIS97YT
 ======================================
 -->


<start>
    <element name="catalog">
        <element name="company">
            <text/>
        </element>
        
        <oneOrMore>
            <ref name="dept-defn"/>
        </oneOrMore>
    </element>
</start>

<define name="dept-defn">
    <element name="department">
        <attribute name="name"/>
        <attribute name="code">
            <data type="ID"/>
        </attribute>
        <oneOrMore>
            <ref name="item-defn"/>
        </oneOrMore>
    </element>
</define>

<define name="item-defn">
    <element name="item">
        <element name="name"><text/></element>
        <interleave>
            <ref name="price-defn"/>

            <optional>
                <element name="manufacturer">
                    <text/>
                </element>
            </optional>

            <choice>
                <ref name="color-list-defn"/>
                <ref name="color-defn"/>
                <element name="sku">
                    <ref name="sku-pattern"/>
                </element>
            </choice>

            <element name="summary">
                <ref name="XHTML-subset"/>
            </element>

            <optional>
                <element name="description">
                    <ref name="XHTML-subset"/>
                </element>
            </optional>
        </interleave>
    </element>
</define>

<define name="price-defn">
    <element name="price">
        <attribute name="amt">
            <data type="decimal"/>
        </attribute>
        
        <optional>
            <attribute name="units">
                <choice>
                    <value>USD</value>
                    <value>CDN</value>
                </choice>
            </attribute>
        </optional>
    </element>
</define>

<define name="color-list-defn">
    <element name="color-list">
        <oneOrMore>
            <ref name="color-defn"/>
        </oneOrMore>
    </element>
</define>

<define name="color-defn">
    <element name="color">
        <text/>
        
        <attribute name="sku">
            <ref name="sku-pattern"/>
        </attribute>

        <optional>
            <attribute name="hex">
                <data type="string">
                    <param name="pattern">#[0-9A-Fa-f]{6}</param>
                </data>
            </attribute>
        </optional>
    </element>
</define>

<define name="sku-pattern">
    <data type="string">
        <param name="pattern">[A-Z]{1,2}\d{3,4}(-[A-Za-z]{2})?</param>
    </data>
</define>

<!--
==================================================================
    The key to the XHTML subset is to do exactly what the
    specification says.  A <summary> and <description>
    can contain a series of
    
        * text-with-inline-elements OR
        * <p>, which contains text-with-inline-elements OR
        * <ul>, which contains
            * one or more <li> elements, each of which
              contains anything in the XHTML subset.
              (This will give us nested list capability)
===================================================================
-->
<define name="XHTML-subset">
    <zeroOrMore ns="http://www.w3.org/1999/xhtml">
        <choice>
            <ref name="text-with-inline"/>
            
            <element name="p">
                <ref name="text-with-inline"/>
            </element>
            
            <element name="ul">
                <oneOrMore>
                    <element name="li">
                        <ref name="XHTML-subset"/>
                    </element>
                </oneOrMore>
            </element> 
        </choice>
    </zeroOrMore>
</define>

<!--
    Since everyone refers to the text-with-inline define,
    it is the only place where we will need <interleave>
    with text.
-->
<define name="text-with-inline">
    <interleave>
        <text/>
        <zeroOrMore ns="http://www.w3.org/1999/xhtml">
            <choice>
                <element name="strong">
                    <ref name="text-with-inline"/>
                </element>
                <element name="em">
                    <ref name="text-with-inline"/>
                </element>
            </choice>
        </zeroOrMore>
    </interleave>
</define>
</grammar>