Click here to Skip to main content
15,867,308 members
Articles / Programming Languages / XSLT

XSL 2.0 and XQuery 1.0 in .NET

Rate me:
Please Sign up or sign in to vote.
5.00/5 (12 votes)
18 Oct 2018Ms-PL4 min read 140.5K   4.4K   34   24
Using the open source Saxon library, .NET programmers can benefit from XSL 2.0 and XQuery 1.0.

Note: you must download both parts in order for the SaxonWrapper to work.

Introduction

This small project started when I wanted to use XSL 2.0 and XPath 2.0 in my .NET code. The problem is that the .NET framework only provides XSL 1.0 and XPath 1.0 out of the box. The only implementation of XSL 2.0 and XPath 2.0 that I am aware of is Saxon. In my experience, Saxon has not experienced wide spread adoption in the .NET community because of the considerable difference between Saxon interfaces and .NET XML interfaces. The aim of the project has been to write very simple interface adapters so that .NET programmers can use Saxon in the same way that they use System.Xml.

The reader should have a basic understanding of XML. The W3Schools website provides highly readable tutorials about XSL, XPath, and XQuery.

Motivation for Using Saxon

XPath 2.0 is richer and more flexible than XPath 1.0. In XPath 2.0, everything is a sequence rather than a "node set", and there is support for conditional logic and looping. For example, the following is a valid XPath 2.0 statement which returns a sequence:

XML
for $x in /order/item return $x/price * $x/quantity

XML.com has a very good article on XPath 2.0. The article was written in early 2002, which shows how long the technology has been around for.

XQuery 1.0 is an extension of XPath 2.0, and is a very capable query language. XQuery can be used to produce XML-based output in place of XSL. In fact, it is far easier to write XQuery than it is to write XSL. The main construct of XQuery is the FLOWR statement. FLOWR stands for "For, Let, Order by, Where, Return", and is similar to LINQ.

XML
<pricing>
for $x in doc("NorthWind.xml")/order/item
where $x/price>

XSL 2.0 uses XPath 2.0, whereas XSL 1.0 uses XPath 1.0. There are numerous benefits to using XSL 2.0 over XSL 1.0. In XSL 2.0, you can write a function in XSL and access the function from within XPath using the xsl:function element. This is an improvement from the previous situation where you write the XPath functions in .NET code and end up with platform specific XSL. Moreover, the development cycle is faster when the custom functions are written in XSL.

XSL 2.0 also features grouping using the xsl:for-each-group element. The following code from the XML.com article is a good example of this:

XML
<xsl:for-each-group select="cities/city" group-by="@country">
  <tr>
    <td><xsl:value-of select="@country"/></td>
    <td>
      <xsl:value-of select="current-group()/@name" separator=", "/>
    </td>
    <td><xsl:value-of select="sum(current-group()/@pop)"/></td>
  </tr>
</xsl:for-each-group>

Detailed information about XSL 2.0 can be found at XML.com.

Using the Code

As discussed, the API for Saxon is somewhat different to the standard XML API for .NET. This project addresses the issue using the adapter pattern. The classes Xsl2Processor and XQueryProcessor present the Saxon API to the .NET programmer in a similar way to the presentation of XslCompiledTransform in System.Xml. The main difference is that XslCompiledTransform accepts IXPathNavigable as XML source, whereas the wrappers accept the less generalized XmlNode. This is due to the Saxon API using XmlNode.

The code incorporates Saxon and its related libraries as a Visual Studio project called SaxonWrappers. There are two options for usage. The first is to add the SaxonWrappers project to your solution. This allows you to customize the wrappers. Alternatively, you can reference all the assemblies in the root directory of the zip file. Ensure that the saxon9api.netmodule file is in the same directory as the DLL files.

The following code performs an XSL 2.0 transformation books.xsl against books.xml and writes the resulting output to books.html. The input files are included in the download.

C#
using (StreamWriter streamWriter = 
       new StreamWriter("books.html", false, Encoding.UTF8))
{            
    // Load the input doc
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.Load("books.xml");

    // Create the output XmlWriter
    XmlTextWriter xmlWriter = new XmlTextWriter(streamWriter);

    // Do the transformation
    Xsl2Processor processor = new Xsl2Processor();
    processor.Load("books.xsl");
    processor.Transform(xmlDoc, xmlWriter);
}

The following code performs an XQuery 1.0 in books-to-html.xq against books.xml, and writes the resulting output to books_xq.html. The input files are included in the download.

C#
using (StreamWriter streamWriter = 
       new StreamWriter("books_xq.html", false, Encoding.UTF8))
{
    // Load the input doc
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.Load("books.xml");

    // Create the output XmlWriter
    XmlTextWriter xmlWriter = new XmlTextWriter(streamWriter);

    // Do the transformation
    XQueryProcessor xp = new XQueryProcessor();
    xp.LoadFromFile("books-to-html.xq");
    xp.RunQuery(xmlDoc, xmlWriter);    
}

