XML Hacks: 100 Industrial-Strength Tips and Tools

   

While XML documents come in all shapes and sizes, a common pattern makes it very easy to present information stored in XML as a table.

XML's structural flexibility is impressive, but many applications are well-served using only a tiny subset of its capabilities, often following a pattern of three levels of nested elements where only the child elements have content. The pattern looks roughly like this:

<table> <row> <cell-1>...value...</cell-1> <cell-2>...value...</cell-2> <cell-3>...value...</cell-3> <cell-4>...value...</cell-4> </row> <row> <cell-1>...value...</cell-1> <cell-2>...value...</cell-2> <cell-3>...value...</cell-3> <cell-4>...value...</cell-4> </row> .... </table>

where table is any root element, row is any container element, and the cell elements are leaf elements containing data. (The names of the elements and whether or not they use namespaces don't matter, provided that the cell elements stay in the same order throughout.) This pattern is common for XML vocabularies representing database tables or query results, as well as those representing data that was originally comma- or tab-separated. Looking beyond the browser for a moment, Excel 2003 [Hack #15] can work with this data easily, and Access 2003 [Hack #16] can import and export it with minimal effort.

Take, for example, the document contracts.xml, which represents two rows of such a table (shown in Example 3-7).

Example 3-7. contracts.xml

<?xml-stylesheet type="text/css" href="table.css"?> <contracts> <contract> <recipient>Josiah Smith</recipient> <signing_date>1999-06-03</signing_date> <signing_time>09:03:22</signing_time> <birthyear>1962</birthyear> <birthday>--06-21</birthday> <male>true</male> <payment_amount>0004002.00200</payment_amount> <years_to_pay>26</years_to_pay> </contract> <contract> <recipient>Jane Zang</recipient> <signing_date>1999-04-03</signing_date> <signing_time>11:04:28</signing_time> <birthyear>1968</birthyear> <birthday>--04-23</birthday> <male>false</male> <payment_amount>000401.0200</payment_amount> <years_to_pay>2</years_to_pay> </contract> </contracts>

The PI at the top of it:

<?xml-stylesheet type="text/css" href="table.css"?>

will apply the stylesheet table.css in Example 3-8 to it.

Example 3-8. table.css

:root {display:table;} :root * {display:table-row;} :root * * {display:table-cell; padding:5px; border-style:inset;}

Open it in Mozilla, and you'll see a table like that shown in Figure 3-12 (with a different filename).

Figure 3-12. A table created with CSS, viewed in Mozilla

It also works nicely in Apple's Safari browser, as shown in Figure 3-13 (under a different name).

Figure 3-13. A table created with CSS, viewed in Safari

The results in Internet Explorer 6, as shown in Figure 3-14, are less enticing, as Microsoft has never updated Internet Explorer to support display:table and related table properties (from CSS2, http://www.w3.org/TR/1998/REC-CSS2-19980512) nor the :root selector (from CSS3, see http://www.w3.org/Style/CSS/current-work).

Figure 3-14. An attempt to create a table with CSS, which doesn't work in Internet Explorer

You can, of course, create a similarly generic stylesheet in XSLT (table.xsl shown in Example 3-9), though it's much longer than the CSS equivalent.

Example 3-9. table.xsl

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" /> <xsl:template match="*"> <html> <head><title>Auto-generated table</title></head> <body> <table border="1"> <xsl:for-each select="*"> <tr> <xsl:for-each select="*"> <td> <xsl:value-of select="."/> </td> </xsl:for-each> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet>

This stylesheet generates an HTML table from contracts.xml. Applied with Xalan C++:

xalan -o table.html contracts.xml table.xsl

it produces table.html, shown in Example 3-10.

Example 3-10. table.html

<html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-16"> <title>Auto-generated table</title></head> <body> <table border="1"> <tr> <td>Josiah Smith</td> <td>1999-06-03</td> <td>09:03:22</td> <td>1962</td> <td>--06-21</td> <td>true</td> <td>0004002.00200</td> <td>26</td> </tr> <tr> <td>Jane Zang</td> <td>1999-04-03</td> <td>11:04:28</td> <td>1968</td> <td>--04-23</td> <td>false</td> <td>000401.0200</td> <td>2</td> </tr> </table> </body> </html>

To use the XSLT stylesheet directly rather than the CSS stylesheet to display a table, change the XML stylesheet processing instruction in contracts.xml to look like:

<?xml-stylesheet type="text/xsl" href="table.xsl"?>

Opening the document table.html (or contracts.xml with the processing instruction change) will produce the result shown in Figure 3-15 in Mozilla, and Figure 3-16 in Internet Explorer 6.

Figure 3-15. A table created with generic XSLT, viewed in Mozilla

Figure 3-16. A table created with generic XSLT, viewed in Internet Explorer 6

Unfortunately, Safari (as of Version 1.2) doesn't support client-side XSLT, so it produces the unhappy result shown in Figure 3-17 (under a different name, again). The Opera browser (as of Version 7) also doesn't support XSLT.

Figure 3-17. An attempt to create a table with generic XSLT, which doesn't work in Safari

Because of cross-browser considerations, you'll probably want to use these hacks only when you control which browser will be used, but they're still very handy tools for exploring data quickly.

Simon St.Laurent

Категории

© amp.flylib.com,