XSL

Contributed by Chris Rathman

Shape class (shape.xsl)

<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

   <!-- shape constructor -->
   <xsl:template name="makeShape">
      <xsl:param name="x" select="0"/>
      <xsl:param name="y" select="0"/>
      <xsl:element name="shape">
         <xsl:element name="x">
            <xsl:value-of select="$x"/>
         </xsl:element>
         <xsl:element name="y">
            <xsl:value-of select="$y"/>
         </xsl:element>
      </xsl:element>
   </xsl:template>

   <!-- getX accessor -->
   <xsl:template mode="getX" match="shape">
      <xsl:copy-of select="x"/>
   </xsl:template>

   <!-- getY accessor -->
   <xsl:template mode="getY" match="shape">
      <xsl:copy-of select="y"/>
   </xsl:template>

</xsl:stylesheet>

Rectangle class (rectangle.xsl)

<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

   <xsl:import href="shape.xsl"/>

   <!-- rectangle constructor -->
   <xsl:template name="makeRectangle">
      <xsl:param name="x" select="0"/>
      <xsl:param name="y" select="0"/>
      <xsl:param name="width" select="0"/>
      <xsl:param name="height" select="0"/>
      <xsl:element name="rectangle">
         <xsl:call-template name="makeShape">
            <xsl:with-param name="x" select="$x"/>
            <xsl:with-param name="y" select="$y"/>
         </xsl:call-template>
         <xsl:element name="width">
            <xsl:value-of select="$width"/>
         </xsl:element>
         <xsl:element name="height">
            <xsl:value-of select="$height"/>
         </xsl:element>
      </xsl:element>
   </xsl:template>

   <!-- getWidth accessor -->
   <xsl:template mode="getWidth" match="rectangle">
      <xsl:copy-of select="width"/>
   </xsl:template>

   <!-- getHeight accessor -->
   <xsl:template mode="getHeight" match="rectangle">
      <xsl:copy-of select="height"/>
   </xsl:template>

   <!-- setWidth accessor (returns new instance) -->
   <xsl:template mode="setWidth" match="rectangle">
      <xsl:param name="width" select="0"/>
      <xsl:variable name="x">
         <xsl:apply-templates mode="getX" select="shape"/>
      </xsl:variable>
      <xsl:variable name="y">
         <xsl:apply-templates mode="getY" select="shape"/>
      </xsl:variable>
      <xsl:variable name="height">
         <xsl:apply-templates mode="getHeight" select="."/>
      </xsl:variable>
      <xsl:call-template name="makeRectangle">
         <xsl:with-param name="x" select="$x"/>
         <xsl:with-param name="y" select="$y"/>
         <xsl:with-param name="width" select="$width"/>
         <xsl:with-param name="height" select="$height"/>
      </xsl:call-template>
   </xsl:template>

   <!-- setHeight accessor (returns new instance) -->
   <xsl:template mode="setHeight" match="rectangle">
      <xsl:param name="height" select="0"/>
      <xsl:variable name="x">
         <xsl:apply-templates mode="getX" select="shape"/>
      </xsl:variable>
      <xsl:variable name="y">
         <xsl:apply-templates mode="getY" select="shape"/>
      </xsl:variable>
      <xsl:variable name="width">
         <xsl:apply-templates mode="getWidth" select="."/>
      </xsl:variable>
      <xsl:call-template name="makeRectangle">
         <xsl:with-param name="x" select="$x"/>
         <xsl:with-param name="y" select="$y"/>
         <xsl:with-param name="width" select="$width"/>
         <xsl:with-param name="height" select="$height"/>
      </xsl:call-template>
   </xsl:template>

   <!-- moveTo method (returns new instance) -->
   <xsl:template mode="moveTo" match="rectangle">
      <xsl:param name="x" select="0"/>
      <xsl:param name="y" select="0"/>
      <xsl:variable name="width">
         <xsl:apply-templates mode="getWidth" select="."/>
      </xsl:variable>
      <xsl:variable name="height">
         <xsl:apply-templates mode="getHeight" select="."/>
      </xsl:variable>
      <xsl:call-template name="makeRectangle">
         <xsl:with-param name="x" select="$x"/>
         <xsl:with-param name="y" select="$y"/>
         <xsl:with-param name="width" select="$width"/>
         <xsl:with-param name="height" select="height"/>
      </xsl:call-template>
   </xsl:template>

   <!-- rMoveTo method (returns new instance) -->
   <xsl:template mode="rMoveTo" match="rectangle">
      <xsl:param name="dx" select="0"/>
      <xsl:param name="dy" select="0"/>
      <xsl:variable name="x">
         <xsl:apply-templates mode="getX" select="shape"/>
      </xsl:variable>
      <xsl:variable name="y">
         <xsl:apply-templates mode="getY" select="shape"/>
      </xsl:variable>
      <xsl:apply-templates mode="moveTo" select=".">
         <xsl:with-param name="x" select="$x + $dx"/>
         <xsl:with-param name="y" select="$y + $dy"/>
      </xsl:apply-templates>
   </xsl:template>

   <!-- draw the rectangle -->
   <xsl:template mode="draw" match="rectangle">
      <xsl:text>Drawing a Rectangle at:(</xsl:text>
      <xsl:apply-templates mode="getX" select="shape"/>
      <xsl:text>,</xsl:text>
      <xsl:apply-templates mode="getY" select="shape"/>
      <xsl:text>), width </xsl:text>
      <xsl:apply-templates mode="getWidth" select="."/>
      <xsl:text>, height </xsl:text>
      <xsl:apply-templates mode="getHeight" select="."/>
      <xsl:text>&#xA;</xsl:text>
   </xsl:template>