The XQueryProcessor class also has a Load method to load an XQuery statement from a string.

More about Saxon, Java, and .NET

Saxon is written and maintained by Michael Kay, who is also the editor of the XSL 2.0 standard. Saxon is written in Java, and Michael has made the work available to .NET using IKVM. Saxon links to the Java core libraries using IKVM's compilation of GNU Class Path. All of these libraries are available under permissive Open Source licenses, including Saxon which is under the Mozilla Public License.

Further Reading

History

  • 25/03/2008 - First release

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Technical Lead Optalitix
United Kingdom United Kingdom
I am a software developer from South Africa currently living and working in the United Kingdom. I have an undergraduate degree in Computer Science and a Masters degree in Artificial Intelligence.

My present interests:
- ASP.NET MVC
- SQL Server
- Mongo Database
- NServiceBus

Optalitix

Comments and Discussions

 
QuestionPassing parameters to xslt2.0 using saxon wrapper in .Net Pin
Rubesh25-Feb-15 1:35
Rubesh25-Feb-15 1:35 
GeneralINFO: here's how to catch xsl:message output Pin
Member 386951926-Jul-12 0:28
Member 386951926-Jul-12 0:28 
GeneralRe: INFO: here's how to catch xsl:message output Pin
Gavin Sinai26-Jul-12 0:34
Gavin Sinai26-Jul-12 0:34 
QuestionProblem with '&' Pin
Member 844303520-Dec-11 22:02
Member 844303520-Dec-11 22:02 
Hello

First of all: Nice Work!

But I have a little problem with the character '&'. Your XSLT Processor always generate & amp; (I'm sorry for that space). CDATA doesnt work and I tried a lot of different ways to use '&' in my generated code, but it doesnt work.

Can't Saxon-B handle this? A little bit strange that it can handle other special chars like '%' or '$' but not '&'.

I hope you'll have a tip for me Smile | :)
GeneralTrobule with saxonwrapper and output textfile Pin
timeos1-Mar-10 5:45
timeos1-Mar-10 5:45 
GeneralRe: Trobule with saxonwrapper and output textfile Pin
timeos4-Mar-10 2:56
timeos4-Mar-10 2:56 
GeneralRe: Trobule with saxonwrapper and output textfile Pin
GLSinai4-Mar-10 3:59
GLSinai4-Mar-10 3:59 
GeneralRe: Trobule with saxonwrapper and output textfile Pin
timeos4-Mar-10 11:06
timeos4-Mar-10 11:06 
GeneralXQSharp Pin
N L Jones3-Sep-09 4:12
N L Jones3-Sep-09 4:12 
GeneralRe: XQSharp Pin
alt2556-Sep-10 22:05
alt2556-Sep-10 22:05 
QuestionClass Library & Client Code implementation Pin
guarisma26-May-09 22:19
guarisma26-May-09 22:19 
AnswerRe: Class Library & Client Code implementation Pin
GLSinai26-May-09 23:19
GLSinai26-May-09 23:19 
GeneralRe: Class Library & Client Code implementation Pin
guarisma27-May-09 1:06
guarisma27-May-09 1:06 
GeneralRe: Class Library & Client Code implementation Pin
GLSinai27-May-09 1:59
GLSinai27-May-09 1:59 
GeneralRe: Class Library & Client Code implementation Pin
guarisma27-May-09 3:17
guarisma27-May-09 3:17 
GeneralReplacing node(s) in one file med node(s) from another file(s) Pin
kastnes10-Apr-08 3:02
kastnes10-Apr-08 3:02 
GeneralRe: Replacing node(s) in one file med node(s) from another file(s) Pin
Gavin Sinai18-Apr-08 12:37
Gavin Sinai18-Apr-08 12:37 
News.Net XPath 2.0 Tools for Saxon Pin
pgfearo8-Apr-08 6:31
pgfearo8-Apr-08 6:31 
GeneralGreat post - one question Pin
headchem3-Apr-08 8:42
headchem3-Apr-08 8:42 
GeneralRe: Great post - one question [modified] Pin
Gavin Sinai3-Apr-08 9:22
Gavin Sinai3-Apr-08 9:22 
GeneralRe: Great post - one question Pin
headchem3-Apr-08 12:20
headchem3-Apr-08 12:20 
GeneralRe: Great post - one question Pin
Gavin Sinai4-Apr-08 4:59
Gavin Sinai4-Apr-08 4:59 
AnswerRe: Great post - one question Pin
headchem4-Apr-08 12:14
headchem4-Apr-08 12:14 
GeneralRe: Great post - one question Pin
Gavin Sinai4-Apr-08 21:32
Gavin Sinai4-Apr-08 21:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.