这是对我有用的方法。
我不会使用 XmlWriter->MemoryStream->XmlReader,而是使用XElement
Microsoft 在 .NET 3.5 中通过 LINQ 引入的。Load
类的和Transform
方法都有XslCompiledTransform
重载,这些重载IXPathNavigable
作为参数传递 XML。这个接口只有一个方法XPathNavigator CreateNavigator()
,XElement
有这样的方法。我不知道为什么微软没有声明XElement
实现这个接口。可能他们忘记了:-)。所以,为了弥补这个疏忽,我实现了 6 线转换器类XNavigable
。你会在下面看到它。这是 OP 的 Page_Load() 的模拟:
public void Generate()
{
XElement inputXml = CreateInputXml();
XElement transformXslt = CreateTransformXslt();
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load(new XNavigable(transformXslt), null, null);
MemoryStream outputStream = new MemoryStream();
transform.Transform(new XNavigable(inputXml), null, outputStream);
byte[] outputBytes = outputStream.ToArray();
string outputString = Encoding.UTF8.GetString(outputBytes);
}
我使用MemoryStream
而不是StringWriter
因为 StringWriter 总是为我创建 UTF-16 编码的 XML 作为输出。我认为 UTF-16 是由 StringWriter 强加的,因为底层字符串每个字符有 16 位。使用 MemoryStream,我们可以控制编码。
为了完整起见,这里是我的CreateInputXml
和CreateTransformXslt
方法的代码。它们只是例子。当然,XElement.Add()
可以使用方法来生成内容。我只是使用其中列出了所有节点的构造函数来快速进行硬编码。
private static XElement CreateTransformXslt()
{
//XSL to substitute <placeholder/> with <realElement/> and copy everything else.
//<stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform">
// <output indent="yes" />
// <template match="@* | node()">
// <copy>
// <apply-templates select="@* | node()" />
// </copy>
// </template>
// <template match="placeholder">
// <realElement xmlns="" />
// </template>
//</stylesheet>
XNamespace xsl = "http://www.w3.org/1999/XSL/Transform";
XNamespace empty = "";
XElement transformXslt = new XElement(xsl + "stylesheet", new XAttribute("version", "1.0"),
new XElement(xsl + "output", new XAttribute("indent", "yes")),
//new XElement(xsl + "strip-space", new XAttribute("elements", "*")),
new XElement(xsl + "template", new XAttribute("match", "@* | node()"),
new XElement(xsl + "copy",
new XElement(xsl + "apply-templates", new XAttribute("select", "@* | node()"))
)
),
new XElement(xsl + "template", new XAttribute("match", "placeholder"),
new XElement("realElement")
)
);
return transformXslt;
}
private static XElement CreateInputXml()
{
XElement origXml = new XElement(new XElement("Root",
new XElement("Child1", "data1"),
new XElement("placeholder"),
new XElement("Child2", "data2")));
return origXml;
}
上面代码中的一个问题是我们不应该xsl:strip-space elements="*"
在 XSL 中使用。上面有评论。这是因为XslCompiledTransform
当输入 xml 作为IXPathNavigable
. 在一条错误消息中,XmlReader
如果我需要剥离,它建议使用。我认为剥离空间对于生成网页并不重要。
最后,这里是开头提到的转换器类:
class XNavigable : IXPathNavigable
{
XElement _xElement;
public XNavigable(XElement xElement)
{
_xElement = xElement;
}
public XPathNavigator CreateNavigator()
{
return _xElement.CreateNavigator();
}
}