Chapter 11: Using XPath and XSLT to Generate Programs

Summary

XPath is an expression language for selecting nodes in an XML tree. XSLT is an XML-based document that specifies how to transform XML documents into other XML documents, HTML documents, or text documents. XSLT, which uses XPath, is used in this chapter to create a Play domain program generator. This shows how Java program generators can be created solely from XML tools without using the Java language.



Chapter 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13

Example 11-1: Excerpt from play1.xml
Example 11-17: viewplay.xsl
Example 11-18: Play2.xsl
Example 11-9: The Generated Program

Example 11-1: Excerpt from play1.xml

<?xml version="1.0"?>
<play name="JackAndJill" width="300" height="120" start="bottom">
  <title>Jack and Jill</title>

  <prop name="up">
    <trait>Go up the hill</trait>
    <script goto="top"/>
  </prop>
  <prop name="fetch"/>
  <prop name="fall"/>
  <prop name="tumble"/>
  <scene name="bottom"/>
  <scene name="top">
    <addprop name="fetch">
	<trait>Fetch another pail</trait>
    </addprop>
    <addprop name="fall"/>
    <addprop name="tumble"/>
  </scene>

</play

Example 11-17: viewplay.xsl

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
		version="1.0">
                
<xsl:template match="/">
<html><head><title><xsl:value-of select="//play/title"/></title></head>
<body>
<h3>Play Specification</h3>
<br/>Title: <xsl:value-of select="//play/title"/>
<br/>Width: <xsl:value-of select="//play/@width"/>
<br/>Height: <xsl:value-of select="//play/@height"/>
<br/>Start Scene: <code><xsl:value-of select="//play/@start"/></code>

<table border="1" cellpadding="5">
<tr><th>Buttons</th><th>Scenes</th></tr>
<tr><td>
<xsl:for-each select="//play/prop">
<br/>Button: <code><xsl:value-of select="@name"/></code>
<xsl:for-each select="trait">
<br/>  <xsl:value-of select="@name"/>: "<code><xsl:value-of select="."/></code>"
</xsl:for-each>
<xsl:for-each select="script">
<br/>  Script <xsl:value-of select="@name"/>:
<ol>
  <xsl:for-each select="trait">
	<li/>Change <xsl:value-of select="@name"/>
  <xsl:if test="@prop"> for Button <code><xsl:value-of select="@prop"/></code></xsl:if>
	to "<code><xsl:value-of select="."/></code>"
  </xsl:for-each>
 <xsl:if test="@goto">
	<li/>Change to Scene <code><xsl:value-of select="@goto"/></code>;
 </xsl:if>
</ol>
<hr/>
</xsl:for-each>

</xsl:for-each>
</td><td valign="top">
<xsl:for-each select="//play/scene">
<br/>Scene: <xsl:value-of select="@name"/>
<br/>Background Color: <code><xsl:value-of select="@color"/></code>
<br/>
<ol>
  <xsl:for-each select="addprop">
	<li>Button <code><xsl:value-of select="@name"/></code>
	</li>
  </xsl:for-each>
</ol>
<hr/>
</xsl:for-each>
</td></tr></table>
</body>
</html>
</xsl:template>

</xsl:stylesheet>

Example 11-18: Play2.xsl

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
		version="1.0"
                xmlns:xt="http://www.jclark.com/xt"
                extension-element-prefixes="xt">
<xsl:output method="text"/>
<xsl:template match="/">
import java.awt.*;
import java.awt.event.*;

class <xsl:value-of select="//play/@name"/>Play2 extends Frame {
    /* The Props for <xsl:value-of select="//play/@name"/> ************/
<xsl:for-each select="//play/prop">
    Button <xsl:value-of select="@name"/>Prop 
              = new Button("<xsl:value-of select="trait"/>");<xsl:text/>
</xsl:for-each>

    /* The Events in the <xsl:value-of select="//play/@name"/> ********/

    class PropEvent implements ActionListener {
        public void actionPerformed(ActionEvent evt) {
            Object prop = evt.getSource();
<xsl:for-each select="//play/prop">
<xsl:text>            </xsl:text>
            <xsl:if test="position()!=1">
	      } else </xsl:if>if (prop.equals(<xsl:value-of
                                    select="@name"/>Prop)) {<xsl:text/>
			<xsl:apply-templates select="script/trait"/>
			<xsl:if test="./script/@goto">
                enterNewScene("<xsl:value-of
                                  select="script/@goto"/>");<xsl:text/>
			</xsl:if>
</xsl:for-each>
            } else {
                System.out.println("Invalid prop");
            }
        }
    }

