Declaring Elements


The intent of a schema definition language is to first describe the elements that make up the language you are defining. Therefore, much of RELAX NG is composed of patterns that you will use to define the elements (and attributes) of an XML syntax. Each of the main RELAX NG patterns defines some aspect of the resulting XML.

Simple Elements

The simplest possible definition of an element uses, strangely enough, the element pattern:

      <element name="fullName" xmlns="http://relaxng.org/ns/structure/1.0">        <text />      </element> 

This pattern defines a single element, called fullName. The declaration includes the current RELAX NG namespace: http://www.relaxng.org/ns/structure/1.0. (Future versions will likely have a different version number.) As with all other XML syntax, you can either use this namespace as the default name-space, or provide a prefix for the RELAX NG elements within your schema. Therefore, both of the RELAX NG schemas in Listing 7-5 are valid.

Listing 7-5: Using namespaces with RELAX NG schemas

image from book
      <element name="contact" xmlns="http://relaxng.org/ns/structure/1.0">        <choice>          <element name="fullName">            <text />          </element>          <group>            <element name="givenName">                    <text />            </element>            <element name="lastName">              <text />            </element>          </group>        </choice>      </element>      <r:element name="contact" xmlns:r="http://relaxng.org/ns/structure/1.0">        <r:choice>          <r:element name="fullName">            <r:text />          </r:element>          <r:group>            <r:element name="givenName">              <r:text />            </r:element>            <r:element name="lastName">              <r:text />            </r:element>          </r:group>        </r:choice>      </r:element> 
image from book

The fullName element must include some text, as defined by the enclosed <text /> element. RELAX NG does not allow element patterns to be empty by default; you must include an element within each element definition that describes the expected content for XML files using the schema. If you are defining an XML element that doesn't have content, such as the <br /> element of XHTML, you should include the <empty /> element as content in the definition. For example:

      <element name="isActive">        <empty />      </element> 

If the element is only optional, you wrap it in the <optional> element as follows.

      <element name="contact" xmlns="http://relaxng.org/ns/structure/1.0">        <element name="fullName">          <text />        </element>        <optional>          <element name="email">            <text />          </element>        </optional>      </element> 

List Types

You rarely have one of anything with XML. Therefore, you need to be able to define the cardinality of a list of items-that is, how many of the items are valid in a schema.

One common cardinality defines whether an element may occur in any number. This is defined with the zeroOrMore element in your schema, as follows:

      <element name="contacts" xmlns="http://relaxng.org/ns/structure/1.0">        <zeroOrMore>          <element name="contact">            <element name="fullName">              <text />            </element>            <element name="email">              <text />            </element>          </element>        </zeroOrMore>      </element> 

Here you can see some of the simplicity of RELAX NG. Rather than describing the cardinality using terms such as minOccurs/maxOccurs, you simply wrap the element in a zeroOrMore element to define the fact that is optional but may occur in any number.

If the element must occur at least once, you use the oneOrMore element instead. For example:

      <element name="contacts" xmlns="http://relaxng.org/ns/structure/1.0">        <oneOrMore>          <element name="contact">            <element name="fullName">              <text />            </element>            <element name="email">              <text />            </element>          </element>        </oneOrMore>      </element> 

RELAX NG includes a third type of element that occurs multiple times: the list. This is for elements that contain multiple items, separated by whitespace. The schema defines the data format and quantity expected. For example, you may have a schema such as the following:

      <element name="line">        <element name="startPt">          <list>            <data type="float" />            <data type="float" />          </list>        </element>        <element name="endPt">          <list>            <data type="float" />            <data type="float" />          </list>        </element>      </element> 

The line element contains two child elements, startPt and endPt, which represent the starting and ending X and Y coordinates for the line. The following XML fragment shows how a valid document might appear using this schema:

      <line>        <startPt>1.0 4.5</startPt>        <endPt>3.2 7.0</endPt>      </line> 

In this example, the content of each element containing a list is broken using any whitespace character (such as a space or tab), and the data type and quantity are used to determine if the content is valid based on the schema.

