Click here to Skip to main content
15,889,034 members
Articles / Programming Languages / XSLT
Tip/Trick

Applying XSL Transformations

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
31 Mar 2010CPOL1 min read 10.2K   2  
Setup: A data from one module is passed into another so that Module 1 takes a (flat) file as input and feeds an xml structure into Module 2. While Module 2 is internal, Module 1 is designed to handle different customer inputs into the system. However, it is not always possible to generate the...
Setup:
A data from one module is passed into another so that Module 1 takes a (flat) file as input and feeds an xml structure into Module 2. While Module 2 is internal, Module 1 is designed to handle different customer inputs into the system. However, it is not always possible to generate the expected Module 2 xml structure from the flat file in one step.

|Customer| -> file -> |Module 1| -> xml(products-product-detail) -> |Module 2|

There are at least two ways to accomodate the (multi-step) translation process:
  • Add re-parsing logic directly in the code - not smart enough as we do not know what input formats will need to be supported by Module 1 in the future
  • Apply customizable xsl transformations - providing decoupled solution with a reliable techology


For example:

Given a list of details, we can group them into product(s) in order to conform to the expected Module 2 hierarchy.

List of details:
XML
<?xml version='1.0' encoding="iso-8859-1"?>
<PRODUCTS>
	<DETAIL>
		<DESC>D1</DESC>
		<PRODUCT_NAME>APL</PRODUCT_NAME>
	</DETAIL>
	<DETAIL>	
		<DESC>D2</DESC>
		<PRODUCT_NAME>ANL</PRODUCT_NAME>
	</DETAIL>
	<DETAIL>
		<DESC>D3</DESC>
		<PRODUCT_NAME>APL</PRODUCT_NAME>
	</DETAIL>
</PRODUCTS> 


List of details grouped by product:
XML
<?xml version='1.0' encoding="iso-8859-1"?>
<PRODUCTS>
	<PRODUCT>
		<PRODUCT_NAME>ANL</PRODUCT_NAME>
		<DETAIL>	
			<DESC>D2</DESC>
			<PRODUCT_NAME>ANL</PRODUCT_NAME>
		</DETAIL>
	</PRODUCT>
	<PRODUCT>
		<PRODUCT_NAME>APL</PRODUCT_NAME>
		<DETAIL>
			<DESC>D1</DESC>
			<PRODUCT_NAME>APL</PRODUCT_NAME>
		</DETAIL>
		<DETAIL>
			<DESC>D3</DESC>
			<PRODUCT_NAME>APL</PRODUCT_NAME>
		</DETAIL>
	</PRODUCT>
</PRODUCTS> 


:thumbsup: In order to achieve this grouping, we can use the Muenchian method as described here:

http://www.jenitennison.com/xslt/grouping/muenchian.html[^]
XML
<!-- GROUPING USING THE MUENCHIAN METHOD: http://www.jenitennison.com/xslt/grouping/muenchian.html -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="xml" indent="yes" encoding="iso-8859-1"/>

	<xsl:key name="details-by-product" match="DETAIL" use="PRODUCT_NAME" />

	<xsl:template match="PRODUCTS">
		<PRODUCTS>
		<xsl:for-each select="DETAIL[count(. | key('details-by-product', PRODUCT_NAME)[1]) = 1]">
			<xsl:sort select="PRODUCT_NAME" />
			<PRODUCT>
				<PRODUCT_NAME><xsl:value-of select="PRODUCT_NAME"/></PRODUCT_NAME>
				<xsl:for-each select="key('details-by-product', PRODUCT_NAME)">
					<DETAIL>
					<xsl:apply-templates/>
					</DETAIL>
				</xsl:for-each>
			</PRODUCT>
		</xsl:for-each>
		</PRODUCTS>
	</xsl:template>

	<xsl:template match="@*|node()">
	  <xsl:copy>
		<xsl:apply-templates select="@*|node()"/>
	  </xsl:copy>
	</xsl:template>
</xsl:stylesheet>

See also:


    XSL Transformations (XSLT):  http://www.w3.org/TR/xslt[^]
    Grouping With XSLT 2.0:  http://www.xml.com/pub/a/2003/11/05/tr.html[^]
    Dave Pawson's Grouping page:  http://www.dpawson.co.uk/xsl/sect2/N4486.html[^]


:thumbsup: In order to test the transformation, we can initiate the xslt in a script as described here:

http://msdn.microsoft.com/en-us/library/ms762796(VS.85).aspx[^]
//Initiate XSLT in a script: http://msdn.microsoft.com/en-us/library/ms762796(VS.85).aspx
var oArgs = WScript.Arguments;

if (oArgs.length == 0)
{
    WScript.Echo ("Usage : cscript xslt.js xml xsl");
    WScript.Quit();
}
xmlFile = oArgs(0) + ".xml";
xslFile = oArgs(1) + ".xsl";

var xsl = new ActiveXObject("MSXML2.DOMDOCUMENT.6.0");
var xml = new ActiveXObject("MSXML2.DOMDocument.6.0");
xml.validateOnParse = false;
xml.async = false;
xml.load(xmlFile);

if (xml.parseError.errorCode != 0)
    WScript.Echo ("XML Parse Error : " + xml.parseError.reason);

xsl.async = false;
xsl.load(xslFile);

if (xsl.parseError.errorCode != 0)
    WScript.Echo ("XSL Parse Error : " + xsl.parseError.reason);

try
{
    WScript.Echo (xml.transformNode(xsl.documentElement));
}
catch(err)
{
    WScript.Echo ("Transformation Error : " + err.number + "*" + err.description);
}


:thumbsup: In order to apply the transformation at run-time, we can use the XslCompiledTransform as described here:

http://msdn.microsoft.com/en-us/library/system.xml.xsl.xslcompiledtransform_members.aspx[^]
C#
// XslCompiledTransform: http://msdn.microsoft.com/en-us/library/system.xml.xsl.xslcompiledtransform_members.aspx
// Note: Exception handling is outside of the scope of this tip
// Note: Xml results are loaded into memory and do not have to be written into the file system, if there is no need for it.
private string ApplyStylesheet(string xml, string stylesheet)
{
	if (!string.IsNullOrEmpty(stylesheet))
	{
		//Configure the reader to skip all forms of validation
		XmlReaderSettings settingsReader = new XmlReaderSettings();
		settingsReader.ValidationType = ValidationType.None;
		settingsReader.ProhibitDtd = false;
		settingsReader.XmlResolver = null;

		StringReader strReader = new StringReader(xml);
		XmlReader xmlReader = XmlReader.Create(strReader, settingsReader);
		// use XmlNodeReader xmlReader = new XmlNodeReader(xml); if xml is XmlNode (not a string)

		StringWriter stringWriter = new StringWriter();
		XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter);

		XslCompiledTransform xslt = new XslCompiledTransform();
		xslt.Load(stylesheet);
		xslt.Transform(xmlReader, xmlWriter);

		xmlWriter.Close();
		xmlReader.Close();

		return stringWriter.ToString();
	}
	return xml;
}


Good luck!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Canada Canada

Comments and Discussions

 
-- There are no messages in this forum --