我正在尝试使用自定义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;
}
}
}
在我看来,使用编译后的转换,不会调用解析器。有谁知道为什么?
答案 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>