Although the previous example uses two explicit <data> elements to define the expected quantity of child elements, you can also use the zeroOrMore or oneOrMore elements to produce more open-ended results. For example:

      <element name="contacts">        <zeroOrMore>          <element name="contact">            <element name="fullName">              <text />            </element>            <element name="email">              <text />            </element>            <optional>              <element name="spouseName">                <text />              </element>            </optional>            <optional>              <element name="children">                <list>                  <zeroOrMore>                   <text />                  </zeroOrMore>                </list>              </element>            </optional>          </element>        </zeroOrMore>      </element> 

In this schema, the children node will contain a list of names, separated by whitespace. There may be zero children, or any number. The following XML fragment shows some valid uses for this schema.

      <contacts>        <contact>          <fullName>Foo deBar</fullName>          <email>foo@debar.com</email>        </contact>        <contact>          <fullName>Bob Sjeruncle</fullName>                <email>bob.sjeruncle@example.com</email>          <spouseName>Mary Sjeruncle</spouseName>          <children>Rob Tina Anne</children>        </contact>        <contact>          <fullName>Anne Other</fullName>          <email>anne@example.com</email>          <children>Thea</children>        </contact>      </contacts> 

Each contact may have a child element, and that element will contain some number of names, separated by spaces (or other whitespace).

The only cardinality you cannot explicitly define with RELAX NG is when the minimum or maximum number of entries is something other than 0 or 1. For example, a manager element might have between 3 and 10 reports elements. However, these types of scenarios are rare, and they can easily be defined through the judicious use of optional and other elements.

Union Types

Union types are when two or more nodes may be valid at a given point in a schema. For example, a child node may occur as either an element or an attribute. Or an element might be presented either completely, or broken down into subcomponents. This last scenario is common when adding names to a schema. Do you include the fullName, or break it into surname and given names? RELAX NG enables you to handle these scenarios with the <choice> element, as shown here:

      <element name="contacts">        <zeroOrMore>          <element name="contact">            <choice>              <element name="fullName">                <text />              </element>              <group>                <element name="surname">                  <text />                </element>                <element name="givenName">                  <text />                </element>              </group>            </choice>            <element name="email">              <text />            </element>          </element>        </zeroOrMore>      </element> 

The choice element identifies a section of a schema where there may be multiple valid nodes. Each element that occurs within the choice becomes a valid entry at that point in an XML document using the schema. In order to mark a set of child elements as being together, you wrap them in the <group> element, as shown in the previous schema for the surname and givenName elements. Failing to add this would have meant that any one of the fullName, surname or givenName elements could have been used, but that surname and givenName could not be used together. The following XML shows a valid XML fragment using the schema defined previously:

      <contacts>        <contact>          <surname>deBar</surname>          <givenName>Foo</givenName>          <email>foo@debar.com</email>        </contact>        <contact>          <fullName>Anne Other</fullName>          <email>anne@example.com</email>        </contact>      </contacts> 

Each contact is identified using either the surname and givenName elements or with the fullName element.

Attributes

A common decision that you must make when you're creating an XML vocabulary is whether a given item should be an element or an attribute. Schemas that use elements for every item are the most extensible, and attribute-based schemas are the most compact. As opposed to DTDs and W3C Schema, in which you define attributes using different syntax than when you're defining elements, RELAX NG attempts to make defining attributes the same as defining elements.

You add attributes to your RELAX NG schemas with the <attribute> element, as shown in Listing 7-6.

Listing 7-6: Defining a schema with attributes

image from book
      <element name="contact" xmlns="http://relaxng.org/ns/structure/1.0">        <attribute name="fullName" />        <attribute name="email" />      </element> 
image from book

One change you may notice is that when you're adding attributes with RELAX NG, you don't need to include the <text /> child element like you do with <element>. This is because it is implied for attributes. You can, however, include it without error, as shown here:

      <element name="contact" xmlns="http://relaxng.org/ns/structure/1.0">        <attribute name="fullName">          <text />        </attribute>        <attribute name="email">          <text />        </attribute>      </element> 

