Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Code generation in XSLT 2.0, Part 2: Generate PHP with XSLT 2.0

Provide database access with PHP

Jack Herrington (jherr@pobox.com), Editor-in-Chief, Code Generation Network
An engineer with with more than 20 years of experience, Jack Herrington is currently Editor-in-Chief of the Code Generation Network. He is the author of Code Generation in Action. You can contact him at jack_d_herrington@codegeneration.net.

Summary:  In Part 2 of this two-part series on XSLT, Jack Herrington shows you how to expand the XSLT 2.0 code generator that you built in Part 1 to create the PHP portion of the code that provides the database access for a Web server.

Date:  18 Feb 2005
Level:  Introductory
Also available in:   Japanese

Activity:  10384 views
Comments:  

In the first article of this two-part series on XSLT, I introduced you to some of the new features in XSLT 2.0 and showed you how to generate code from an abstract data model. To illustrate this process, I started a project to build a robust code generator that produces both the SQL for a database server and the PHP that will ultimately provide database access to a Web server. I employed XSL to build the SQL using a multilevel transformation. The first transformation turned the abstract model into a database physical schema model. I then used this schema model to build the SQL code.

The next step in this process is to build the model for the code, then generate PHP from that model. By the end of this project, you'll have an abstract model of your system, SQL code to build the database, and PHP wrappers for each table. However, before digging into PHP generation, I'd like to step back and look a bit more at XSL and the new XSLT 2.0 features that affect XSL template design and use.

Enhancements for XSL templates

Successful code generation requires both an understanding of the target language (in this case, PHP) and the code generation language (in this case, XSLT). In Part 1, I concentrated on the basics of code generation. This article provides more detail on the XSL side of the code-generation equation.

Download the code for this article

The code listings in this article do not include all of the XSLT 2.0 code required to generate the PHP you need for Web server access. For the rest of the code, refer to Resources.

At its core, XSLT is a templating language. It takes XML as input, then uses a set of templates to transform the XML into XML, HTML, or text. In this code-generation example, I use the templates to generate both XML and text. The generator, which is a collection of related templates, uses two modes -- XML mode and Text mode -- to translate the original input XML into code. XML mode is used for the temporary models that sit between the abstract model and the code templates. Text mode is used in the code templates when you generate the PHP and the SQL.

Modes in XSL

Modes are an important concept in XSL. Because you can have multiple XML hierarchies in memory simultaneously, you need a way to apply a specific set of templates to a particular hierarchy or a set of conversions that you can apply to a single XML source. This is where modes come in. This code generator has one set of templates with PHP as the mode and another set with SQL as the mode. With modes, you keep the template logic for the two languages separate.

For this code-generation system, I use the Saxon XSLT engine and a set of custom templates. For convenience, these templates reside in the same directory as the input. The output of the templates goes into directories for the PHP and SQL code. No special extensions to Saxon are required, although if you find the XSL tags or XPath functions provided in the basic installation inadequate, you can use Java™ code to extend the template engine.

The starting point of an XSL template is a template that matches the root node of the input XML. When the XSL engine starts up, it applies the input XML to the library of templates. If a particular template matches the root node (/), it is executed first. Here's the main template tag for the generator:

<xsl:template match="/">

This matching system is important, because XSL works by looking through the list of available templates that apply to the node it's currently processing, then applying the template with the most specific match. Take a look at the code in Listing 1, which is an example from the previous article.


Listing 1. Template with a mode type
<xsl:template match="create" mode="sql">
DROP TABLE IF EXISTS <xsl:value-of select="@name" />;
CREATE <xsl:value-of select="@name" /> (
<xsl:apply-templates mode="sql" select="field" />
PRIMARY KEY ( <xsl:value-of select="@primary-key" /> )
        );
</xsl:template>

This code tells the XSL that this template applies to create tags. So, when the XSL comes across a create tag, it executes this template. In addition, note that this template specifies a mode. You specify the mode in the xsl:apply-templates tag, as Listing 2 shows.


Listing 2. Tag for applying templates
<xsl:apply-templates mode="sql" select="$sql-model/sql" />

The xsl:apply-templates tag tells XSL to apply the available templates to the section of the XML model that the select tag specifies. Additionally, you specify that the mode is sql, so the XSL finds only those templates that work in sql mode. This is a handy namespace mechanism for templates.

But what happens with the output of these templates? That's where the new xsl:result-document tag comes in (see Listing 3).


Listing 3. Code to invoke the SQL templates
        <xsl:result-document href="db/gen-tables.sql" format="sql" >
            <xsl:apply-templates mode="sql" select="$sql-model/sql" />
        </xsl:result-document>

