代码之家  ›  专栏  ›  技术社区  ›  Stan R.

.NET XSLT转换,这真的是流式传输吗?

  •  3
  • Stan R.  · 技术社区  · 16 年前

    我有一个XML,需要从中删除空元素。我试图避免使用DOM,并尝试将其作为流进行。我有这段代码,但我不完全确定这段代码有多正确和优化。

    StringBuilder xslt = new StringBuilder();
    xslt.Append(@"<?xml version=""1.0"" encoding=""UTF-8""?>");
    xslt.Append(@"<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"">");
    xslt.Append(@"<xsl:output method=""xml"" version=""1.0"" encoding=""UTF-8"" indent=""yes""/>");
    xslt.Append(@"<xsl:template match=""*"">");
    xslt.Append(@"<xsl:if test=""count(@*) > 0 or count(node()) > 0"">");
    xslt.Append(@"<xsl:copy>");
    xslt.Append(@"<xsl:apply-templates select=""@* | node()""/>");
    xslt.Append(@"</xsl:copy>");
    xslt.Append(@"</xsl:if>");
    xslt.Append(@"</xsl:template>");
    xslt.Append(@"<xsl:template match=""@* | text()"">");
    xslt.Append(@"<xsl:copy/>");
    xslt.Append(@"</xsl:template>");
    xslt.Append(@"</xsl:stylesheet>");
    
    StringBuilder resultString = new StringBuilder();
    XmlTextWriter xmlWriter = new XmlTextWriter(new StringWriter(resultString));
    XmlTextReader xmlReader = new XmlTextReader(new StringReader(xmlString));
    
    System.Xml.Xsl.XslCompiledTransform xslTransform = new System.Xml.Xsl.XslCompiledTransform();
    xslTransform.Load(new XmlTextReader(new StringReader(xslt.ToString())));
    xslTransform.Transform(xmlReader, xmlWriter);
    xmlReader.Close();
    
    xmlWriter.Flush();
    xmlWriter.Close();
    

    这是个好方法吗?

    2 回复  |  直到 8 年前
        1
  •  6
  •   Peter Mortensen Pieter Jan Bonestroo    8 年前

    是的,您使用的是流,但您正在失去流的一个好处:不能一次将整个XML输入和输出加载到内存中。

    对于非常小的XML文档来说,这是非常好的,但是对于大型文档,这可能会导致非常高的内存使用率。

    一种解决方案是避免使用StringReader/StringWriter,而是根据从何处读取和发送XML来使用适当的流实现。例如:

    • 如果要转换为XML文件或从XML文件转换为XML文件,请使用文件流。
    • 如果通过socket/http连接发送,请使用连接对象提供的流。

    另外,从嵌入的字符串加载XSLT通常不是一个好主意(更难维护),但我认为它不会导致性能问题(除非XSLT真的很大)。为了更好地维护,我建议将XSLT存储在另一个文件中。该文件可以从文件系统加载(使用文件流),也可以作为“嵌入资源”存储在已编译的dll文件中,并使用 assembly.GetManifestResourceStream() .

        2
  •  3
  •   Peter Mortensen Pieter Jan Bonestroo    8 年前

    为什么使用StringBuilder来构建XSL文本?如果XSL是固定的,为什么不将其保留为常量字符串呢?

    例如,

    string xslt =
        @"<?xml version=""1.0"" encoding=""UTF-8""?>" +
         "<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"">" +
         "<xsl:output method=""xml"" version=""1.0"" encoding=""UTF-8"" indent=""yes""/>" +
         "<xsl:template match=""*"">" +
         "<xsl:if test=""count(@*) > 0 or count(node()) > 0"">" +
         "<xsl:copy>" +
         "<xsl:apply-templates select=""@* | node()""/>" +
         "</xsl:copy>" +
         "</xsl:if>" +
         "</xsl:template>" +
         "<xsl:template match=""@* | text()"">" +
         "<xsl:copy/>" +
         "</xsl:template>" +
         "</xsl:stylesheet>";
    
    
    StringBuilder resultString = new StringBuilder();
    XmlTextWriter xmlWriter = new XmlTextWriter(new StringWriter(resultString));
    XmlTextReader xmlReader = new XmlTextReader(new StringReader(xmlString));
    
    System.Xml.Xsl.XslCompiledTransform xslTransform = new System.Xml.Xsl.XslCompiledTransform();
    xslTransform.Load(new XmlTextReader(new StringReader(xslt)));
    xslTransform.Transform(xmlReader, xmlWriter);
    xmlReader.Close();
    
    xmlWriter.Flush();
    xmlWriter.Close();
    

    另外,如果是我,我将在xmlReader和xmlWriter周围放置using()子句。我想它们是一次性的。如,

    StringBuilder resultString = new StringBuilder();
    using (XmlTextWriter xmlWriter = new XmlTextWriter(new StringWriter(resultString)))
    {
        using (XmlTextReader xmlReader = new XmlTextReader(new StringReader(xmlString)))
        {
            System.Xml.Xsl.XslCompiledTransform xslTransform = new System.Xml.Xsl.XslCompiledTransform();
            xslTransform.Load(new XmlTextReader(new StringReader(xslt)));
            xslTransform.Transform(xmlReader, xmlWriter);
        }
    }