Just as with elements, attributes added using this syntax are mandatory. To make an attribute optional, you wrap it with the <optional> element, just as you do with elements. For example:

      <element name="contact" xmlns="http://relaxng.org/ns/structure/1.0">        <attribute name="fullName" />        <attribute name="email" />         <optional>          <attribute name="notes" />        </optional>      </element> 

Order of Elements

Although RELAX NG attempts to use consistent behavior for both attributes and elements, there is one notable difference. The order of attributes is not significant, but the order of elements is. Therefore, using the schema defined in Listing 7-6, either of the two following fragments would be valid:

      <contact fullName="Foo deBar" email="foo@debar.com" />      <contact email="bob.sjeruncle@example.com" fullName="Bob Sjeruncle" /> 

However, using the equivalent schema with elements, this fragment is valid:

      <contact>        <fullName>Foo deBar</fullName>        <email>foo@debar.com</email>      </contact> 

The following fragment is not valid, because the two child elements don't appear in the same order as in the schema:

      <contact>        <email>foo@debar.com</email>        <fullName>Foo deBar</fullName>      </contact> 

If the order of the elements is not significant, you can use the <interleave> pattern to group those elements, like this:

      <?xml version="1.0" encoding="UTF-8"?>      <element name="order" xmlns="http://relaxng.org/ns/structure/1.0">          <zeroOrMore>            <interleave>              <element name="name">                  <text/>              </element>              <element name="email">                  <text/>              </element>            </interleave>          </zeroOrMore>      </element> 

In this schema, the name and e-mail elements can occur in any order. The interleave element is useful when XML documents need extra flexibility. For example, the elements within XHTML documents can occur in any order. Listing 7-7 shows a simplified section of the XHTML schema for the <head> element, as it might be defined in RELAX NG.

Listing 7-7: RELAX NG schema for XHTML <head>

image from book
      <?xml version="1.0" encoding="UTF-8"?>      <element name="head" xmlns="http://relaxng.org/ns/structure/1.0">          <interleave>              <element name="title">                  <text/>              </element>              <zeroOrMore>                  <element name="style">                     <text/>                  </element>              </zeroOrMore>              <zeroOrMore>                  <element name="script">                     <text/>                  </element>              </zeroOrMore>              <zeroOrMore>                  <element name="meta">                     <text/>                  </element>              </zeroOrMore>          </interleave>      </element> 
image from book

When you're writing an XHTML document, you don't normally think of the order you use to add elements, therefore the interleave pattern is ideal.

Another use for the interleave pattern is when an element may have child elements in addition to, or instead of, text. Listing 7-8 shows a schema and Listing 7-9 the XML fragment for this type of scenario.

Listing 7-8: Mixed-content elements-Schema

image from book
      <element name="meetings" xmlns="http://relaxng.org/ns/structure/1.0">          <oneOrMore>              <element name="meeting">                  <element name="topic">                      <text/>                  </element>                  <element name="dateTime" datatypeLibrary="">                      <text/>                  </element>                  <optional>                      <element name="notes">                          <interleave>                              <zeroOrMore>                                  <element name="keyPoint">                                          <text/>                                </element>                             </zeroOrMore>                             <text/>                         </interleave>                     </element>                  </optional>              </element>          </oneOrMore>      </element> 
image from book

Listing 7-9: Mixed-content elements-XML fragment<meetings>