Typically, output from the template goes to whatever output file you specify when you run the XSL translator -- usually a file or a standard out (that is, the console or the default output file). Using the xsl:result-document tag in the XSL template, you can specify a new file to hold the output. In this case, I'm sending the output to the file db/gen-tables.sql. This new XSL feature is critical for code generation because you often need to create multiple output files from a single piece of XML.

Another important tag that has changed in XSLT 2.0 is xsl:variable. Like the xsl:result-document tag, xsl:variable diverts the output of the tags nested inside it. Instead of going to a file, these nested tags go to a temporary variable in memory. In this case, I take the output of the template that I call and put it in a variable called sql-model (see Listing 4). This variable is actually an XML tree to which I can then apply other templates.


Listing 4. Code to create a temporary tree variable
        <xsl:variable name="sql-model">
            <xsl:call-template name="gen-sql-model">
                <xsl:with-param name="model" select="."/>
            </xsl:call-template>
        </xsl:variable>

This ability to have multiple XML trees in memory simultaneously opens new vistas for XSL. With it, you can have much larger template systems while you reduce the complexity of each template.

Another important enhancement to XSLT is the inclusion of the xsl:function tag, which creates new XPath functions (see Listing 5).


Listing 5. Code to create an XPath function
<xsl:function name="gen:model-type-to-sql">

I used this tag to create a new function that maps types specified in the abstract model (the original input file) into SQL native types for the output file (Listing 6). I could have done this with a template, but with this new syntax I can declare a function that can be used in XPath, which is much more convenient.


Listing 6. Code to invoke an XPath function
<field name="{lower-case(@name)}" type="{gen:model-type-to-sql(@type)}"/>

As you can see, the code in Listing 6 is much simpler than the xsl:call-template functionality that you had to use in XSLT 1.0. See Resources for more information about XSLT and the new features in XSLT 2.0.

Now I'll show you how to apply the new XSLT features that I just illustrated and build PHP from a model. I started with an abstract model, which is just the XML input file. In the first article, I used templates to create an SQL model from which I built the SQL code. Here, I use a similar technique to build PHP from a PHP model.


Generate PHP from the abstract data model

To generate the PHP, first build a model of the code you want to generate. Then, apply code templates to that new model. For the Author table I created last time, this new database access model looks like the code in Listing 7.


Listing 7. Language model corresponding to the abstract input
<?xml version="1.0" encoding="UTF-8"?>
<modules xmlns:gen="http://www.codegeneration.net/">
   <module name="Author">
      <class name="Author">
         <constructor name="Author"/>
         <method name="selectAll">
            <parameters/>
            <implementation>
               <selectAll table="author">
                  <field name="author_id"/>
                  <field name="first"/>
                  <field name="last"/>
               </selectAll>
            </implementation>
         </method>
         <method name="selectOne">
            <parameters>
               <variable name="author_id"/>
            </parameters>
            <implementation>
               <selectOne table="author" by="author_id">
                  <field name="author_id"/>
                  <field name="first"/>
                  <field name="last"/>
               </selectOne>
            </implementation>
         </method>
         <method type="insert" name="insert">
            <parameters>
               <variable name="first"/>
               <variable name="last"/>
            </parameters>
            <implementation>
               <insert table="author">
                  <field name="first"/>
                  <field name="last"/>
               </insert>
            </implementation>
         </method>
      </class>
   </module>

The structure of the XML matches exactly with the structure of the code that you expect to see on the other end. However, note that nothing about this code is PHP-specific. You could use this model to generate any latently typed language. For example, you could generate Java code just by adding some type information to the model. To see why the construction of the XML is so important in this scheme, simply look at the resulting PHP in Listing 8.


Listing 8. The output Author table
<script language="php">

class Author extends DatabaseTable {

    function Author ( ) {  }

    function selectAll (  )
    { 
    $dbh = getDbh();
    return $dbh->doQuery(
    "SELECT author_id, first, last FROM author"
    );
 }

    function selectOne ( $author_id )
    { 
    $dbh = getDbh();
    return $dbh->doQuery(
    "SELECT author_id, first, last FROM author WHERE author = ?",
    $author_id );
 }

    function insert ( $first, $last ) 
    { 
    $dbh = getDbh();
    $dbh->doCommand( "INSERT INTO author ( first, last ) VALUES ( ?, ? )",
    $first, $last );
 }
}

</script>

If you look back at the XML in Listing 7, you can see how each tag in the XML represents a structure in the PHP. For example, you can see the method tag of type insert in the model and the resulting input function in the output class.

