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

3

我希望使用正则表达式在匹配函数中选择元素,但不想使用外部库(如saxon)来完成此操作。

6个回答

5

我认为这个讨论中的答案是误导性的。我认为.NET 3.5不支持大多数XSL/T 2.0函数(如果有的话)。

一个例子

在.NET 3.5下调用2.0函数会给出以下错误信息:

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


你是完全正确的。XSLT 2.0 没有任何支持。答案确实是误导性的。我在那个答案上添加了一个注释。 - Abel

3
在XSLT 2.0中有一些内置库不支持的功能(关于此问题,在mono邮件列表中进行了讨论,但我找不到信息了)。但是大多数人从未遇到不受支持的边缘情况。
另一个选择是查看开源http://saxon.sourceforge.net/,它对2.0有很好的支持。 编辑(AB):上面接受的答案可能会令人困惑。在.NET中,没有任何XPath 2.0或XSLT 2.0函数的支持,也没有朝这个方向的计划

我更愿意不使用外部库(比如saxon)来完成这个任务。 - user1228
2
角落案例? XSLT 2.0 是对 1.0 规范的完全重写和非常广泛的扩展。目前,在 .NET 中没有对 XSLT 2.0 或 XPath 2.0 的任何新功能提供支持,也没有任何计划:https://dev59.com/6XI_5IYBdhLWcg3wF_F3 - Abel
我想我在这个问题上有一个赏金,它会自动选择得票最高的答案。有了Abel的补充,现在这是一个不错的选择。 - user1228

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

1
我认为答案是关于引用的,可以参考这个链接:https://dev59.com/B0XRa4cB1Zd3GeqPpzQi(作者Nikki9696) - Scott Dorman

2

为了以后参考,这里有一个有关在.net中扩展xpath/xquery的不错页面:

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

我不相信这个会长存,所以我把它复制到这里:


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

我们需要扩展XSLT的一些情况包括:

1) 调用自定义业务逻辑
2) 根据权限执行不同的操作
3) 对日期、字符串等进行复杂的格式化
4) 甚至调用webservice!!

扩展XSLT的步骤:

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

CustomDate custDate = new CustomDate() ;

2) 在XSLT文件中的命名空间声明中为自定义类提供自定义命名空间声明。

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

3) 在C#中,将自定义对象的实例传递给具有与上一步相同命名空间的XSLT。

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

4) 在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>        

+1 很棒的帖子,对在 .NET 中扩展 XSLT 1.0 进行了很好的解释。 - Abel
@abel 去访问我链接的网站,给他们一些爱。我从他们那里偷了所有东西。 - user1228

2
当讨论.NET对XSLT 2.0、XPath 2.0和XQuery 1.0的支持时,重要的是要区分语言本身和数据模型(XDM)。 .NET 3.5框架支持数据模型,但不支持这些语言。正如微软的Pawel Kadluczka最近在电子邮件中向我解释的那样:
“XQuery 1.0和XPath 2.0数据模型的实例”这句话可能有些混淆,但我认为它指的是W3C XQuery 1.0和XPath 2.0数据模型(XDM)规范(http://www.w3.org/TR/xpath-datamodel),其中写道:“[定义:数据模型的每个实例都是一个序列。]。” “[定义:序列是零个或多个项目的有序集合。] 序列不能是序列的成员。单个出现的项目被建模为包含一个项目的序列。序列在2.5序列中定义。” “[定义:项目是节点或原子值],在XPath API的情况下 - XPathNodeIterator是序列,而XPathItem(XPathNavigator)表示项目。”

非常好的回答,比实际答案正确得多 ;-). 我一直在寻找关于 XDM 支持(和使用?)的官方文件,但找不到任何信息。Kadluczka 是否知道其中一个呢? - Abel
Kadluczka先生并未推荐任何此类文档。如果您有任何具体问题,我建议通过他们的博客http://blogs.msdn.com/xmlteam/联系Microsoft XML团队。 - John Ingle

-3

那为什么匹配函数没有被识别? - user1228
我不知道,它有文档记录。http://msdn.microsoft.com/zh-cn/library/system.xml.xpath.xpathnavigator.matches.aspx - Nikki9696
XSLT与XPath或XQuery不同,因此它实际上不支持XSLT 2.0(虽然有一些它可以做到的事情,但并不多)。 - Scott Dorman
@Scott:恐怕没有“几件事”可以做。 无论是XPath 2.0还是XSLT 2.0都没有得到支持。 他们宣布了一种实现,但后来又撤回了。 - Abel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接