image from book
        <meeting>          <topic>Plan new widget</topic>          <dateTime>2006-04-01T14:30:00Z</dateTime>          <notes>      Lorem ipsum dolor sit amet, <keyPoint>consectetuer adipiscing elit</keyPoint>.      Fusce id ante et orci facilisis tristique. Suspendisse viverra. <keyPoint>Morbi at      purus</keyPoint> non metus venenatis egestas. Duis nulla ipsum, imperdiet eu,      interdum vitae, mattis ut, diam. <keyPoint>Integer egestas ultricies      lacus</keyPoint>. Suspendisse commodo. Vestibulum diam. Curabitur consectetuer      tempor diam. Aliquam <keyPoint>tincidunt mollis mi</keyPoint>. Suspendisse porta      lorem vitae odio. Mauris accumsan sapien eget ante. Praesent suscipit lobortis      turpis.          </notes>        </meeting>        <meeting>          <topic>Assign widget tasks</topic>          <dateTime>2006-04-04T09:00:00Z</dateTime>          <notes>      Morbi rhoncus, purus ac imperdiet auctor, quam augue euismod diam, ac tempus dolor      metus in odio. Sed ac lacus. Cras pulvinar enim sed justo tempor fermentum. Proin      dictum dapibus urna. Maecenas at velit a <keyPoint>magna congue      pulvinar</keyPoint>. Praesent <keyPoint>consectetuer convallis erat. Cras lobortis      orci eu pede dapibus aliquam. Ut fringilla molestie risus. Nam diam.      <keyPoint>Quisque consequat euismod turpis</keyPoint>.          </notes>        </meeting>      </meetings> 
image from book

Because this pattern is fairly common in XML, RELAX NG creates a shortcut method that enables you to describe elements like this: <mixed>. Using <mixed>, you can simplify the schema in Listing 7-8 to the one shown in Listing 7-10. Notice that the <mixed> section does not need to include either the <interleave> pattern or <text />.

Listing 7-10: Using <mixed>

image from book
      <element name="meetings" xmlns="http://relaxng.org/ns/structure/1.0">          <oneOrMore>              <element name="meeting">                  <element name="topic">                            <text/>                  </element>                  <element name="dateTime" datatypeLibrary="">                      <text/>                  </element>                  <optional>                      <element name="notes">                          <mixed>                              <zeroOrMore>                                  <element name="keyPoint">                                      <text/>                                  </element>                              </zeroOrMore>                          </mixed>                      </element>                  </optional>              </element>          </oneOrMore>      </element> 
image from book

Defining Grammar

Some schemas can have different valid root nodes. For example, the Atom specification allows the root node to either be an atom:feed element or atom:entry. With W3C schemas, you would have to define this as two schemas. RELAX NG, on the other hand, enables you to create schemas with different root nodes by using two special elements: grammar and start.

The grammar element replaces the normal starting node. The start element then contains the various nodes that may be used as the root node in the syntax. Listing 7-11 shows these two elements in action as part of the Atom 1.0 specification.

Listing 7-11: Using grammar and start elements

image from book
      <grammar xmlns:atom="http://www.w3.org/2005/Atom"        xmlns="http://relaxng.org/ns/structure/1.0"        datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">        <start>          <choice>            <element name="atom:feed">              ...            </element>            <element name="atom:entry">              ...            </element>          </choice>        </start>      </grammar> 
image from book

In this schema, the grammar element marks the starting point of the schema definition, and includes the namespaces used by the definition. The full Atom specification includes other namespaces, but these have been removed for simplicity. You can define multiple elements within the grammar element. Therefore, you need the start element to identify the possible root nodes of the document. In this case, the start element includes a choice element, meaning that multiple elements are possible-either the atom:feed or atom:entry elements can represent the starting point of an Atom document. Although you can approximate this with W3C XML Schema by identifying each of the root nodes as minOccurs=“0”, a document with neither may be valid. RELAX NG avoids this outcome.

Reusing Types

There may be times when you want to reuse the structure of a schema. For example, you may use an address structure multiple times within the schema. Alternately, you may want to maintain a library of commonly defined items to be included in your company's schemas. RELAX NG supports both internal and external references to reuse schema patterns.

A common model of writing schemas is to define building block elements, such as address or partClass, and then include these building blocks at the appropriate location of the schema (that is, to use an internal reference in your schemas). You can do this in RELAX NG with the ref and define elements.

The define element is used to define a type for reference elsewhere in the document. This element has the required attribute name. This name is referenced with the ref element to include the defined structure. Listing 7-12 shows these two elements in action.

Listing 7-12: Using define and ref for internal references

