我正在动态创建一个xslt和xml文件来显示我的问卷&保存我的问题选项(用于下拉列表)。现在我想使用流而不是在实际文件上写。所以我就是这样做的:
XmlReader xslt_reader;
XmlReader xml_reader;
PageLoad(){
Fn_CreateXSL();
Fn_CreateXML();
LoadQuestionnaire();
}
Fn_CreateXSL(){
xslt_stream = new MemoryStream();
XmlTextWriter objXSLTWriter = new XmlTextWriter(xslt_stream, Encoding.UTF8);
objXSLTWriter.Formatting = Formatting.Indented;
objXSLTWriter.WriteStartDocument();
..........
objXSLTWriter.WriteEndDocument();
xslt_stream.Seek(0, SeekOrigin.Begin);
xslt_reader = XmlReader.Create(xslt_stream);
}
Fn_CreateXML(){
xmlt_stream = new MemoryStream();
XmlTextWriter objXMLTWriter = new XmlTextWriter(xmlt_stream, Encoding.UTF8);
objXMLTWriter.Formatting = Formatting.Indented;
objXMLTWriter.WriteStartDocument();
..........
objXMLTWriter.WriteEndDocument();
xmlt_stream.Seek(0, SeekOrigin.Begin);
xmlt_reader = XmlReader.Create(xmlt_stream);
}
LoadQuestionnaire(){
XslCompiledTransform var_xsl_trans = new XslCompiledTransform();
// also tried var_xsl_trans.Load(xslt_reader, null, new XmlUrlResolver());
var_xsl_trans.Load(xslt_reader); // XSLT Compile Error occurs
StringWriter sw = new StringWriter();
var_xsl_trans.Transform(xml_reader, null, sw);
}
但是当我尝试加载它时,我得到“XSLT编译错误。有什么想法吗?
答案 0 :(得分:1)
这是适合我的方法。
我将使用Microsoft引入的XElement
和.NET 3.5中的LINQ,而不是使用XmlWriter-> MemoryStream-> XmlReader。 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作为输出。我认为StringFriter强加了UTF-16,因为底层字符串每个字符有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中使用xsl:strip-space elements="*"
。上面评论过。这是因为当输入xml作为XslCompiledTransform
传递时,IXPathNavigable
在删除空间方面存在问题。在错误消息中,如果我需要剥离,则建议使用XmlReader
。我不认为剥离空间对于生成网页很重要。
最后,这里是开头提到的转换器类:
class XNavigable : IXPathNavigable
{
XElement _xElement;
public XNavigable(XElement xElement)
{
_xElement = xElement;
}
public XPathNavigator CreateNavigator()
{
return _xElement.CreateNavigator();
}
}
答案 1 :(得分:0)
正如@kevin在评论中提到的,以下问题解决了我的问题,但我不太清楚为什么它有效(有一些想法,但不确定)
在xmlt_stream.Seek(0之前添加objXMLTWriter.Flush() SeekOrigin.Begin);