[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: translate to XML using XSL into an HTML table

Subject: Re: translate to XML using XSL into an HTML table
From: Abel Braaksma <abel.online@xxxxxxxxx>
Date: Fri, 03 Aug 2007 23:38:50 +0200
Re:   translate to XML using XSL into an HTML table
Oryann,

You have already been helped very well with the code below, but the discussion stayed all around using the same construct: xsl:for-each. You stated that you are new to XSLT, so I take it that you are not very familiar with it. In a later post you say that you are accustomed to Perl, which is, as many general domain and scripting languages, an imperative language, where you are used to be in charge yourself of telling the compiler what to do and when, and XSLT takes it just the other way around.

Your approach below does exactly that: you layout a table, and you use for-each to tell the compiler (xslt processor) to get a group of elements and to do something with it. This is not wrong on itself, but if your code will grow, you will find yourself having very complex and hard to maintain structures, just like a nested for/next and if/then would give you in an imperative language (unless you choose to use its OO capabilities etc to get your code more readable).

XSLT is a declarative / functional language. You literally *declare* what your output should look like based on a set of rules, and then you let the processor do the brainy stuff for you. What you need to know is that the processor will walk the input tree of XML for you and you declare templates where you say "if the processor encounters node XYZ create a TD tag" and "if the processor encounters node ABC create a TABLE tag". To control this flow, you can select what nodes the processor is allowed to process on a given position.

To illustrate this approach, let's take your example. Instead of writing a for-each loop (it is not hard to imagine how your code will look when you need several tables inside one another, with several for-each loops etc), you can take the following approach, which needs a little shift in thinking (read along with the comment lines):

<xsl:template match="/">
   <!-- here comes your frameword for the html page -->
   <html>
       <head>.....</head>
       .... etc ....
       <body>
            <!-- now we tell the processor what main elements to grab -->
            <!-- these are children of the root -->
            <xsl:apply-templates select="PHONEBOOK" />
       </body>
    </body>
</xsl:template>

<!-- declaring the table, which starts for each PHONEBOOK (only one) -->
<xsl:template match="PHONEBOOK">
<!-- here comes the start of the table, you could put it in the main, but this keeps it cleaner -->
<table border="3">
<!-- table header -->
<tr bgcolor="lightblue">
<th>FirstName</th>
<th>LastName</th>
<th>Phone</th>
</tr>
<!-- here we say to the processor: take these elements that we want a rows -->
<!-- I assume that you have added a <member> around each first/last/phone, though this is not necessary -->
<xsl:apply-template select="MEMBER" />
</table>
</xsl:template>


<!-- declaring the row, which the processor will automatically select for each MEMBER -->
<xsl:template match="MEMBER">
<!-- here goes the row definition
all is a client of MEMBER now -->
<!-- an easy way to create a way so you can point your browser
to each member by its id or name (IE), by using http://yoururl/yourpath#memberID -->
<xsl:variable name="id"><xsl:number /></xsl:variable>
<tr id="member-{$id}">
<xsl:apply-templates select="FIRST | LAST | PHONE" />
</tr>
</xsl:template>


<!-- declare the cells, which is any node that is a child of MEMBER -->
<xsl:template match="MEMBER/*">
    <!-- here we select the value of the current node (.) -->
    <td><xsl:value-of select="." /></td>
</xsl:template>


Now, the above is finished. If you use that, you will get a neatly rendered table. Why is this better than the previous approach? Suppose that you want to but the text of the first name (FIRST) into bold.


If you take your original approach, you would have to add a <xsl:if> statement, which would even more deeply indent the already deeply nested structure. In the new approach (the XSLT'ish approach) all you need to is make a specific exception for the FIRST nodes, which you do by adding an extra declaration, that is all. The processor "knows" that it should take the exception case, instead of the generic case and will automatically choose the correct declaration.

This is what I meant by: let the processor do the thinking for you. This is also the one point that many people find rather daunting when attacking XSLT at first, but once understood it will make you go like lightspeed!

Here's what you do, just add this to the code above, and you are done:

<xsl:template match="FIRST">
    <td><b><xsl:value-of select="."></b><td>
</xsl:template>


These concepts are very well presented in Jeni Tennison's tutorial books. You can also check her website. Another good starting point is the XSLT Cookbook (consider the second edition only) and Dave Pawson's FAQ (search google for XSLT FAQ followed by your query and you get there). If you want to get a bit further on the subject, you should consider buying the authoritative definitive books on XPath 2.0 and XSLT 2.0 by Michael Kay.


Hope it helps! Happy coding!

Cheers,
-- Abel Braaksma



oryann9 wrote:
Hello all ,

This is my 1st post so be kind...
Anywho... here is my xsl code and I need to make a
table for every entry in my XML code, but cannot get
it to work. Please help!
Thank you,
oryan

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<html>
<head>
<title> My Phone Book</title>
</head>
<h2> My Phone Book </h2>
<body bgcolor="YELLOW">
<table border="3">
<tr bgcolor="lightblue">
<th>FirstName</th>
<th>LastName</th>
<th>Phone</th>
</tr>
<xsl:for-each select="//FIRST"> <tr>
<td> <xsl:value-of
select="//FIRST/*"/>


</td>
</tr> </xsl:for-each> </table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>



XML CODE:


<?xml version="1.0"?>
<!DOCTYPE PHONEBOOK>
<PHONEBOOK>
<LISTING>
<FIRST> Derek </FIRST>
<LAST> Smith </LAST>
<PHONE> 614-757-2123 </PHONE>
<FIRST> Steve </FIRST>
<LAST> Gretschmann </LAST> <PHONE> 614-757-2323 </PHONE>
<FIRST> Corey </FIRST>
<LAST> Pohl </LAST>
<PHONE> 614-806-1416 </PHONE>
<FIRST> Tiko </FIRST>
<LAST> Lewis </LAST>
<PHONE> 614-232-3434 </PHONE> <FIRST> Kurt </FIRST>
<LAST> Smith </LAST>
<PHONE> 419-455-9090 </PHONE> </LISTING>


    <LISTING>
       <FIRST>Jane</FIRST>
       <LAST>Smith</LAST>
       <PHONE>1-800-234-5678</PHONE>
       <PHONE>1-555-222-3333</PHONE>
    </LISTING>

</PHONEBOOK>


____________________________________________________________________________________
Looking for a deal? Find great prices on flights and hotels with Yahoo! FareChase.
http://farechase.yahoo.com/

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.