XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.

advertisement

An Introduction to the Relaxer Schema Compiler
Pages: 1, 2

Generating Stylesheets

With Relaxer's -xslt option, you can construct an XSLT stylesheet that is essentially an identity transform for the originating document or documents. The command

relaxer -xslt album01.xml album02.xml

produces the stylesheet album01.xsl:

<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes" method="xml"/>
  <xsl:template 
  match="album[title and artist and manufacturer and release and format and condition]">
    <album>
      <xsl:attribute name="id">
        <xsl:value-of select="@id"/>
      </xsl:attribute>
      <xsl:apply-templates/>
    </album>
  </xsl:template>
  <xsl:template match="manufacturer">
    <manufacturer>
      <xsl:apply-templates/>
    </manufacturer>
  </xsl:template>
  <xsl:template match="format">
    <format>
      <xsl:apply-templates/>
    </format>
  </xsl:template>
  <xsl:template match="release">
    <release>
      <xsl:apply-templates/>
    </release>
  </xsl:template>
  <xsl:template match="artist">
    <artist>
      <xsl:apply-templates/>
    </artist>
  </xsl:template>
  <xsl:template match="condition">
    <condition>
      <xsl:apply-templates/>
    </condition>
  </xsl:template>
  <xsl:template match="title">
    <title>
      <xsl:apply-templates/>
    </title>
  </xsl:template>
  <xsl:template match="comments">
    <comments>
      <xsl:apply-templates/>
    </comments>
  </xsl:template>
</xsl:stylesheet>

Each template contains literal result elements that mirror each node in the originating document. If you process album01.xml or album02.xml with album01.xsl, you will get a result tree that fairly resembles the source tree. It also gives you a good start for writing your own custom stylesheet.

You can also control the output of the XSLT generator by using the -xslt.template option in tandem with -xslt. The -xslt.template option takes as a parameter an XSLT stylesheet that may be annotated with Relaxer-specific attributes. When these attributes are processed by Relaxer, they will augment the location paths in a generated stylesheet, giving them a more precise context.

Consider the following stylesheet, album.xsl:

<xsl:stylesheet version="1.0"
 xmlns:label="http://www.relaxer.org/xmlns/relaxer/xslt/label"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>

 <xsl:template label:match="album">
  <html xmlns="http://www.w3.org/1999/xhtml">
  <head><title><xsl:apply-templates select="title"/></title></head>
  <body>
   <p><b>Release Date</b>: <xsl:apply-templates label:select="release"/><</p>
  </body>
  </html>
 </xsl:template>

</xsl:stylesheet>

This stylesheet is intended to create a brief HTML document that contains an album's title and release date. The label namespace marks attributes for Relaxer to process specially. If you enter the command

relaxer -xslt -xslt.template:album.xsl album02.xml

Relaxer produces the following stylesheet (album02.xsl):

<?xml version='1.0'?>
<xsl:stylesheet version="1.0" 
xmlns:label="http://www.relaxer.org/xmlns/relaxer/xslt/label" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes" method="xml"/>
  <xsl:template label:match="album" 
  match="album[title and artist and manufacturer and release and format and condition and comments]">
    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <title>
          <xsl:apply-templates select="title"/>
        </title>
      </head>
      <body>
        <p>
          <b>Release Date</b>: 
		  <xsl:apply-templates label:select="release" select="release"/>
        </p>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

Notice the value of the match attribute in the template element. The location path now contains a predicate that is highly specific to documents that have the <album> data model.

Generating Java Classes with Relaxer

Now let's generate some Java code with Relaxer. You can use an XML instance, a Relax Core schema, or a RELAX NG schema for code generation, but not WXS or DTDs. We'll use the RELAX NG schema produced earlier, album01.rng. To generate Java source code from this schema, enter this line at a command or shell prompt:

relaxer -java album01.rng

Note the -java switch. Relaxer produces the following four Java files as a result of this command:

  • Album.java
  • RStack.java
  • UJAXP.java
  • URelaxer.java

Album.java is based on album01.rng, and provides several constructors for creating objects based on album01.rng's data model. Among others, Album.java provides a default constructor with no arguments, another that accepts a file as an argument (java.io.File), and another that accepts a SAX InputSource argument (org.xml.sax.InputSource).

Album.java also provides a number of methods that you can use to access or manipulate the content of a document that has the same content model. For example, you can use the getArtist() and setArtist() methods in Album.java to retrieve or change the content of the <artist> element in instances that are valid with regard to album01.rng.

Other methods in Album.java include makeDocument(), which creates a DOM representation of the object modeled after the schema, and makeTextDocument(), which outputs a representation of the object as an XML document.

The other three Java files that Relaxer produced -- RStack.java, UJAXP.java, and URelaxer.java -- were generated automatically and support underlying functionality of Album.java. The fields and methods in these files are not user-accessible.

To easily examine the Java source that Relaxer produces, you can apply Javadoc to the source files with this line:

javadoc -d doc Album.java RStack.java UJAXP.java URelaxer.java

This command will place Javadoc's output files in the subdirectory doc. If you open the file doc/index.html in a browser, you will be able to navigate through the documentation of the classes to get a feel for all the fields, constructors, and methods that Relaxer created.

Compiling and Running Relaxer's Java Code

If you have a Java SDK installed, you can compile these Java files with javac, as follows:

javac Album.java

This command compiles Album.java, RStack.java, UJAXP.java, and URelaxer.java. In the example archive, you will also find a Java file that Relaxer did not create. It is called TestAlbum.java. Here is the source code for the program:

import java.io.File;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;

/**
 * A small application that changes the content of
 * valid album type documents.
 *
 */
public class TestAlbum {

    public static void main(String[] args)
	throws IOException, SAXException, ParserConfigurationException {

        if (args.length == 0) {
             System.out.println("Usage: java TestAlbum file.xml");
             System.exit(1);
        }

        // Instantiate an Album object with a file
	Album album = new Album(new File(args[0]));
 
        // Print the XML representation of the document
	System.out.println("\nOriginal document:\n");
	System.out.println(album.makeTextDocument());
 
        // Change the content   
        album.setId("ID-8406-4-R");
	album.setTitle("Cool Water");
	album.setArtist("The Sons of the Pioneers");
	album.setManufacturer("RCA/BMG");
	album.setRelease("no date");
	album.setComments("none");

        // Again, print the XML representation of the document
	System.out.println("\nUpdated document:\n");
	System.out.println(album.makeTextDocument());

    }

}

Now compile and run this program.

javac TestAlbum.java
java TestAlbum

The output for this program will look something like this:

Original document:

<album id="HANC-20241"><title>The Best of Patsy Cline
</title><artist>Patsy Cline</artist>
<manufacturer>MCA Records, Inc.</manufacturer>
<release>1985</release><format>cassette
</format><condition>good</condition></album>

Updated document:

<album id="ID-8406-4-R"><title>Cool Water</title>
<artist>The Sons of the Pioneers</artist>
<manufacturer>RCA/BMG</manufacturer><release>
no date</release><format>cassette</format>
<condition>good</condition><comments>none
</comments></album>

As you can see, the document content can be changed programmatically by calls to the set methods.

Conclusion

Relaxer has many other features which we cannot cover here. This article only deals with a few of its fundamental features, including schema, stylesheet, and Java generation. To continue exploring Relaxer, visit the Relaxer site, where you will (soon) find a tutorial and reference manual. A book on Relaxer is also available in Japanese. In addition, you will find many code examples in the sample subdirectory of the Relaxer distribution.