views:

2777

answers:

6

I'd like to use regular expressions in selecting elements using the match function. I'd prefer not to use an external library (such as saxon) to do this.

A: 

Yes, 3.5 XPathNavigator supports XSLT 2.0.

http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathnavigator.aspx

"The XPathNavigator class in the System.Xml.XPath namespace is an abstract class which defines a cursor model for navigating and editing XML information items as instances of the XQuery 1.0 and XPath 2.0 Data Model."

Nikki9696
Then why isn't the matches function recognized?
Will
I don't know; it's documented. http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathnavigator.matches.aspx
Nikki9696
XSLT is not the same as XPath or XQuery, so it really doesn't support XSLT 2.0 (there are a few things it does, but not a lot.)
Scott Dorman
@Scott: There are not even a "few things" I'm afraid. Nothing is supported of either XPath 2.0 or XSLT 2.0. They've announced an implementation but later withdrew that again.
Abel
+1  A: 
sontek
"I'd prefer not to use an external library (such as saxon) to do this."
Will
corner cases? XSLT 2.0 is a complete rewrite and very wide extension to the 1.0 spec. There's currently no support whatsoever for any of the new functionality of XSLT 2.0 or XPath 2.0 in .NET and there are no plans anymore: http://stackoverflow.com/questions/1525299/xpath-and-xslt-2-0-for-net
Abel
I think I had a bounty on this, which automatically selects the top voted answer. With Abel's addition this is a good choice now.
Will
+3  A: 

I think the answer above is wrong. I can't find any evidence that Microsoft supports XSLT 2.0. XSLT != XPath.

Pete
I think the answer being references is this one: http://stackoverflow.com/questions/94047/are-net-35-xpath-classes-and-methods-xslt-20-compatible#94076 (by Nikki9696)
Scott Dorman
+2  A: 

For future reference, here's a nice page on extending xpath/xquery in .net:

http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=64

I don't trust this to last, so I copy it here:


XSLT is a transformation language for XML. It allows server systems to transform the source XML tree into a more suitable form for clients. XSLT uses node patterns to match against templates to perform its transformations. Though it makes complex transformations relatively simple there are some situations where we might have to use some custom classes.

Some of the situations where we might need to extend XSLT are:

1) Call custom business logic
2) Perform different actions depending on Permissions
3) Perform complex formatting for dates, strings etc
4) Or even call a webservice!!

Steps to extend XSLT

1) Create the custom object to use from within XSLT(in C#)

CustomDate custDate = new CustomDate() ;

2) Provide a custom namespace declaration for the custom class within XSLTs namespace declaration(in XSLT file)

<xsl:transform
        version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:myCustDate="urn:custDate">

3) Pass an instance of the custom object to XSLT, with the same namespace as in last step(in C#)

xslArgs.AddExtensionObject("urn:custDate", custDate) ;

4) Use the object from within XSLT(in XSLT file)

<xsl:value-of select="myCustDate:GetDateDiff(./joiningdate)"/>

Sample code

For our example let us assume we have a XSLT sheet where we need to manipulate dates. We need to show the number of days the employee has been with the company. Since XSLT has no native date manipulation functions, let us use an extension object for our task.

using System ;
using System.IO ;
using System.Xml ;
using System.Xml.Xsl ;
using System.Xml.XPath ;

public class XsltExtension{

    public static void Main(string[] args){

        if (args.Length == 2){

            Transform(args[0], args[1]) ;

        }else{

            PrintUsage() ;

        }
    }

    public static void Transform(string sXmlPath, string sXslPath){

        try{

            //load the Xml doc
            XPathDocument myXPathDoc = new XPathDocument(sXmlPath) ;

            XslTransform myXslTrans = new XslTransform() ;

            //load the Xsl 
            myXslTrans.Load(sXslPath) ;

            XsltArgumentList xslArgs = new XsltArgumentList() ;

            //create custom object
            CustomDate custDate = new CustomDate() ;

            //pass an instance of the custom object
            xslArgs.AddExtensionObject("urn:custDate", custDate) ;

            //create the output stream
            XmlTextWriter myWriter = new XmlTextWriter("extendXSLT.html", null) ;

            //pass the args,do the actual transform of Xml
            myXslTrans.Transform(myXPathDoc,xslArgs, myWriter) ;        

            myWriter.Close() ;

        }catch(Exception e){

            Console.WriteLine("Exception: {0}", e.ToString());
        }

    }

    public static void PrintUsage(){
        Console.WriteLine("Usage: XsltExtension.exe <xml path> >xsl path<") ;
    }

}

//our custom class
public class CustomDate{

