by Eric van der Vlist is published by O'Reilly & Associates (ISBN: 0596004214)
After this long introduction to annotation syntax, it is time to explore applications of annotations. The first application of annotations is for documentation. The issue of generating documentation from schemas, much like the problem of generating documentation from code, is a long-running problem with three different schools of thought:
The documentation and the schema are stored separately. In this case, there is nothing specific to documenting RELAX NG schemas, and this technique is beyond the scope of this book.
The schema can be embedded in the documentation: proponents of "Literate Programming" are fans of this approach. It will be presented in Chapter 14.
The documentation can be embedded within the schema: I'll cover this approach in this section.
You've seen the technical basis of how these annotations can be included in RELAX NG schemas. Generating documentation from these annotations is mainly a matter of writing an XSLT transformation to extract them and then formatting the annotations according to your needs. I won't be going through the details of XSLT transformations, but the following examples are good candidates for these kinds of transformation.
This example uses simple comments:
<define name="author-element"> <!-- Definition of the author element --> <element name="author"> <attribute name="id"/> <ref name="name-element"/> <ref name="born-element"/> <optional> <ref name="died-element"/> </optional> </element> </define> |
which is equivalent to:
author-element = # Definition of the author element element author { attribute id { text }, name-element, born-element, died-element? } |
These comments can be easily extracted, not only from the XML syntax using an XSLT transformation, but also from the compact syntax using regular expressions.
Comments provide a lightweight way to document RELAX NG schemas. They are the least intrusive mechanism to annotate schemas and can be used at any location in a schema, even within the text-only patterns value and param.
The problems with comments are well known:
The XML recommendation states that parsers don't have to report them, so some tools just ignore them. This was the case for early parsers and editors, but the situation has improved since the early days of XML. Most, if not all, of the XML parsers and editors now report XML comments.
Comments may contain only plain text and have no XML structures. In the context of a RELAX NG schema, this state is often not a concern; however, when needed, conventions can easily be added to define specific structures. This is done in JavaDoc, for example, where special "tags" are prefixed by @. Similarly, Wiki Wiki Webs express links as [ link title|http://...link.location].
I have already mentioned the RELAX NG DTD Compatibility specification in Chapter 8, in which we studied DTD datatypes. RELAX NG includes more than datatypes in the compatibility specification. It also includes a way to specify comments that would appear in a DTD equivalent to the RELAX NG schema. It also specifies an annotation for defining default values, which are covered later in this chapter.
DTD compatibility comments have a special status: the RELAX NG Technical Committee has defined a namespace for them and provided a shortcut to a concise form in the compact syntax. As annotations in the XML syntax and comment like in the compact syntax, they are thus a kind of middle ground between XML comments and RELAX NG annotations.
When using the XML syntax, DTD Compatibility Comments are foreign elements in the namespace http://relaxng.org/ns/compatibility/annotations/1.0. Their content is text-only, and they may be annotated using foreign namespace attributes. An example of schema using this feature is:
<?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"> <a:documentation>RELAX NG flat schema for our library</a:documentation> <start> <element name="library"> <oneOrMore> <ref name="book-element"/> </oneOrMore> </element> </start> <define name="author-element"> <a:documentation>Definition of the author element</a:documentation> <element name="author"> <attribute name="id"/> <ref name="name-element"/> <ref name="born-element"/> <optional> <ref name="died-element"/> </optional> </element> </define> ... </grammar> |
Here's an equivalent schema using the compact syntax:
## RELAX NG flat schema for our library grammar{ start = element library { book-element+ } ## Definition of the author element author-element = element author { attribute id { text }, name-element, born-element, died-element? } ... } |
Note that the syntax with the leading double hashes (##) is analogous to the /** comment used in JavaDoc. Despite the fact that they look like comments, these are annotations that have the same meaning and rules as initial annotations. They must precede the pattern to which they apply. This form is equivalent to:
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0" [ a:documentation [ "RELAX NG flat schema for our library" ] ] grammar { start = element library { book-element+ } [ a:documentation [ "Definition of the author element" ] ] author-element = element author { attribute id { text }, name-element, born-element, died-element? } ... } |
This shortcut has the same restrictions as initial annotations, in that they must precede all the initial annotations. It is possible to mix them with other types of annotations and write the following, for instance:
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0" a:documentation [ "RELAX NG flat schema for our library" ] start = element library { book-element+ } ## Definition of the author element author-element = element author { attribute id { text }, name-element, born-element, died-element? } ... |
Up to now, you've seen examples of compatibility comments that were the first element in their parent. These examples have hidden an important feature of these comments: they are using the trick mentioned in the previous section about workarounds for annotating param and value patterns. They apply their comments to the preceding sibling from the RELAX NG namespace when there is one. To annotate the reference to the name-element definition, you can write either:
<define name="author-element"> <element name="author"> <attribute name="id"/> <ref name="name-element"> <a:documentation>Definition of the author element</a:documentation> </ref> <ref name="born-element"/> <optional> <ref name="died-element"/> </optional> </element> </define> |
or:
<define name="author-element"> <element name="author"> <attribute name="id"/> <ref name="name-element"/> <a:documentation>Definition of the author element</a:documentation> <ref name="born-element"/> <optional> <ref name="died-element"/> </optional> </element> </define> |
In the first case, the DTD compatibility annotation is the first child element of its parent element (ref) and applies to the ref pattern for this reason. In the second case, the annotation isn't the first child element from the RELAX NG namespace and applies to its preceding sibling, which is the ref pattern again.
The compact syntax has the same rules, so the following annotations are equivalent:
author-element = element author { attribute id { text }, ## Definition of the author element name-element, born-element, died-element? } |
and:
author-element = element author { attribute id { text }, name-element >> a:documentation [ "Definition of the author element" ], born-element, died-element? } |
Here again, a following annotation is considered as an annotation of the name-element reference.
Of course, if you are annotating a param or value pattern, you have no other choice than to locate the annotation after the pattern, which is why this tricky mechanism has been introduced.
XHTML seems like a natural choice for embedding documentation in RELAX NG schemas. You have already seen several examples of such annotations. The main benefit of XHTML is that it is so similar to HTML that it is known by pretty much anyone who has ever published a web page. A lot of documentation and books on XHTML are available, and many editors can be used to edit XHTML documents. Furthermore, if you keep to a reasonable subset of XHTML (such as, for instance, XHTML Basic), you have a simple and generic language for writing documentation. The work needed to publish the result of the extraction of XHTML annotations as HTML is minimal, since your annotations are already XHTML.
You have also seen many examples of XHTML annotations, such as:
<?xml version="1.0" encoding="utf-8"?> <grammar xmlns="http://relaxng.org/ns/structure/1.0" xmlns:xhtml="http://www.w3.org/ 1999/xhtml"> <xhtml:div> <xhtml:h1>RELAX NG flat schema for our library</xhtml:h1> <xhtml:p>This schema has been written by <xhtml:a href="http://dyomedea.com/ vdv">Eric van der Vlist</xhtml:a>.</xhtml:p> </xhtml:div> ... </grammar> |
or, using the compact syntax:
namespace xhtml = "http://www.w3.org/1999/xhtml" xhtml:div [ xhtml:h1 [ "RELAX NG flat schema for our library" ] xhtml:p [ "This schema has been written by " xhtml:a [ href = "http://dyomedea.com/vdv" "Eric van der Vlist" ] "." ] ] start = element library { book-element+ } ... |
Beyond the syntax that has already been discussed in the first part of this chapter, note how I have embedded a title (xhtml:h1) and a paragraph (xhtml:p) within a division (xhtml:div). This is generally a good practice; it makes it easier to associate the title with the rest of the content and to manipulate the annotation as a whole.
First designed as an SGML application and very popular for writing technical documentation, DocBook is now also an XML language. With more features than XHTML, DocBook offers many predefined bells and whistles to facilitate indexes and cross references. DocBook makes it easy to indicate that some bit of text is a snippet of source code and can identify acronyms, as well as do many other things. These features can be emulated in XHTML using the class attribute, but in DocBook they are built in from the beginning, and there is a common meaning.
Tip | |
---|---|
You will find more information about DocBook on its web site: http://www.oasis-open.org/committees/docbook/ and in the book DocBook: The Definitive Guide, by Norm Walsh (O'Reilly). |
DocBook is defined as a DTD that doesn't use any namespaces; this isn't an issue because RELAX NG allows annotations through elements without namespace. To give you an idea of what DocBook looks like, as well as an example showing how to "undeclare" a namespace in XML, the following would more or less match the XHTML in the previous example:
<?xml version="1.0" encoding="utf-8"?> <grammar xmlns="http://relaxng.org/ns/structure/1.0"> <sect1 xmlns=""> <title>RELAX NG flat schema for our library</title> <para>This schema has been written by <xref linkend="vdv"/>.</para> </sect1> <start> <element name="library"> <oneOrMore> <ref name="book-element"/> </oneOrMore> </element> </start> ... </grammar> |
or, with the compact syntax:
sect1 [ title [ "RELAX NG flat schema for our library" ] para [ "This schema has been written by " xref [ linkend = "vdv" ] "." ] ] start = element library { book-element+ } ... |
While XHTML and DocBook are great for including content as documentation, Dublin Core fills a different niche. It is widely used over the Web to include metadata about all type of resources. Dublin Core includes a set of elements with a description of their semantics, which provides sharable information including details relevant to a schema. Dublin Core can answer questions about the schema's authors, their organization, the date, or the copyright associated with the schema. Dublin Core is very complementary to DocBook, and XHTML and is often used in XHTML documents, where it finds a natural fit in the meta element.
In a RELAX NG schema, Dublin Core elements may be included wherever it makes sense. Under the grammar pattern, they qualify the whole grammar, while under an element pattern, they qualify the specific element.
A more complete example than those shown previously includes title, creator, subject, description, date, language, and rights information for a schema:
<?xml version="1.0" encoding="UTF-8"?> <grammar xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns="http://relaxng.org/ns/structure/1.0"> <dc:title>The library element</dc:title> <dc:creator>Eric van der Vlist</dc:creator> <dc:subject>library, book, RELAX NG</dc:subject> dc:description>This RELAX NG schema has been written as an example to show how Dublin Core elements may be used.</dc:description> <dc:date>2003-01-30</dc:date> <dc:language>en</dc:language> <dc:rights>Copyright Eric van der Vlist, Dyomedea. During development, I give permission for non-commercial copying for educational and review purposes. After publication, all text will be released under the Free Software Foundation GFDL.</dc:rights> ... </grammar> |
or:
namespace dc = "http://purl.org/dc/elements/1.1/" dc:title [ "The library element" ] dc:creator [ "Eric van der Vlist" ] dc:subject [ "library, book, RELAX NG" ] dc:description [ "This RELAX NG schema has been written as an example to show how Dublin Core elements may be used." ] dc:date [ "2003-01-30" ] dc:language [ "en" ] dc:rights [ "Copyright Eric van der Vlist, Dyomedea. \x{a}" ~ "During development, I give permission for non-commercial copying for \x{a}" ~ "educational and review purposes. \x{a}" ~ "After publication, all text will be released under the \x{a}" ~ "Free Software Foundation GFDL." ] ... |
There is no reason to limit yourself to text and metadata; graphics can be included too, thanks to Scalable Vector Graphics (SVG). SVG is an XML vocabulary published by the W3C, and can be integrated as RELAX NG annotations like other XML vocabularies:
<?xml version="1.0" encoding="utf-8"?> <grammar xmlns="http://relaxng.org/ns/structure/1.0" xmlns:svg="http://www.w3.org/2000/svg"> <start> <element name="library"> <oneOrMore> <ref name="book-element"/> </oneOrMore> </element> </start> <define name="author-element"> <element name="author"> <svg:svg> <svg:title>A typical author</svg:title> <svg:ellipse style="stroke:#000000; fill:#e3e000; stroke-width:2pt;" id="head" cx="280" cy="250" rx="110" ry="130"/> <svg:ellipse style="stroke:none; fill:#7f7f7f; " id="leftEye" cx="240" cy="225" rx="18" ry="18"/> <svg:ellipse style="stroke:none; fill:#7f7f7f; " id="rightEye" cx="320" cy="225" rx="18" ry="18"/> <svg:path style="fill:none;stroke:#7F7F7F; stroke-width:5pt;" id="mouth" d="M 222 280 A 58 48 0 0 0 338 280"/> </svg:svg> <attribute name="id"/> <ref name="name-element"/> <ref name="born-element"/> <optional> <ref name="died-element"/> </optional> </element> </define> ... </grammar> |
or, using the compact syntax:
namespace svg = "http://www.w3.org/2000/svg" start = element library { book-element+ } author-element = [ svg:svg [ svg:title [ "A typical author" ] svg:ellipse >[ style = "stroke:#000000; fill:#e3e000; stroke-width:2pt;" id = "head" cx = "280" cy = "250" rx = "110" ry = "130" ] svg:ellipse [ style = "stroke:none; fill:#7f7f7f; " id = "leftEye" cx = "240" cy = "225" rx = "18" ry = "18" ] svg:ellipse [ style = "stroke:none; fill:#7f7f7f; " id = "rightEye" cx = "320" cy = "225" rx = "18" ry = "18" ] svg:path [ style = "fill:none;stroke:#7F7F7F; stroke-width:5pt;" id = "mouth" d = "M 222 280 A 58 48 0 0 0 338 280" ] ] ] element author { attribute id { text }, name-element, born-element, died-element? } ... |
I leave it to you as an additional exercise to visualize what a typical author looks like!
The last type of annotation I'd like to mention provides a transition between annotations for documentation purposes and annotation for applications. The Resource Directory Description Language (RDDL) is designed as an XML vocabulary that can be used by humans as documentation and by applications. Although RDDL was invented to document namespaces, it can fit very well in a RELAX NG schema. The information provided by RDDL annotations can be extracted to constitute RDDL documentation for the namespaces described in the schema. RDDL is based on XHTML and XLink and also works well with XHTML documentation.
The main benefit of RDDL is that it provides a way to associate resources with a document. As an example, I'll use it to associate an XSLT template and a CSS style sheet with the definition of the author element:
<?xml version="1.0" encoding="utf-8"?> <grammar xmlns="http://relaxng.org/ns/structure/1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:rddl="http://www.rddl.org/" xmlns:xhtml="http://www.w3.org/1999/xhtml"> <start> <element name="library"> <oneOrMore> <ref name="book-element"/> </oneOrMore> </element> </start> <define name="author-element"> <element name="author"> <xhtml:div> <rddl:resource id="author-transform" xlink:arcrole="http://www.w3.org/1999/xhtml" xlink:role="http://www.w3.org/1999/XSL/Transform" xlink:title="Author XSLT template" xlink:href="library.xslt#author"> <xhtml:div class="resource"> <xhtml:h4>XSLT Transformation</xhtml:h4> <xhtml:p>This <xhtml:a href="library.xslt#author">XSLT template</xhtml:a> displays the description of an author as XHTML.</xhtml:p> </xhtml:div> </rddl:resource> <rddl:resource id="CSS" xlink:title="CSS Stylesheet" xlink:role="http://www.isi.edu/in-notes/iana/assignments/media-types/text/ css" xlink:href="author.css"> <xhtml:div class="resource"> <xhtml:h4>CSS Stylesheet</xhtml:h4> <xhtml:p>A <xhtml:a href="author.css">CSS stylesheet</xhtml:a> defining some cool styles to display an author.</xhtml:p> </xhtml:div> </rddl:resource> </xhtml:div> <attribute name="id"/> <ref name="name-element"/> <ref name="born-element"/> <optional> <ref name="died-element"/> </optional> </element> </define> ... </grammar> |
or:
namespace rddl = "http://www.rddl.org/" namespace xhtml = "http://www.w3.org/1999/xhtml" namespace xlink = "http://www.w3.org/1999/xlink" start = element library { book-element+ } author-element = [ xhtml:div [ rddl:resource [ id = "author-transform" xlink:arcrole = "http://www.w3.org/1999/xhtml" xlink:role = "http://www.w3.org/1999/XSL/Transform" xlink:title = "Author XSLT template" xlink:href = "library.xslt#author" xhtml:div [ class = "resource" xhtml:h4 [ "XSLT Transformation" ] xhtml:p [ "This " xhtml:a [ href = "library.xslt#author" "XSLT template" ] " displays the description of an author as XHTML." ] ] ] rddl:resource [ id = "CSS" xlink:title = "CSS Stylesheet" xlink:role = "http://www.isi.edu/in-notes/iana/assignments/media-types/text/css" xlink:href = "author.css" xhtml:div [ class = "resource" xhtml:h4 [ "CSS Stylesheet" ] xhtml:p [ xhtml:a [ href = "author.css" "CSS stylesheet" ] " defining some cool styles to display an author." ] ] ] ] ] element author { attribute id { text }, name-element, born-element, died-element? } ... |
Applications that understand RDDL can act on this information automatically, while humans can find it through the XHTML documentation included with it.
This text is released under the Free Software Foundation GFDL.