This post contains attachments v20010410230220.zip 
Summary
A common question is 'how do I pass a value into a XSLT document'. In this example I will show you how we do it on TopXML, explaining the different ways to pass values into the stylesheet.
The easiest way to transform an XSLT file with an XML file is to use the DOM object's transformnode function:
<% set xslDoc = server.CreateObject(Msxml2.FreeThreadedDOMDocument.3.0) xsldoc.async = false xslDoc.load server.MapPath(members.xml) set xslDoc = server.CreateObject(Msxml2.FreeThreadedDOMDocument.3.0) xsldoc.async = false xslDoc.load server.MapPath(members.xsl) Response.Write xmldoc.transformnode(xsldoc) %>
Please note that we always use the FreeThreadedDOM when working with ASP so that the object is stateless and free-threaded, therefore we can store the object as an application variable so that we can share the object.
From the July MSXML parser (version 2.6) the <xsl:param> element in XSLT was implemented. The <xsl:param> element enables one to pass a value into the stylesheet.
In our example we will be using the following members XML:
<members> <member registered=20010125 id=i1001> <email>trace_wilson@yahoo.com</email> <details f_name=Trace C l_name=Wilson country=AU gender=F dob=19700418/> </member> <member registered=20010126 id=i1002> <email>jbarnes@hotmail.com</email> <details f_name=Jenny l_name=Barnes country=US gender=F dob=19720720/> </member> <member registered=20010202 id=i1003> <email>davidk@yahoo.com</email> <details f_name=David l_name=Knight country=US gender=M dob=19650701/> </member> <member registered=20010202 id=i1004> <email>mike.todd@wakeup.com</email> <details f_name=Mike l_name=Todd country=AU gender=M dob=19701218/> </member> </members>
In this snippet I'll be demonstrating how to pass in 1. a value: so that we can do a search on the value 2. a node-set: where we will iterate through the node-set 3. an XML document: a replacement for using the XSLT document() functionScenario 1: Passing in a value to the XSLT stylesheet ========================================
In the following XSLT example we want to find Mike Todd's details and pass his id into the stylesheet, to display his details:
<?xml version=1.0 ?> <xsl:stylesheet version=1.0 xmlns:xsl=http://www.w3.org/1999/XSL/Transform>
<xsl:output method=html indent=no /> <xsl:param name=id />
<xsl:template match=members> <xsl:apply-templates select=member[@id=$id] /> </xsl:template> <xsl:template match=member> <h1>Member: <xsl:value-of select=concat(details/@f_name, ' ', details/@l_name) /></h1> <p>Email: <a href=mailto:{email}><xsl:value-of select=email /></a><br /> Country: <xsl:value-of select=details/@country /> </p> </xsl:template> </xsl:stylesheet>
(members.xsl)
From our ASP we want to pass the param called 'id' into the stylesheet. In the <xsl:apply-templates > we are only wanting to process Mike Todd's details (select=member[@id=$id]).
The ASP for doing this is:
<% dim xslDoc, xmlDoc dim id set xmlDoc=server.CreateObject(Msxml2.FreeThreadedDOMDocument.3.0) set xslDoc=server.CreateObject(Msxml2.FreeThreadedDOMDocument.3.0) xmldoc.async = false xslDoc.async = false xmlDoc.load server.mapPath(members.xml) xslDoc.load server.mapPath(members.xsl) Set template = Server.CreateObject(MSXML2.XSLTemplate.3.0) Set template.stylesheet = xslDoc Set proc = template.createProcessor proc.input = xmlDoc proc.addParameter id, i1004 proc.transform Response.Write proc.output %>
The Template object's main functions is a way to allow us to cache a compiled XSLT stylesheet in an application variable. To do the transformation of the XML/XSLT we need to create an XSLProcessor, using the createProcessor function of the XSLTemplate object. The XSLProcessor also allows us to pass parameters into an XSLT document.
In the above ASP code using the XSLProcessor object we pass in a value, but what happens if we want to pass the node of Mike Todd's details instead of doing the search for his details in the stylesheet? Scenario 2: Passing in a node-set from the DOM into the XSLT stylesheet =======================================================
In this example we want to pass in a 'member' node-set to our XSLT from our ASP where the members date of birth is before 1970. We need to use the selectNodes method of the DOM to return a node-set, which we pass to the stylesheet.
<% dim xslDoc, xmlDoc dim id set xmlDoc=server.CreateObject(Msxml2.FreeThreadedDOMDocument.3.0) set xslDoc=server.CreateObject(Msxml2.FreeThreadedDOMDocument.3.0) xmldoc.async = false xslDoc.async = false xmlDoc.load server.mapPath(members.xml) xslDoc.load server.mapPath(member-node.xsl) Set template = Server.CreateObject(MSXML2.XSLTemplate.3.0) Set template.stylesheet = xslDoc Set proc = template.createProcessor proc.input = xmlDoc set node = xmlDoc.documentElement.selectNodes(member[details/@dob < '19710000']) proc.addParameter member, node proc.transform Response.Write proc.output %> (member-node.asp)
In the stylesheet we are iterating through the members that were found in our selectNodes DOM method.
<?xml version=1.0 ?> <xsl:stylesheet version=1.0 xmlns:xsl=http://www.w3.org/1999/XSL/Transform>
<xsl:output method=html indent=no /> <xsl:param name=member />
<xsl:template match=members> <xsl:for-each select=$member> <h1>Member: <xsl:value-of select=concat(details/@f_name, ' ', details/@l_name) /></h1> <p>Email: <a href=mailto:{email}><xsl:value-of select=email /></a><br /> Country: <xsl:value-of select=details/@country /> </p> </xsl:for-each> </xsl:template> </xsl:stylesheet>
(member-node.xsl) Scenario 3: Passing in an XML Document, replacement for the XSLT document() function ==================================================================
On VBXML.COM we store our XML documents as application variables, so that we take advantage of cached data. This is instead of using the XSLT document() function, which needs to load the XML document each time.
Passing in the XML document is the same as passing a value into the XSLT stylesheet and it works the same as the document() function, in that you need to work with the document from the root of the document.
From our first example we want to pass in a reference data XML file that has all the countries so that we can display the members full country name. I would normally use an application variable, but for the sake of this snippet, I'm loading the reference data.
Our refdata.xml looks as follows:
<countries> <country code=AF>Afghanistan</country> <country code=AL>Albania</country> <country code=DZ>Algeria</country> ....
As you can see in the ASP below, we pass in the whole XML document object. <% dim xslDoc, xmlDoc dim id set xmlDoc=server.CreateObject(Msxml2.FreeThreadedDOMDocument.3.0) set xslDoc=server.CreateObject(Msxml2.FreeThreadedDOMDocument.3.0) xmldoc.async = false xslDoc.async = false xmlDoc.load server.mapPath(members.xml) xslDoc.load server.mapPath(member-doco.xsl) 'load the reference data set xmlRefdata=server.CreateObject(Msxml2.FreeThreadedDOMDocument.3.0) xmlrefdata.async = false xmlRefdata.load server.MapPath(refdata.xml) Set template = Server.CreateObject(MSXML2.XSLTemplate.3.0) Set template.stylesheet = xslDoc Set proc = template.createProcessor proc.input = xmlDoc proc.addParameter id, i1004 proc.addParameter doco-refdata, xmlrefdata proc.transform Response.Write proc.output %>
(member-doco.asp)
<?xml version=1.0 ?> <xsl:stylesheet version=1.0 xmlns:xsl=http://www.w3.org/1999/XSL/Transform>
<xsl:output method=html indent=no /> <xsl:param name=id /> <xsl:param name=doco-refdata />
<xsl:template match=members> <xsl:apply-templates select=member[@id=$id] /> </xsl:template> <xsl:template match=member> <h1>Member: <xsl:value-of select=concat(details/@f_name, ' ', details/@l_name) /></h1> <p>Email: <a href=mailto:{email}><xsl:value-of select=email /></a><br /> <xsl:variable name=country-code select=details/@country /> Country: <xsl:value-of select=$doco-refdata/countries/country[@code=$country-code] /> </p> </xsl:template> </xsl:stylesheet>
(member-doco.xsl)
We now reference this document using the following XSLT where we reference the document: <xsl:variable name=country-code select=details/@country /> Country: <xsl:value-of select=$doco-refdata/countries/country[@code=$country-code] />
|