    //function that gets called from XSLT
    public string GetDateDiff(string xslDate){

        DateTime dtDOB = DateTime.Parse(xslDate) ;

        DateTime dtNow = DateTime.Today ;

        TimeSpan tsAge = dtNow.Subtract(dtDOB) ;

        return tsAge.Days.ToString() ;
    }

}

Compile this code and use the provided members.xml and memberdisplay.xsl to run this console application. You should see a extendXSLT.html file within the same folder. Open this file and notice that our class CustomDate has been called to calculate the number of days the employee has been in the company.

Summary :
XSLT is a powerfull transformation language for XML, however using extension objects in .NET and C# should ensure that we could easily accomplish what would be impossible or hard with XSLT alone.

Members.xml:

 <root>
    <member>
     <name>Employee1</name>
     <joiningdate>01/01/1970</joiningdate>
     <role>CTO</role>
    </member>
    <member>
     <name>Employee2</name>
     <joiningdate>24/07/1978</joiningdate>
     <role>Web Developer</role>
    </member>
    <member>
     <name>Employee3</name>
     <joiningdate>15/12/1980</joiningdate>
     <role>Tester</role>
    </member>
</root>

Memberdisplay.xsl:

<xsl:transform
        version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:myCustDate="urn:custDate">

<xsl:output method="html" omit-xml-declaration="yes" />  

    <xsl:template match="/">
     <html>
      <head>
       <style>
        TABLE.tblMaster
        {
            border-style: solid; 
         border-width: 1px 1px 1px 1px; 
         border-style: solid; 
         border-color:  #99CCCC; 
         padding: 4px 6px; 
         text-align: left; 
            font-family:Tahoma,Arial;
         font-size:9pt;

        }
        TD.tdHeader
        {
            FONT-WEIGHT: bolder;
            FONT-FAMILY: Arial;
            BACKGROUND-COLOR: lightgrey;
            TEXT-ALIGN: center
        }
       </style>
      </head>
      <body>
       <table width="50%" class="tblMaster">
        <tr >
         <td class="tdHeader">Employee</td>
         <td class="tdHeader">Join date</td>
         <td class="tdHeader">Days in company</td>
         <td class="tdHeader">Role</td>
        </tr>
        <xsl:for-each select="/root/member">

         <tr >
          <td> <xsl:value-of select="./name"/> </td>

          <td> <xsl:value-of select="./joiningdate"/> </td>

          <td> <xsl:value-of select="myCustDate:GetDateDiff(./joiningdate)"/> </td>

          <td> <xsl:value-of select="./role"/> </td>
         </tr> 

        </xsl:for-each>

       </table>
      </body>
     </html>
    </xsl:template>

</xsl:transform>
Will
+1 excellent post and explanation of extending XSLT 1.0 in .NET.
Abel
@abel go visit the site I linked and give them some love. I stole it all from them.
Will
:-) already did! ...
Abel
+3  A: 

I believe the answer in this discussion is misleading. I think .NET 3.5 doesn't support most XSL/T 2.0 functions (if any at all).

An example:

A call to a 2.0 function gives the following error message under .NET 3.5:

'current-dateTime()' is an unknown XSLT function.

E Zeelen
You are totally correct. There's no support at all for XSLT 2.0. The answer is indeed misleading. I added a note to that answer.
Abel
+2  A: 

When discussing .NET support for XSLT 2.0, XPath 2.0, and XQuery 1.0, it is important to distinguish between the languages themselves and the Data Model (XDM). The .NET 3.5 Framework supports the Data Model, but not the languages. As it was recently explained to me via email correspondence by Microsoft's Pawel Kadluczka:

The sentence "instances of the XQuery 1.0 and XPath 2.0 Data Model" may be confusing but I believe it refers to W3C XQuery 1.0 and XPath 2.0 Data Model (XDM) spec (http://www.w3.org/TR/xpath-datamodel) that reads:

[Definition: Every instance of the data model is a sequence.].

[Definition: A sequence is an ordered collection of zero or more items.] A sequence cannot be a member of a sequence. A single item appearing on its own is modeled as a sequence containing one item. Sequences are defined in 2.5 Sequences.

[Definition: An item is either a node or an atomic value],

In the case of XPath API - XPathNodeIterator is the sequence while XPathItem (XPathNavigator) represents the item.

John Ingle
Thanks for that info.
Will
Excellent answer, much more correct than the actual answer ;-). I've been looking for an official document about the support (and use?) of XDM, but couldn't find any. Does Kadluczka perhaps know one?
Abel
Mr. Kadluczka did not recommend any such document. I recommend contacting the Microsoft XML Team via their blog at http://blogs.msdn.com/xmlteam/ if you have any specific questions.
John Ingle