image from book
      <?xml version="1.0" encoding="UTF-8"?>      <grammar        xmlns="http://relaxng.org/ns/structure/1.0"        xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0"        datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">          <start>              <element name="orders">                  <oneOrMore>                      <element name="order">                          <element name="shipToAddress">                           <ref name="addressType" />                          </element>                          <element name="billToAddress">                              <ref name="addressType" />                          </element>                          </element>                  </oneOrMore>              </element>          </start>          <define name="addressType">              <element name="street">                  <text />              </element>              <element name="city">                  <text />              </element>              <element name="state">                  <text />              </element>              <element name="zip">                  <text />              </element>                    <element name="country">                  <text />              </element>          </define>      </grammar> 
image from book

The addressType definition creates a simple structure that you can use elsewhere in the document. Both the shipToAddress and billToAddress elements then reference this definition.

External references are basically the same as internal references, with the exception that the defined pattern is located in a separate file. The externalRef and include elements identify this file with its href attribute. This is another useful technique for creating modular RELAX NG schemas. You can create standard definitions of commonly used patterns, and then reference them to complete the schema. Listing 7-13 defines a pattern for a part definition and Listing 7-14 shows how you might reference this file. Although the include and externalRef patterns are similar in behavior, they serve two logical needs. The include pattern acts like an import and must occur as a child node to the grammar element. The included document must contain a grammar root node. Conversely, the externalRef element may occur at any place in the schema, and the file referenced does not need to be a complete grammar.

Listing 7-13: Using externalRef-External Schema

image from book
      <?xml version="1.0" encoding="UTF-8"?>      <grammar        xmlns="http://relaxng.org/ns/structure/1.0"        datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">          <start><ref name="partDefinition" /></start>          <define name="partDefinition">              <attribute name="id"><data type="integer"/></attribute>              <element name="shortName"><text /></element>              <element name="fullName"><text /></element>              <element name="description"><text /></element>              <element name="components"><ref name="partDefinition" /></element>          </define>      </grammar> 
image from book

Listing 7-14: Using externalRef-Referencing Schema

image from book
      <?xml version="1.0" encoding="UTF-8"?>      <grammar xmlns="http://relaxng.org/ns/structure/1.0"          <start>              <element name="productCatalog">                  <zeroOrMore>                      <element name="part">                          <externalRef href="externalRefDefinition.rng" />                      </element>                  </zeroOrMore>              </element>          </start>      </grammar> 
image from book

Listings 7-13 and 7-14 show two RELAX NG schemas. The first defines a grammar that includes a single element named partDefinition. This element defines a single attribute and four child elements. Note that the last child element references itself, meaning that the parts may be defined recursively. This partDefinition file is referenced using the externalRef element in the second schema. The href attribute of the externalRef element points to the URL of the included schema. In this example, the two files are stored in the same directory. Therefore, the URL includes only the filename. You could store all of your external definitions in a single location and reference them with a full URL. The externalRef element acts as though the referenced file replaces the externalRef element. Therefore, the resulting logical schema is as if the contents of the partDefinition file were included within the <element name=“part”> pattern.

Merging Schemas

When you begin reusing schema parts with <ref> and <externalRef>, you will eventually need to combine two types that contain multiple definitions for the same name. RELAX NG contains patterns that describe how the schema should combine the multiple definitions.

There are two main ways that RELAX NG can combine schema: the definitions can be combined, or one definition can replace or override the other definitions.

The core pattern used to merge two or more schemas is the <combine> attribute. You include this attribute for elements that have multiple definitions. This attribute must have a value of either choice or interleave, which describes how the schema validates the XML. Listing 7-15 shows the use of the combine attribute.

Listing 7-15: Combine attribute

