1

我正在动态创建一个 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 编译错误。知道吗?

4

2 回答 2

1

这是对我有用的方法。

我不会使用 XmlWriter->MemoryStream->XmlReader,而是使用XElementMicrosoft 在 .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,我们可以控制编码。

为了完整起见,这里是我的CreateInputXmlCreateTransformXslt方法的代码。它们只是例子。当然,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();
    }
}
于 2012-10-05T04:08:46.253 回答
0

正如评论中提到的@kevin,以下解决了我的问题,但我不太确定它为什么会起作用(有一些想法,但不确定)

在 xmlt_stream.Seek(0, SeekOrigin.Begin); 之前添加 objXMLTWriter.Flush()

于 2012-10-09T17:05:17.547 回答