C#中使用Xslt 2.0处理器

用C#处理Xslt 2.0的时候,才发现原来.Net并没有提供对Xslt 2.0的支持,毕竟Xslt 2.0目前更多的还是纸面上的标准,而且微软的动作一向速度有限。

于是开始找专门的Xslt 2.0处理器。

首先找到的是Saxon,不知道是不是逐步商业化的缘故,Saxon版本显得有点凌乱。在9.1,分成商用的SA版,开源的B版;到了9.2又改成商用的EE企业版,PE专业版和开源的HE家庭版,加上每个版本又都分成java版和.Net版,看得都有点眼晕。

不管怎样直奔最新版本,先下了9.2 HE .NET版,结果发现处理中总是会有出现编码异常,貌似是Saxon的一个BUG,因为也其他有人碰到同样的问题,据说是换上9.1就没有好了。

于是换上9.1 B版,果然什么问题都没有了。察看文件9.2在支持库的部署方式上作了大的调整,可能是因为这个缘故导致的吧。(一个小问题,9.1中包含的IKVM.OpenJDK.ClassLibrary.dll,一个文件就26M,无论如此无法提交到Google Code,而在9.2中,这个大文件被分割成了几个相对小的问题)

Saxon在调用上,最简单的方式是使用SaxonWarpper,代码类似.Net本身的方式。其实SaxonWarpper自己也不过是几行代码而已,所以直接调用Saxon也不会复杂到哪儿去,下面是一段处理Xslt 2.0的代码:

        /// <summary>
        /// 使用Saxon处理Xslt 2.0
        /// </summary>
        /// <param name="strXml">字符串形式的XML数据</param>
        /// <param name="strXsl">字符串形式的XSLT数据</param>
        /// <returns>处理后的XML字符串</returns>
        public static string TransformBySaxon( string strXml, string strXsl )
        {
            //
            System.Xml.XmlDocument xml = new System.Xml.XmlDocument();
            xml.LoadXml(strXml);
            //
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            Saxon.Api.Processor    processor = new Saxon.Api.Processor();
            Saxon.Api.XsltCompiler compiler = processor.NewXsltCompiler();
            System.Xml.XmlReader xr = System.Xml.XmlReader.Create( new System.IO.StringReader( strXsl ) );
            Saxon.Api.XsltTransformer transformer = compiler.Compile(xr).Load();
            Saxon.Api.XdmNode inputNode = processor.NewDocumentBuilder().Build(xml);
            transformer.InitialContextNode = inputNode;
            Saxon.Api.TextWriterDestination dest = new Saxon.Api.TextWriterDestination( System.Xml.XmlWriter.Create( sb ) );
            transformer.Run(dest);
            return sb.ToString();       
        }

除了Saxon以外,AltavoXML也是一个不错的选择,本来以为只要安装XmlSpy就可以使用AltavoXML,就像Adobe Reader那样,可在GAC中怎么也找不到。后来才发现AltavoXML是需要另外下载的。

安装过程很简单,并且会自动注册到GAC中,然后再C#中添加引用就可以了。

AltavoXML的调用非常的简单,调用代码如下:

        /// <summary>
        /// 使用AltovaXML处理Xslt 2.0
        /// </summary>
        /// <param name="strXml">字符串形式的XML数据</param>
        /// <param name="strXsl">字符串形式的XSLT数据</param>
        /// <returns>处理后的XML字符串</returns>
        public static string TransformByAltovaXML( string strXml, string strXsl )
        {
            Altova.AltovaXML.ApplicationClass ac = new Altova.AltovaXML.ApplicationClass();
            ac.XSLT2.InputXMLFromText = strXml;
            ac.XSLT2.XSLFromText = strXsl;
            return ac.XSLT2.ExecuteAndGetResultAsString();           
        }

AltavoXML比较奇怪的地方是,按说应该是和XmlSpy共用的技术,但在执行效率上却远达不到XmlSpy的效果,不知道是我调用的缘故还是XmlSpy在其他地方做了什么优化。

那么,到底应该使用Saxon还是AltavoXML呢?

首先,感觉上AltavoXML在处理上比Saxon精确(可能是因为处理结果的比较都是用XmlSpy做参照),如正则表达式的处理,两者处理结果尚有差距,或许也是因为Xslt 2.0的标准还不够完善,但这些差距已经足以影响到返回Xml的后续处理了。

其次,Saxon基于Java的原始代码,所以C#的调用接口库需要包括内置Java虚拟机IKVM和OpenJDK,仅IKVM就已经超过25M,全部库加起来要35M以上(貌似9.2版相对小一点,但也超过25M),对于桌面程序部署负担比较大。而AltovaXML只有一个14M的组件,压缩后不到3M

第三,AltovaXML的弱点在于它基于一个EXE的COM组件,所以跨平台能有限,而且可能会因为COM注册的问题无法在远程服务器上部署,而Saxon则没有这样的问题

所以桌面程序,我倾向于AltovaXML,而Web类程序倾向于Saxon。

即使如此,如果能够在一个程序中同时支持2种处理器,提供方式让用户选择或能够自动根据环境配置仍然是很有吸引力的一种想法。

好在两个处理器都提供了专门的接口dll,Saxon是saxon9api.dll和saxon9api.netmodule,AltovaXML是Altova.AltovaXML.dll(需要从GAC中复制出来,方法是在控制台用命令行进入对应的目录,用copy进行复制),我们只需要将这些dll引用并附带在我们的安装包中,并使用以下的代码对对应处理器的有效性进行判断就可以了。

/// <summary>
/// 检查Xslt 2.0引擎的有效性
/// </summary>
/// <returns>返回可用的引擎类型,所有都不可用则返回Unknown</returns>
public static Xsl2EngineType CheckEngine()
{
    try {
        Altova.AltovaXML.ApplicationClass ac = new Altova.AltovaXML.ApplicationClass();
        return Xsl2EngineType.AltovaXML;
    } catch (Exception)
    {
    }
    try {
        Saxon.Api.Processor    processor = new Saxon.Api.Processor();
        return Xsl2EngineType.Saxon;
    }catch (Exception)
    {           
    }

    return Xsl2EngineType.Unknown;
}

Leave a Reply

Your email address will not be published. Required fields are marked *