Recipe15.12.Extending XSLT Transformations


Recipe 15.12. Extending XSLT Transformations

Problem

You want to perform operations that are outside the scope of XSLT to include data in the transformed result.

Solution

Add an extension object to the transformation that can perform the operations necessary based on the node it is passed. This can be accomplished by using the XsltArgumentList.AddExtensionObject method. This object you've created (XslExtensionObject) can then be accessed in the XSLT and a method called on it to return the data you want included in the final transformed result:

 string xmlFile = @"..\..\publications.xml"; string xslt = @"..\..\publications.xsl"; //Create the XslTransform and load the stylesheet. // This is not XslCompiledTransform because it gives a different empty node. //Create the XslCompiledTransform and load the stylesheet. XslCompiledTransform transform = new XslCompiledTransform(); transform.Load(xslt); // Load the XML. XPathDocument xPathDoc = new XPathDocument(xmlFile); // Make up the args for the stylesheet with the extension object. XsltArgumentList xslArg = new XsltArgumentList(); // Create our custom extension object. XSLExtensionObject xslExt = new XSLExtensionObject(); xslArg.AddExtensionObject("urn:xslext", xslExt); // Send output to the console and do the transformation. using (XmlWriter writer = XmlWriter.Create(Console.Out)) {     transform.Transform(xPathDoc, xslArg, writer); } 

Note that when the extension object is added to the XsltArgumentList, it supplies a namespace of urn:xslext. This namespace is used in the XSLT stylesheet to reference the object. The XSLExtensionObject is defined here:

 // Our extension object to help with functionality public class XslExtensionObject {     public XPathNodeIterator GetErrata(XPathNodeIterator nodeChapter)     {         try         {             // In here we could go do other lookup calls              // (XML, database, web service) to get information to             // add back in to the transformation result.              string errata =                  string.Format("<Errata>{0} has {1} errata</Errata>",                    nodeChapter.Current.Value, nodeChapter.Current.Value.Length);              XmlDocument xDoc = new XmlDocument();              xDoc.LoadXml(errata);              XPathNavigator xPathNav = xDoc.CreateNavigator();              xPathNav.MoveToChild(XPathNodeType.Element);              XPathNodeIterator iter = xPathNav.Select(".");              return iter;         }         catch (Exception e)         {             // Eat the exception, as we were unable to use the extension.              // So just return the original iterator.              return nodeChapter;         }     } } 

The GetErrata method is called during the execution of the XSLT stylesheet to provide data in XPathNodeIterator format to the transformation. The xmlns:xslext namespace is declared as urn:xslext, which matches the namespace value you passed as an argument to the transformation. In the processing of the Book template for each Chapter, an xsl:value-of is called with the select criteria containing a call to the xslext:GetErrata method. The stylesheet makes the call as shown here:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"      xmlns:xslext="urn:xslext">      <xsl:template match="/">         <xsl:element name="PublishedWorks">             <xsl:apply-templates/>         </xsl:element>     </xsl:template>     <xsl:template match="Book">         <Book>             <xsl:attribute name ="name">                 <xsl:value-of select="@name"/>             </xsl:attribute>             <xsl:for-each select="Chapter">                 <Chapter>                     <xsl:value-of select="xslext:GetErrata(/)"/>                 </Chapter>             </xsl:for-each>         </Book>     </xsl:template> </xsl:stylesheet> 

Discussion

The ability to call custom code from inside of an XSLT stylesheet is a very powerful one, but one that should be used cautiously. Adding code like this into stylesheets usually renders them less useful in other environments. If the stylesheet never has to be used to transform XML in another parser, this can be a good way to offload work that is either difficult or impossible to accomplish in regular XSLT syntax.

The sample data used in the Solution is presented here:

 <?xml version="1.0" encoding="utf-8"?> <Publications>     <Book name="Subclassing and Hooking with Visual Basic">         <Chapter>Introduction</Chapter>          <Chapter>Windows System-Specific Information</Chapter>          <Chapter>The Basics of Subclassing and Hooks</Chapter>          <Chapter>Subclassing and Superclassing</Chapter>         <Chapter>Subclassing the Windows Common Dialog Boxes</Chapter>          <Chapter>ActiveX Controls and Subclassing</Chapter>          <Chapter>Superclassing</Chapter>          <Chapter>Debugging Techniques for Subclassing</Chapter>          <Chapter>WH_CALLWNDPROC</Chapter>          <Chapter>WH_CALLWNDPROCRET</Chapter>          <Chapter>WH_GETMESSAGE</Chapter>         <Chapter>WH_KEYBOARD and WH_KEYBOARD_LL</Chapter>         <Chapter>WH_MOUSE and WH_MOUSE_LL</Chapter>          <Chapter>WH_FOREGROUNDIDLE</Chapter>          <Chapter>WH_MSGFILTER</Chapter>          <Chapter>WH_SYSMSGFILTER</Chapter>          <Chapter>WH_SHELL</Chapter>          <Chapter>WH_CBT</Chapter>          <Chapter>WH_JOURNALRECORD</Chapter>          <Chapter>WH_JOURNALPLAYBACK</Chapter>          <Chapter>WH_DEBUG</Chapter>          <Chapter>Subclassing .NET WinForms</Chapter>          <Chapter>Implementing Hooks in VB.NET</Chapter>      </Book>     <Book name="C# Cookbook">          <Chapter>Numbers</Chapter>          <Chapter>Strings and Characters</Chapter>          <Chapter>Classes And Structures</Chapter>          <Chapter>Enums</Chapter>          <Chapter>Exception Handling</Chapter>          <Chapter>Diagnostics</Chapter>          <Chapter>Delegates and Events</Chapter>          <Chapter>Regular Expressions</Chapter>          <Chapter>Collections</Chapter>          <Chapter>Data Structures and Algorithms</Chapter>         <Chapter>File System IO</Chapter>          <Chapter>Reflection</Chapter>          <Chapter>Networking</Chapter>          <Chapter>Security</Chapter>          <Chapter>Threading</Chapter>          <Chapter>Unsafe Code</Chapter>          <Chapter>XML</Chapter>     </Book>     <Book name="C# Cookbook 2.0">          <Chapter>Numbers and Enumerations</Chapter>          <Chapter>Strings and Characters</Chapter>          <Chapter>Classes And Structures</Chapter>          <Chapter>Generics</Chapter>          <Chapter>Collections</Chapter>          <Chapter>Iterators and Partial Types</Chapter>          <Chapter>Exception Handling</Chapter>          <Chapter>Diagnostics</Chapter>          <Chapter>Delegates, Events, and Anonymous Methods</Chapter>          <Chapter>Regular Expressions</Chapter>          <Chapter>Data Structures and Algorithms</Chapter>         <Chapter>File System IO</Chapter>          <Chapter>Reflection</Chapter>          <Chapter>Web</Chapter>          <Chapter>XML</Chapter>          <Chapter>Networking</Chapter>          <Chapter>Security</Chapter>          <Chapter>Threading and Synchronization</Chapter>          <Chapter>Unsafe Code</Chapter>          <Chapter>Toolbox</Chapter>     </Book>  </Publications> 

See Also

See the "XsltArgumentList Class" topic in the MSDN documentation.



C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net