    /* Creating and starting up the <xsl:value-of
                                          select="//play/@name"/> ****/

    String currentScene;

    public <xsl:value-of select="//play/@name"/>Play2() {
        super("<xsl:if test="count(//play/title)=0">No Title xx</xsl:if>
                              <xsl:value-of select="//play/title"/>");
        setSize(<xsl:value-of select="//play/@width"/>, <xsl:text/>
                              <xsl:value-of select="//play/@height"/>);
        setLayout(new FlowLayout());

        // initialize props
        PropEvent a = new PropEvent();
<xsl:for-each select="//play/prop">
<xsl:text>        </xsl:text>
        <xsl:value-of select="@name"/>Prop.addActionListener(a);
</xsl:for-each>
        // start scene
        enterNewScene("<xsl:value-of select="//play/@start"/>");
    }

    public void enterNewScene(String scene) {
        removeAll();  // remove previous scene
        currentScene = scene;
<xsl:for-each select="//play/scene">
<xsl:text>        </xsl:text>
            <xsl:if test="position()!=1">
	  } else </xsl:if>if (scene.equals("<xsl:value-of
                                   select="@name"/>")) {<xsl:text/>
  <xsl:for-each select="addprop">
                add(<xsl:value-of select="@name"/>Prop);<xsl:text/>
</xsl:for-each>
	          setBackground(Color.decode("<xsl:value-of
                                   select="@color"/>"));<xsl:text/>
</xsl:for-each>
        } else {
            System.out.println("Invalid scene: "+scene);
        }
        show();
    }

    public static void main(String[] args) {
        new <xsl:value-of select="//play/@name"/>Play2();
    }
}

</xsl:template>

<xsl:template match="trait">
<xsl:text>
                </xsl:text>
 <xsl:choose>
  <xsl:when test="@prop"><xsl:value-of select="@prop"/></xsl:when>
  <xsl:otherwise><xsl:value-of
	select="ancestor::addprop/@name | ancestor::prop/@name"/>
  </xsl:otherwise>
  </xsl:choose>Prop.setLabel("<xsl:value-of select="."/>");<xsl:text/>
</xsl:template>

</xsl:stylesheet>

Example 11-9: The Generated Program

import java.awt.*;
import java.awt.event.*;

class JackAndJillPlay2 extends Frame {
    /* The Props for JackAndJill ************/

    Button upProp 
		= new Button("Go up the hill");
    Button fetchProp 
		= new Button("Fetch a pail of water");
    Button fallProp 
		= new Button("Fall down, break crown");
    Button tumbleProp 
		= new Button("Tumble down");

    /* The Events in the JackAndJill ********/

    class PropEvent implements ActionListener {
        public void actionPerformed(ActionEvent evt) {
            Object prop = evt.getSource();
            if (prop.equals(upProp)) {
                fetchProp.setLabel("Fetch a pail of water");
                enterNewScene("top");            
	      } else if (prop.equals(fetchProp)) {
                fetchProp.setLabel("Fetch another pail");            
	      } else if (prop.equals(fallProp)) {
                fallProp.setLabel("Break crown");
                tumbleProp.setLabel("Tumble after");
                enterNewScene("bottom");            
	      } else if (prop.equals(tumbleProp)) {
                enterNewScene("bottom");
            } else {
                System.out.println("Invalid prop");
            }
        }
    }

    /* Creating and starting up the JackAndJill ****/

    String currentScene;

    public JackAndJillPlay2() {
        super("Jack and Jill");
        setSize(200, 120);
        setLayout(new FlowLayout());

        // initialize props
        PropEvent a = new PropEvent();
        upProp.addActionListener(a);
        fetchProp.addActionListener(a);
        fallProp.addActionListener(a);
        tumbleProp.addActionListener(a);

        // start scene
        enterNewScene("bottom");
    }

    public void enterNewScene(String scene) {
        removeAll();  // remove previous scene
        currentScene = scene;
        if (scene.equals("bottom")) {
                add(upProp);
                add(fallProp);
	          setBackground(Color.decode("#8888aa"));        
	  } else if (scene.equals("top")) {
                add(fetchProp);
                add(fallProp);
                add(tumbleProp);
	          setBackground(Color.decode("#dddddd"));
        } else {
            System.out.println("Invalid scene: "+scene);
        }
        show();
    }

    public static void main(String[] args) {
        new JackAndJillPlay2();
    }
}