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?
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:
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()
.
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With