Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET XSLT transformation, is this really streamed?

Tags:

c#

.net

stream

xslt

I have an XML that I need remove empty elements from. I am trying to avoid using the DOM and am 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"">");
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?

like image 401
Stan R. Avatar asked Jan 23 '23 12:01

Stan R.


2 Answers

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 it 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 file as an "embedded resource" and loaded with assembly.GetManifestResourceStream().

like image 123
ckarras Avatar answered Jan 26 '23 02:01

ckarras


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?

For example,

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();

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);
    }
}
like image 33
Cheeso Avatar answered Jan 26 '23 03:01

Cheeso