Click here to Skip to main content
Click here to Skip to main content

XSLT Unleashed

, 11 Jan 2007
Rate this:
Please Sign up or sign in to vote.
Another use for XML and XSLT

Introduction

Following on from a previous article I posted, I thought I'd share another use for XML and XSLT, albeit an uncommon one.

The Problem

You have an application which imports data from an XML file. Odds are that the schema changes or a new namespace is introduced. You will need to rewrite your loader code and update the application at the client. Alternatively, you don't enjoy writing lots of loopy code using XPathNavigators and XPathNodeIterators, or worse the XMLDocument.

The Solution

Use XSLT to transform the source XML data into XSLT extension calls to a object which will persist the imported data to a backing store. This way, you can package the XML importers as external files to the application, and just deploy a new XSLT whenever the source changes. Since XSLT is designed to manipulate XML, it offers a more elegant approach to extracting the data than writing loopy code. Other nasties like supporting multiple namespaces are easy to do using XSLT. An interesting side effect is that the output of the transform can be used as an activity log of the imports activities.

How it Works

The attached sample application imports order data from an XML file to a backing store. The source XML data is transformed by an XSLT which invokes methods on an extension object to do the work of creating the order and details in the backing store.

XSLT invoking methods

An instance of the OrderEntry() class is created and added to the XslTransform as an extension under the urn:chrisstefano.xslt.orderentry namespace.

// load orders document (assume in bin/Debug or bin/Release dir)
XmlDocument ordersDoc = new XmlDocument();
ordersDoc.Load("Orders.xml");

// load order processor XSLT
XslTransform orderProcessor = new XslTransform();
orderProcessor.Load("LoadOrder.xslt");

XsltArgumentList args = new XsltArgumentList();

// associate the extension object with a namespace, so
// it can be invoked within the transformation
args.AddExtensionObject("urn:chrisstefano.xslt.orderentry", 
                            new OrderEntry());

XmlTextWriter output = new XmlTextWriter("output.xml", 
                        System.Text.Encoding.UTF8); 

orderProcessor.Transform(ordersDoc.CreateNavigator(), args, output, null);

output.Close();

The OrderEntry class contains two methods for interfacing with the backing store.

Order Entry extension class

The int CreateOrder(string) method creates the order header record and returns an int which represents the order identifier. The decimal CreateOrderLine(int, string, int, decimal) method takes the order identifier and some other information and creates the order line. It returns a decimal value which represents the value of the order line. This value is included in the output of the transformation.

This extension namespace is declared in the XSLT with the prefix ext. Method calls on the extension are written using the prefix and the method name.

<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:ext="urn:chrisstefano.xslt.orderentry">

   <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

  <xsl:template match="/">
    <OrderProcessing>
      <xsl:apply-templates select="Orders"/>    
    </OrderProcessing>
  </xsl:template>
  
  <xsl:template match="Orders">
    <xsl:apply-templates select="Order">
      <xsl:sort select="@date" />      
    </xsl:apply-templates>    
  </xsl:template>
  
  <xsl:template match="Order">
    
    <!-- invoke extension to create the order -->
    <!-- save the order id into a variable -->
    
    <xsl:variable name="order-id">
    <xsl:value-of select="ext:CreateOrder(@customer)"/></xsl:variable>
    
    <!-- write out processing step -->
    <OrderProcessed order-id="{$order-id}" customer="{@customer}">
    
      <xsl:apply-templates select="OrderLine">
        <xsl:with-param name="order-id" select="$order-id" />
      </xsl:apply-templates>
      
    </OrderProcessed>
    
  </xsl:template>
  
  <xsl:template match="OrderLine">
    <xsl:param name="order-id">0</xsl:param>
    
    <!-- invoke extension function to create order line -->
    <!-- save consideration into variable -->
    <xsl:variable 
          name="consideration" 
          select="ext:CreateOrderLine
        ($order-id, @product, number(@quantity), number(@price))" />
    
    <!-- write out processed order line -->
    <ProcessedOrderLine consideration="{$consideration}" />
    
  </xsl:template>

</xsl:stylesheet>

Conclusion

XSLT is an elegant way to query and manipulate XML data, and coupled with XSLT extensions provides a way to interface with other data stores.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Chris Stefano
Software Developer (Senior)
South Africa South Africa
I'm a developer specializing in software for the financial services industry particularly in the decision support area. Currently my specialty is in investment compliance.

Comments and Discussions

 
GeneralHi, Implementation technique required for xslt. PinmemberSidharthaShenoy17-Aug-10 3:30