</xsl:stylesheet>

Circle class (circle.xsl)

<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

   <xsl:import href="shape.xsl"/>

   <!-- circle constructor -->
   <xsl:template name="makeCircle">
      <xsl:param name="x" select="0"/>
      <xsl:param name="y" select="0"/>
      <xsl:param name="radius" select="0"/>
      <xsl:element name="circle">
         <xsl:call-template name="makeShape">
            <xsl:with-param name="x" select="$x"/>
            <xsl:with-param name="y" select="$y"/>
         </xsl:call-template>
         <xsl:element name="radius">
            <xsl:value-of select="$radius"/>
         </xsl:element>
      </xsl:element>
   </xsl:template>

   <!-- getRadius accessor -->
   <xsl:template mode="getRadius" match="circle">
      <xsl:copy-of select="radius"/>
   </xsl:template>

   <!-- setRadius accessor (returns new instance) -->
   <xsl:template mode="setRadius" match="circle">
      <xsl:param name="radius" select="0"/>
      <xsl:variable name="x">
         <xsl:apply-templates mode="getX" select="shape"/>
      </xsl:variable>
      <xsl:variable name="y">
         <xsl:apply-templates mode="getY" select="shape"/>
      </xsl:variable>
      <xsl:call-template name="makeCircle">
         <xsl:with-param name="x" select="$x"/>
         <xsl:with-param name="y" select="$y"/>
         <xsl:with-param name="radius" select="$radius"/>
      </xsl:call-template>
   </xsl:template>

   <!-- moveTo method (returns new instance) -->
   <xsl:template mode="moveTo" match="circle">
      <xsl:param name="x" select="0"/>
      <xsl:param name="y" select="0"/>
      <xsl:variable name="radius">
         <xsl:apply-templates mode="getRadius" select="."/>
      </xsl:variable>
      <xsl:call-template name="makeCircle">
         <xsl:with-param name="x" select="$x"/>
         <xsl:with-param name="y" select="$y"/>
         <xsl:with-param name="radius" select="$radius"/>
      </xsl:call-template>
   </xsl:template>

   <!-- rMoveTo method (returns new instance) -->
   <xsl:template mode="rMoveTo" match="circle">
      <xsl:param name="dx" select="0"/>
      <xsl:param name="dy" select="0"/>
      <xsl:variable name="x">
         <xsl:apply-templates mode="getX" select="shape"/>
      </xsl:variable>
      <xsl:variable name="y">
         <xsl:apply-templates mode="getY" select="shape"/>
      </xsl:variable>
      <xsl:apply-templates mode="moveTo" select=".">
         <xsl:with-param name="x" select="$x + $dx"/>
         <xsl:with-param name="y" select="$y + $dy"/>
      </xsl:apply-templates>
   </xsl:template>

   <!-- draw the circle -->
   <xsl:template mode="draw" match="circle">
      <xsl:text>Drawing a Circle at:(</xsl:text>
      <xsl:apply-templates mode="getX" select="shape"/>
      <xsl:text>,</xsl:text>
      <xsl:apply-templates mode="getY" select="shape"/>
      <xsl:text>), radius </xsl:text>
      <xsl:apply-templates mode="getRadius" select="."/>
      <xsl:text>&#xA;</xsl:text>
   </xsl:template>

</xsl:stylesheet>

Try shapes stylesheet (polymorph.xsl)

