It's surprisingly easy in .NET 2.0. Obviously it can't be done with pure XSLT, but an extension function returning line number for a node takes literally two lines. The trick is to use XPathDocument, not XmlDocument to store source XML to be transformed.
The key is IXmlLineInfo interface. Every XPathNavigator over XPathDocument implements this interface and provides line number and line position for every node in a document. Here is a small sample:
using System; using System.Xml; using System.Xml.XPath; using System.Xml.Xsl; public class Test { static void Main() { XPathDocument xdoc = new XPathDocument("books.xml"); XslCompiledTransform xslt = new XslCompiledTransform(); xslt.Load("foo.xslt", XsltSettings.TrustedXslt, new XmlUrlResolver()); xslt.Transform(xdoc, null, Console.Out); } }
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://example.com/ext" extension-element-prefixes="ext"> <ms:script implements-prefix="ext" xmlns:ms="urn:schemas-microsoft-com:xslt" language="C#"> public int line(XPathNavigator node) { IXmlLineInfo lineInfo = node as IXmlLineInfo; return lineInfo != null ? lineInfo.LineNumber : 0; } </ms:script> <xsl:template match="/"> <foo> <xsl:value-of select="ext:line(//book)"> </foo> </xsl:template> </xsl:stylesheet>
Ability to report line info is another reason to choose XPathDocument as a store for your XML (in read-only scenarios such as query or transformation) - in addition to better performance and smaller memory footprint.
If you really need the same, but with XmlDocument, you have to extend DOM.
Leave a comment