tags:

views:

1072

answers:

2

Hi. I have an XML that I need remove empty elements from, I am trying to avoid using DOM and trying to do this as streams. I have this code, but I am not entirely sure how correct and optimized this is.

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""&gt;");
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();

is this a good way to do it? looking for any input. thanks.

+3  A: 

Yes you are using streams, but you are losing one of the benefits of streams: not loading the whole XML input and output in memory at once.

This is perfectly fine for very small XML documents, but can lead to very high memory usage for large documents.

A solution would be to avoid StringReader/StringWriter, and instead use an appropriate stream implementation depending on where the XML should be read from and sent. For example:

  • if you want to transform to/from an XML file, use FileStreams
  • if you are sending over a socket/http connection, use a Stream provided by your connection object

Also, loading the XSLT from embedded strings is usually not a good idea (harder to maintain), but I don't think it would cause performance problems (unless the XSLT is really huge). For better maintainability, I would recommend storing the XSLT in another file. The file can either be loaded from the filesystem (with a FileStream), or it can also be stored inside the compiled dll as an "embedded resource" and loaded with assembly.GetManifestResourceStream()

ckarras
good point about using FileStreams, my problem is the XML i receive is an XML coming from COM, so its coming in as String. I would love to use real streams, but I dont have that option.
Stan R.
+1  A: 

Why are you using a StringBuilder to build that xsl text? If the xsl is fixed, why not just leave it as a constant string? eg

string xslt = 
    @"<?xml version=""1.0"" encoding=""UTF-8""?>" +
     "<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""&gt;" +
     "<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();

Also, if it were me I would be putting a using() clause around the xmlReader and xmlWriter. I think they are disposable. eg,

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);
    }
}
Cheeso
good point about using Using ;). Definitely feels like much cleaner and safer code, especially if there is an exception it makes sure the readers are disposed.
Stan R.