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>