image from book
      <?xml version="1.0" encoding="UTF-8"?>      <grammar xmlns="http://relaxng.org/ns/structure/1.0">          <start>              <element name="orders">                  <zeroOrMore>                      <element name="order">                          <element name="customer">                              <ref name="contact"/>                          </element>                          <oneOrMore>                              <element name="orderItem">                                  <element name="item">                                      <ref name="product"/>                                  </element>                              </element>                          </oneOrMore>                      </element>                  </zeroOrMore>              </element>          </start>          <!-- These would likely be from separate externalRefs -->          <define name="contact" combine="choice">              <attribute name="id"/>              <element name="fullName">                  <text/>              </element>          </define>          <define name="contact" combine="choice">              <attribute name="id"/>                    <element name="given">                  <text/>              </element>              <element name="surname">                  <text/>              </element>              <element name="price">                  <text/>              </element>          </define>          <define name="product" combine="interleave">              <attribute name="id"/>              <attribute name="name"/>          </define>          <define name="product" combine="interleave">              <attribute name="description"/>          </define>      </grammar> 
image from book

If the combine attribute is choice, this means that any of the items combined are valid. The following schema fragment is equivalent to the one shown in Listing 7-15:

      <grammar xmlns="http://relaxng.org/ns/structure/1.0">          <start>              <element name="orders">                  <zeroOrMore>                      <element name="order">                          <element name="customer">                              <element name="contact">                                  <attribute name="id"/>                                  <choice>                                      <element name="fullName">                                          <text/>                                      </element>                                      <group>                                          <element name="given">                                             <text/>                                        </element>                                        <element name="surname">                                            <text/>                                        </element>                                    </group>                                </choice>                            </element>                        </element>                        <oneOrMore>                            <element name="orderItem">                                <element name="item">                                    <interleave>                                        <attribute name="id"/>                                        <attribute name="name"/>                                        <attribute name="description"/>                                    </interleave>                                </element>                            </element>                               </oneOrMore>                     </element>                  </zeroOrMore>              </element>          </start>      </grammar> 

When combining multiple schemas, there may be a case when you need to replace the existing definition with the one from the external definition, such as when the core definition includes a placeholder element that will be provided by the external definition. Alternately, the core definition may include a default implementation (such as an address pattern that defaults to the US formatting), and the external implementations override this behavior for other implementations. The schemas in Listing 7-16 and Listing 7-17 show how you can override a definition in another RELAX NG schema.

Listing 7-16: The replace pattern-Base definition

image from book
      <?xml version="1.0" encoding="UTF-8"?>      <grammar xmlns="http://relaxng.org/ns/structure/1.0">          <start>              <element name="orderItems">                  <element name="shipAddress">                      <ref name="address"/>                  </element>                  <oneOrMore>                      <ref name="item"/>                  </oneOrMore>              </element>          </start>          <define name="item">              <notAllowed/>          </define>          <define name="address">              <element name="street">                  <text/>              </element>              <element name="city">                  <text/>              </element>              <element name="state">                  <text/>              </element>              <element name="zip">                  <text/>              </element>          </define>      </grammar> 
image from book

Listing 7-17: The replace pattern-Overriding base

image from book
      <grammar xmlns="http://relaxng.org/ns/structure/1.0">          <include href="replaceBase.rng">              <define name="item">                  <attribute name="partNum"/>                  <attribute name="color">                            <choice>                          <value>red</value>                          <value>black</value>                          <value>blue</value>                      </choice>                  </attribute>              </define>              <define name="address">                  <element name="street"><text /></element>                  <element name="city"><text /></element>                  <element name="postalCode"><text /></element>              </define>          </include>      </grammar> 
image from book

The notAllowed element is a placeholder for an alternate implementation. You can add it at any point in a schema to mark a point where a later element will use replace to provide the actual implementation. In the preceding base schema, the item element is undefined in the orderItems schema. Instead, the orderItems includes the notAllowed element. The notAllowed element will not match any content. The item element is defined in the overriding schema. Notice that the replacement definitions for item and address are written within the <include> element. This ensures that it will be included within the original schema. If the define elements were not enclosed within the include element, they would be considered side-by-side definitions, and you would have to include the combine attribute.

Namespaces and Name Classes

RELAX NG also supports the use of namespaces to define elements and attributes that exist within alternate schemas. (See Chapter 1 for more information on namespaces.)

There may be times when you are not absolutely sure what tags may be within a block, such as when you have an element that may contain arbitrary XHTML or another XML dialect. In those cases, you want to describe the possible content, but you don't want to simply leave it as <text />. Alternately, you might want to create a pattern where the documents may include any attribute, or any attribute with a given namespace. In these cases, you will make use of the RELAX NG name classes.

