XmlResolver未使用XslCompiledTransform调用

时间:2014-05-21 13:22:11

标签: c# xml xslt

我正在尝试使用自定义XmlResolver而不是文件系统上的实际文件来解析XslCompiledTransform中的文档函数引用。使用过时的XslTransform我可以使它正常工作,但不能使用已编译的转换(出于性能原因我想使用它)。

源XML文档如下所示:

<?xml version=""1.0"" encoding=""UTF-8""?>
<StackOverflow>
</StackOverflow>

XSLT看起来像这样:

<xsl:stylesheet version=""1.0""
                xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""
                xmlns:xs=""http://www.w3.org/2001/XMLSchema""
                exclude-result-prefixes=""xs"">
    <xsl:variable name=""author"" select=""document('data.xml')""/>

    <xsl:template match=""/"">
        <StackOverflow>
            <Author>
                <xsl:copy-of select=""$author/Person/*""/>
            </Author>
        </StackOverflow>
    </xsl:template>
</xsl:stylesheet>

预期输出为:

<?xml version="1.0" encoding="utf-16"?>
<StackOverflow>
 <Author>
  <FirstName>Aaron</FirstName>
  <LastName>Janes</LastName>
 </Author>
</StackOverflow>

我想要使用自定义XmlResolver的部分是&#34;文档(&#39; data.xml&#39;)&#34;我不想从磁盘上的文件加载,但为了简洁和简洁,本文中,从解析器中的静态字典中加载,如下所示:

namespace transform
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Xml;

    public class XmlStaticResolver : XmlResolver
    {
        private const string PersonXml = 
@"<?xml version=""1.0"" encoding=""utf-8""?>
<Person>
    <FirstName>Aaron</FirstName>
    <LastName>Janes</LastName>
</Person>";

        private readonly IDictionary<string, string> _input;

        public XmlStaticResolver()
        {
            _input = new Dictionary<string, string>
            {
                { "data.xml", PersonXml }
            };
        }

        public override object GetEntity(Uri absoluteUri, 
                                         string role, 
                                         Type ofObjectToReturn)
        {
            var host = absoluteUri.Host;
            var xml = _input[host];
            var bytes = Encoding.UTF8.GetBytes(xml);
            var result = new MemoryStream(bytes);

            return result;
        }

        public override Uri ResolveUri(Uri baseUri, string relativeUri)
        {
            return new Uri("static://" + relativeUri);
        }
    }
}

解析器获取相对URI(&#34; data.xml&#34;)并预先设置一个伪协议,以便GetEntity方法考虑&#34; data.xml&#34;作为网址的主机。然后在静态字典中查找该值,并将其作为内存流返回以供转换使用。

当我使用过时的XmlTransform使用此方法时,它完全按预期工作,例如,使用上述XSLT和XML调用Transform方法获得预期结果:

namespace transform
{
    using System.IO;
    using System.Xml;
    using System.Xml.XPath;
    using System.Xml.Xsl;

    public class ObsoleteTransform
    {
        public string Transform(string xslt, string xml)
        {
            var resolver = new XmlStaticResolver();
            var transform = new XslTransform { XmlResolver = resolver };
            using (var transformReader = CreateXmlReader(new StringReader(xslt), resolver))
            {
                transform.Load(transformReader);
            }

            using (var writer = new StringWriter())
            {
                using (var xwriter = CreateXmlWriter(writer))
                {
                    using (var inputReader = new StringReader(xml))
                    {
                        var input = new XPathDocument(inputReader);
                        transform.Transform(input, 
                                            new XsltArgumentList(), 
                                            xwriter);
                    }
                }

                return writer.ToString();
            }
        }

        private static XmlReader CreateXmlReader(TextReader reader, 
                                                 XmlResolver resolver)
        {
            var settings = new XmlReaderSettings
            {
                XmlResolver = resolver
            };

            var xreader = XmlReader.Create(reader, settings, (string)null);
            return xreader;
        }

        private static XmlWriter CreateXmlWriter(TextWriter writer)
        {
            var settings = new XmlWriterSettings
            {
                Indent = true,
                IndentChars = " ",
                NewLineChars = "\r\n"
            };

            var xwriter = XmlWriter.Create(writer, settings);
            return xwriter;
        } 
    }
}

但是,当我尝试使用XslCompiledTransform时,我得到一个例外:

System.Xml.Xsl.XslTransformException: 
    An error occurred while loading document 'data.xml'.

我用来尝试使用XslCompiledTransform进行转换的代码是:

namespace transform
{
    using System.IO;
    using System.Xml;
    using System.Xml.XPath;
    using System.Xml.Xsl;

    public class CompiledTransform
    {
        public string Transform(string xslt, string xml)
        {
            var resolver = new XmlStaticResolver();
            var xsltSettings = new XsltSettings(true, true);
            var transform = new XslCompiledTransform();
            using (var transformReader = CreateXmlReader(new StringReader(xslt), resolver))
            {
                transform.Load(transformReader, xsltSettings, resolver);
            }

            using (var writer = new StringWriter())
            {
                using (var xwriter = CreateXmlWriter(writer))
                {
                    using (var inputReader = new StringReader(xml))
                    {
                        var input = new XPathDocument(inputReader);
                        transform.Transform(input, 
                                            new XsltArgumentList(), 
                                            xwriter);
                    }
                }

                return writer.ToString();
            }
        }

        private static XmlReader CreateXmlReader(TextReader reader, 
                                                 XmlResolver resolver)
        {
            var settings = new XmlReaderSettings
            {
                XmlResolver = resolver
            };

            var xreader = XmlReader.Create(reader, settings, (string)null);
            return xreader;
        }

        private static XmlWriter CreateXmlWriter(TextWriter writer)
        {
            var settings = new XmlWriterSettings
            {
                Indent = true,
                IndentChars = " ",
                NewLineChars = "\r\n"
            };

            var xwriter = XmlWriter.Create(writer, settings);
            return xwriter;
        } 
    }
}

在我看来,使用编译后的转换,不会调用解析器。有谁知道为什么?

1 个答案:

答案 0 :(得分:0)

您正在将XmlStaticResolver resolver传递给 XmlReader.Create() XslCompiledTransform.Load()。在这两种情况下,您都会返回PersonXml / data.xml,即XML。但XslCompiledTransform.Load()使用Uris调用XmlStaticResolver.ResolveUri()来解析样式表,即.xslt个文件的路径。无论如何,我没有看到您希望将XmlStaticResolver resolver传递给正在阅读XSL的CreateXmlReader(new StringReader(xslt), resolver));我不知道它在旧代码中是如何工作的......

我认为您会发现错误System.Xml.Xsl.XslTransformException: An error occurred while loading document 'data.xml'.告诉您尝试加载data.xml作为样式表文档而不是XML文档时失败!< / p>

你说“在我看来,使用已编译的转换,没有调用解析器”,但假设您可以调试断点XmlStaticResolver.ResolveUri()并查看它的调用位置和参数。< / p>