I'll show you a few of these code templates to illustrate how they work.

Code template examples

The first template example is the Module template, which you use to build a new .php file. Listing 9 shows this template.


Listing 9. The Module template
    <!-- PHP: Module tag handler -->
<xsl:template match="module" mode="php">
<xsl:result-document href="php/{@name}.php">
<script language="php">
<xsl:apply-templates select="*" mode="php" />
</script>
</xsl:result-document>
</xsl:template>

Notice how the template uses the xsl:result-document tag to build a new file for each module. It then uses the xsl:apply-templates tag to fill in the file with the code.

To build the implementation portion of the insert method, I use the template shown in Listing 10.


Listing 10. The SQL Insert template
    <!-- PHP: SQL Insert tag handler -->
<xsl:template match="insert" mode="php">
<xsl:call-template name="php-db-function">
<xsl:with-param name="content">
<xsl:call-template name="php-sql-command">
<xsl:with-param name="command" select="gen:build-insert(.)" />
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:template>

The other important call is to the build-insert function. The code in Listing 11 shows this function.


Listing 11. The insert command builder
    <!-- Builds an SQL insert command -->
<xsl:function name="gen:build-insert">
<xsl:param name="query" />
<xsl:variable name="out">
<sql>
    <query>
INSERT INTO <xsl:value-of select="$query/@table" />
(
<xsl:for-each select="$query/field"><xsl:if test="position() > 1">,
    </xsl:if><xsl:value-of select="@name" /></xsl:for-each>
) VALUES (
<xsl:for-each select="$query/field"><xsl:if test="position() > 1">, 
    </xsl:if>?</xsl:for-each>
)
    </query>
    <inputs>
        <xsl:for-each select="$query/field">
    <input name="{@name}" />
    </xsl:for-each>
    </inputs>
</sql>
</xsl:variable>
    <xsl:sequence select="$out" />
</xsl:function>

This function returns a full data structure with both the query and the required inputs. This function was possible in XSLT 1.0, but the custom functions in XSLT 2.0 make the process much easier.

The php-sql-command template uses the SQL data structure to build the PHP -- see Listing 12.


Listing 12. Template for SQL commands
    <!-- SQL command template -->
<xsl:template name="php-sql-command">
<xsl:param name="command" />$dbh->doCommand( 
    "<xsl:value-of select="normalize-space( $command/sql/query )" />"
    <xsl:for-each select="$command/sql/inputs/input">, 
                  $<xsl:value-of select="@name" />
    </xsl:for-each> );
</xsl:template>

The $command/sql/query and $command/sql/inputs/input tags are where the SQL query and inputs are turned into code.


Conclusions

As small as it seems, this is all there is to building potentially hundreds of database access classes for PHP. Of course, what I provide in these two articles is just an example: To use the generator, you have to implement the DatabaseTable base class, then add methods for deleting and updating. I left out those methods to keep the code in the article shorter.

You can separate the information in these articles into two main categories: technical and theoretical.

On the technical side, you've learned a couple of things. First, XSLT does a great job with code generation, and XSLT 2.0 makes that process even easier. Second, using multiple models and levels of translation in a generator makes your application easier to understand, develop, and maintain.

On the theoretical side, you can see that code-generation techniques are capable of quickly building a large volume of repetitive code accurately. This has several advantages, not the least of which is that you can concentrate on writing code rather than attending to the repetitive work. Also, you can quickly change your code base to accommodate changing requirements. And you can change technologies reasonably quickly as needed because the important design information is in an abstract model, not embedded in the code.

For several years, I have written, lectured, and evangelized about code-generation techniques. In that time, I talked with many engineers who had positive experiences generating code for their projects. One went so far as to tell me, "If you have a Ford vehicle manufactured in the U.S., the parts for that vehicle were delivered to Ford based on a product built through code generation." With a thoughtful, pragmatic approach to code generation, you can dramatically cut your schedule time, increase the quality of your code, and return to writing the type of interesting code that you got into this game to build.



Download

DescriptionNameSizeDownload method
XSLT templates and resulting output filesx-xslphp2-PHPgeneration.zip8 KB HTTP

Information about download methods


Resources

About the author

An engineer with with more than 20 years of experience, Jack Herrington is currently Editor-in-Chief of the Code Generation Network. He is the author of Code Generation in Action. You can contact him at jack_d_herrington@codegeneration.net.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML, Open source
ArticleID=48573
ArticleTitle=Code generation in XSLT 2.0, Part 2: Generate PHP with XSLT 2.0
publish-date=02182005
author1-email=jherr@pobox.com
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Try IBM PureSystems. No charge.

Special offers