The simplest name class is anyName. This represents any possible node, regardless of the name or name-space. It is equivalent to the any element in W3C XML schema. In the schema shown in Listing 7-18, the notes element can include any single element, of any name. That element may include any number of attributes and child elements.

Listing 7-18: Using the anyName element

image from book
      <grammar xmlns="http://relaxng.org/ns/structure/1.0">        <start>          <element name="contact">            <element name="fullName">              <text />            </element>            <element name="email">              <text />            </element>                  <element name="notes">              <ref name="childElement" />            </element>          </element>        </start>        <define name="childElement">          <element>            <anyName />              <zeroOrMore>                <attribute>                  <anyName />                </attribute>              </zeroOrMore>              <text />              <zeroOrMore>                <ref name="childElement" />              </zeroOrMore>          </element>        </define>      </grammar> 
image from book

In this schema, the notes element is defined as a childElement. This definition allows any element (the <element><anyName /></element> part. Also within the childElement, you can have zeroOrMore attributes, again with any name. In addition to these elements, the childElement pattern may contain <text /> and zeroOrMore child elements using the same definition. This is the definition of well-formed XML. Therefore, the notes element of the contact will be valid as long as it contains any well-formed XML.

In addition to the anyName element, REL AX NG includes two other name classes for describing valid content: nsName and except. You use the nsName element to identify the namespace of valid content when you need to include elements or attributes of a specific alternate namespace to your schema. For example, you may need to define a schema in which part of the document should contain a valid SOAP message. The following fragment shows how this would be defined using RELAX NG:

      <element name="message">        <element>          <nsName ns=" http://www.w3.org/2003/05/soap-envelope/" />        </element>      </element> 

Both the anyName and nsName elements may include the <except> child. This provides exceptions to the parent. You may have an element that can include any possible child element except specific ones, or more commonly, you may want to exclude specific elements or namespaces as possible children. The following schema fragment shows an element that may have any child element, but only the xs:type attribute from the W3C XML schema data types namespace (http://www.w3.org/2001/XMLSchema):

      <element name="item" xmlns:xs="http://www.w3.org/2001/XMLSchema" >          <zeroOrMore>              <attribute>                        <anyName>                      <except>                          <nsName ns="http://www.w3.org/2001/XMLSchema"/>                      </except>                  </anyName>              </attribute>          </zeroOrMore>          <optional>              <attribute name="xs:type"/>          </optional>      </element> 

This item element definition allows for any attribute, except one with the namespace of http://www.w3.org/2001/XMLSchema, that includes the data type definitions. This item is added later with the optional attribute that includes both name and ns attributes.

Annotating Schemas

The RELAX NG specification does not explicitly define an element or pattern for annotating your schema. However, because it supports namespaces and including elements from alternate namespaces in your schemas, you can add annotations using another namespace. The Oxygen XML editor (discussed later in this chapter) adds the http://www.relaxng.org/ns/compatibility/annotations/1.0 name-space to documents it creates. You can then use this namespace to add notes to your schema, keeping in mind that they will be ignored by the parser except as needed. The schema in Listing 7-19 includes a couple of annotations that use this namespace.

Listing 7-19: Annotating RELAX NG schemas

image from book
      <grammar xmlns="http://relaxng.org/ns/structure/1.0"          xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0">          <start>              <a:documentation>Short schema for a personal contact</a:documentation>              <element name="contact">                  <a:documentation xml:lang="en">                    Full name of the contact ({given Name} {surname}                  </a:documentation>                  <element name="fullName">                      <text/>                  </element>                  <a:documentation>                    E-mail address using RFC 822(http://www.w3.org/Protocols/rfc822/)                  </a:documentation>                  <element name="email">                      <text/>                  </element>              </element>          </start>      </grammar> 
image from book




Professional XML
Professional XML (Programmer to Programmer)
ISBN: 0471777773
EAN: 2147483647
Year: 2004
Pages: 215

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net