MSXML3.0 provides support for XSL transformations without
any additional software. The parser features a transformNode
method that usually accepts a
stylesheet as a parameter (in DOM form) and returns the result of
processing the current document with the supplied stylesheet. For
example:
objXML = win32com.client.Dispatch("MSXML2.DOMDocument.3.0") objXSL = win32com.client.Dispatch("MSXML2.DOMDocument.3.0") strTransformedXML = objXML.transformNode(objXSL)
In the simplest case, as shown in the preceding code, two DOM
instances are created. One DOM instance is needed to hold the source
document, the other contains the stylesheet. To get the result of the
transformation, call transformNode
on
the source DOM, providing the stylesheet DOM as a parameter.
Example E-4 shows 1999temps.xml, a document containing monthly average temperatures for Woodinville, Washington. This is a simple XML document with a flat structure.
<CalendarYear value="1999" data="Average Monthly Highs"> <Month name="January">45.0</Month> <Month name="February">49.5</Month> <Month name="March">52.7</Month> <Month name="April">57.2</Month> <Month name="May">63.9</Month> <Month name="June">69.9</Month> <Month name="July">75.2</Month> <Month name="August">75.2</Month> <Month name="September">69.3</Month> <Month name="October">59.7</Month> <Month name="November">50.5</Month> <Month name="December">45.1</Month> </CalendarYear>
There are attributes indicating the year on record, and the type of data displayed. The Month elements have a name attribute, while the actual temperature is character data.
With your stylesheet, attempt to find the average yearly
temperature, based on the average monthly temperatures. Using a
combination of XPath’s sum
function
and div
operator yields the results
needed. Example E-5 shows
the stylesheet temps.xsl.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:variable name="average" select="sum(//CalendarYear/Month/text( )) div 12"/> <xsl:template match="/"> <html> <body> <p> <font face="tahoma,arial,helvetica" size="2"> <xsl:value-of select="/CalendarYear/@data"/> for <xsl:value-of select="/CalendarYear/@value"/>: </font> </p> <table border="1" bordercolor="#000000" cellpadding="5" cellspacing="0" width="350"> <xsl:apply-templates/> <tr> <td colspan="2" bgcolor="#88BBEE" width="350" align="right"> <p> <font face="tahoma,arial,helvetica" size="2"> <b>Average: <xsl:value-of select="format-number($average, '0.00')"/> </b> </font> </p> </td> </tr> </table> </body> </html> </xsl:template> <xsl:template match="Month"> <tr> <td bgcolor="#CCCCCC" width="325" align="left"> <p> <font face="tahoma,arial,helvetica" size="2"> Month: <b><xsl:value-of select="@name"/></b> </font> </p> </td> <td bgcolor="#CCCCCC" width="25" align="left"> <p> <font face="tahoma,arial,helvetica" size="2"> <b><xsl:value-of select="./text( )"/></b> </font> </p> </td> </tr> </xsl:template> </xsl:stylesheet>
The stylesheet performs its computational work in two parts.
First, a variable is created that holds the average of the
temperatures by using the sum
function to add them together, then using the div
operator to divide between the total
number of months in a year:
<xsl:variable name="average" select="sum(//CalendarYear/Month/text( )) div 12"/>
Finally, some formatting is performed within a template by
calling format-number
, using
$average
as a parameter:
<xsl:value-of select="format-number($average, '0.00')"/>
This ensures that the temperature figure contains at least two floating-point digits.
To apply the transformation from Python, create two
instances of MSXML3.0, and supply one with the source XML and one with
the stylesheet. Then use transformNode
to complete the transformation
process. Example E-6 shows
transform.py, which completes the
task.
""" transform.py - using MSXML3.0 XSLT support from Python """ import win32com.client strSourceDoc = "1999temps.xml" strStyleDoc = "temps.xsl" objXML = win32com.client.Dispatch("MSXML2.DOMDocument.3.0") objXSL = win32com.client.Dispatch("MSXML2.DOMDocument.3.0") if (not objXML.load(strSourceDoc)): print "Error loading", strSourceDoc if (not objXSL.load(strStyleDoc)): print "Error loading", strStyleDoc strTransformedXML = objXML.transformNode(objXSL) print strTransformedXML
You can run the process from a command prompt, and write the output to an HTML file if you want to view the results in a browser.
>c:python21python transform.py > temps.html
Figure E-1 shows the transformed XML residing in a browser.