.NET 3.5 XPath类和方法是否与XSLT 2.0兼容?

时间:2020-03-06 14:22:11  来源:igfitidea点击:

我想在使用match函数选择元素时使用正则表达式。我不希望使用外部库(例如saxon)来执行此操作。

解决方案

是的,3.5 XPathNavigator支持XSLT 2.0。

http://msdn.microsoft.com/zh-CN/library/system.xml.xpath.xpathnavigator.aspx

" System.Xml.XPath命名空间中的XPathNavigator类是一个抽象类,它定义了一个游标模型,以作为XQuery 1.0和XPath 2.0数据模型的实例来导航和编辑XML信息项。"

内置库中不支持XSLT 2.0中的某些功能(在单邮件列表中对此进行了讨论,但我找不到信息了)。但是大多数人从来没有遇到过不被支持的情况。

另一种选择是查看开放源码http://saxon.sourceforge.net/,它对2.0有很好的支持。

编辑(AB):以上接受的答案可能会造成混淆。根本没有任何支持,并且.NET中没有针对XPath 2.0或者XSLT 2.0功能的任何计划。

我认为以上答案是错误的。我找不到任何证据表明Microsoft支持XSLT 2.0。 XSLT!= XPath。

供将来参考,这是有关在.net中扩展xpath / xquery的一个不错的页面:

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

我不相信这会持续到最后,所以我在这里复制:

XSLT是XML的转换语言。它允许服务器系统将源XML树转换为更适合客户端的形式。 XSLT使用节点模式来匹配模板以执行其转换。尽管它使复杂的转换相对简单,但是在某些情况下,我们可能不得不使用一些自定义类。

我们可能需要扩展XSLT的一些情况是:

1)调用自定义业务逻辑
2)根据权限执行不同的操作
3)对日期,字符串等执行复杂的格式化
4)甚至打电话给网络服务!

扩展XSLT的步骤

1)从XSLT(在C#中)创建要使用的自定义对象

CustomDate custDate = new CustomDate() ;

2)在XSLT名称空间声明(在XSLT文件中)内为自定义类提供自定义名称空间声明

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

3)将自定义对象的实例传递给XSLT,并使用与上一步相同的名称空间(在C#中)

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

4)使用XSLT中的对象(在XSLT文件中)

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

样例代码

对于我们的示例,假设我们有一个XSLT工作表,我们需要在其中操纵日期。我们需要显示员工在公司的工作天数。由于XSLT没有本地日期操作功能,因此让我们为任务使用扩展对象。

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() ;
    }

}

编译此代码,并使用提供的members.xml和memberdisplay.xsl运行此控制台应用程序。我们应该在同一文件夹中看到一个extendXSLT.html文件。打开此文件,请注意已经调用了我们的CustomDate类来计算员工进入公司的天数。

概括 :
XSLT是XML的强大转换语言,但是在.NET和C中使用扩展对象应确保我们可以轻松完成仅凭XSLT不可能或者很难完成的工作。

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>

我相信在这次讨论中的答案是误导的。我认为.NET 3.5不支持大多数XSL / T 2.0功能(如果有的话)。

一个例子:

在.NET 3.5下,对2.0函数的调用会给出以下错误消息:

'current-dateTime()'是未知的XSLT函数。

在讨论.NET对XSLT 2.0,XPath 2.0和XQuery 1.0的支持时,重要的是要区分语言本身和数据模型(XDM)。 .NET 3.5框架支持数据模型,但不支持语言。正如最近Microsoft的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.