<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
   xmlns:xt="http://icl.com/saxon" extension-element-prefixes="xt">

   <xsl:import href="circle.xsl"/>
   <xsl:import href="rectangle.xsl"/>
   <xsl:output method="text"/>

   <xsl:template match="/">

      <!-- create some shape instances -->
      <xsl:variable name="scribble">
         <xsl:call-template name="makeRectangle">
            <xsl:with-param name="x" select="10"/>
            <xsl:with-param name="y" select="20"/>
            <xsl:with-param name="width" select="5"/>
            <xsl:with-param name="height" select="6"/>
         </xsl:call-template>
         <xsl:call-template name="makeCircle">
            <xsl:with-param name="x" select="15"/>
            <xsl:with-param name="y" select="25"/>
            <xsl:with-param name="radius" select="8"/>
         </xsl:call-template>
      </xsl:variable>

      <!-- iterate through the list and handle shapes polymorphically -->
      <xsl:for-each select="xt:node-set($scribble)/*">
         <xsl:apply-templates mode="draw" select="."/>
      </xsl:for-each>
      <xsl:variable name="moved-scribble">
         <xsl:for-each select="xt:node-set($scribble)/*">
            <xsl:apply-templates mode="rMoveTo" select=".">
               <xsl:with-param name="dx" select="100"/>
               <xsl:with-param name="dy" select="100"/>
            </xsl:apply-templates>
         </xsl:for-each>
      </xsl:variable>
      <xsl:for-each select="xt:node-set($moved-scribble)/*">
         <xsl:apply-templates mode="draw" select="."/>
      </xsl:for-each>

      <!-- call a rectangle specific function -->
      <xsl:variable name="arec">
         <xsl:call-template name="makeRectangle">
            <xsl:with-param name="x" select="0"/>
            <xsl:with-param name="y" select="0"/>
            <xsl:with-param name="width" select="15"/>
            <xsl:with-param name="height" select="15"/>
         </xsl:call-template>
      </xsl:variable>
      <xsl:variable name="brec">
         <xsl:apply-templates mode="setWidth" select="xt:node-set($arec)/*">
            <xsl:with-param name="width" select="30"/>
         </xsl:apply-templates>
      </xsl:variable>
      <xsl:apply-templates mode="draw" select="xt:node-set($brec)"/>


      <!-- get the shape instances from the input xml file -->
      <xsl:text>&#xA;*** Shapes instantiated from XML File ***&#xA;</xsl:text>
      <xsl:variable name="xmlscribble">
         <xsl:copy-of select="polymorph/*"/>
      </xsl:variable>

      <!-- iterate through the list and handle shapes polymorphically -->
      <xsl:for-each select="xt:node-set($xmlscribble)/*">
         <xsl:apply-templates mode="draw" select="."/>
      </xsl:for-each>
      <xsl:variable name="moved-xmlscribble">
         <xsl:for-each select="xt:node-set($xmlscribble)/*">
            <xsl:apply-templates mode="rMoveTo" select=".">
               <xsl:with-param name="dx" select="100"/>
               <xsl:with-param name="dy" select="100"/>
            </xsl:apply-templates>
         </xsl:for-each>
      </xsl:variable>
      <xsl:for-each select="xt:node-set($moved-xmlscribble)/*">
         <xsl:apply-templates mode="draw" select="."/>
      </xsl:for-each>

   </xsl:template>

</xsl:stylesheet>

XML data file (polymorph.xml)

<?xml version="1.0"?>
<!DOCTYPE polymorph SYSTEM "polymorph.dtd">
<?xml-stylesheet type="text/xsl" href="polymorph.xsl"?>
<polymorph>
   <rectangle>
      <shape>
         <x>30</x>
         <y>40</y>
      </shape>
      <width>7</width>
      <height>8</height>
   </rectangle>
   <circle>
      <shape>
         <x>35</x>
         <y>45</y>
      </shape>
      <radius>9</radius>
   </circle>
</polymorph>

XML DTD file (polymorph.dtd)

<!ELEMENT polymorph (rectangle | circle)*>
<!ELEMENT shape (x, y)>
<!ELEMENT x (#PCDATA)>
<!ELEMENT y (#PCDATA)>
<!ELEMENT rectangle (shape, width, height)>
<!ELEMENT width (#PCDATA)>
<!ELEMENT height (#PCDATA)>
<!ELEMENT circle (shape, radius)>
<!ELEMENT radius (#PCDATA)>

Output

Drawing a Rectangle at:(10,20), width 5, height 6
Drawing a Circle at:(15,25), radius 8
Drawing a Rectangle at:(110,120), width 5, height 6
Drawing a Circle at:(115,125), radius 8
Drawing a Rectangle at:(0,0), width 30, height 15

*** Shapes instantiated from XML File ***
Drawing a Rectangle at:(30,40), width 7, height 8
Drawing a Circle at:(35,45), radius 9
Drawing a Rectangle at:(130,140), width 7, height 8
Drawing a Circle at:(135,145), radius 9

Chris Rathman / Chris.Rathman@tx.rr.com