tags:

views:

376

answers:

5

In other words, is there a faster, more concise way of writing the following code:

//Create an object for performing XSTL transformations
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(HttpContext.Current.Server.MapPath("/xslt/" + xsltfile.Value), new XsltSettings(true, false), new XmlUrlResolver());

//Create a XmlReader object to read the XML we want to format
//XmlReader needs an input stream (StringReader)
StringReader sr = new StringReader(node.OuterXml);
XmlReader xr = XmlReader.Create(sr);

//Create a StringWriter object to capture the output from the XslCompiledTransform object
StringWriter sw = new StringWriter();

//Perform the transformation
xslt.Transform(xr, null, sw);

//Retrieve the transformed XML from the StringWriter object
string transformedXml = sw.ToString();

UPDATE (thanks for all the answers so far!):

Sorry for my vagueness: by "faster" and more "concise" I mean, am I including any unnecessary steps? Also, I would love a more "readable" solution if someone has one. I use this code in a small part of a web application I'm developing, and I'm about to move it to a large part of the application, so I want to make sure it's as neat as can be before I make the move.

Also, I get the XML from a static class (in a separate data access class library) which communicates with a database. I also manipulate the transformed XML string before shipping it off to a web page. I'm not sure if the input/response streams are still viable in this case.

One more thing: the XML and the XSLT supplied may change (users of the application can make changes to both), so I think I would be forced to compile each time.

+2  A: 

Since you mention ASP.NET, the question is whether you can use the response stream directly for your transform output and whether you can use the input stream directly if it is a POST...

flq
+3  A: 

If you have a large XSLT you can save the overhead of compiling it at runtime by compiling the XSLT into a .NET assembly when you build your project (e.g. as a post-build step). The compiler to do this is called xsltc.exe and is part of Visual Studio 2008.

In order to load such a pre-compiled XSLT you will need .NET Framework 2.0 SP1 or later installed on your server (the feature was introduced with SP1).

For an example check Anton Lapounov's blog article:

XSLTC — Compile XSLT to .NET Assembly

If pre-compiling the XSLT is not an option you should consider caching the XslCompiledTransform after it is loaded so that you don't have to compile it everytime you wnat to execute the transform.

0xA3
+3  A: 

Here's code I did for my ASP.NET, which is very similar to yours:

  XDocument xDoc = XDocument.Load("output.xml");

        XDocument transformedDoc = new XDocument();
        using (XmlWriter writer = transformedDoc.CreateWriter())
        {
            XslCompiledTransform transform = new XslCompiledTransform();
            transform.Load(XmlReader.Create(new StreamReader("books.xslt")));
            transform.Transform(xDoc.CreateReader(), writer);
        }

        // now just output transformedDoc
Jim Schubert
A: 

I'd rewrite the code like this:

string path = HttpContext.Current.Server.MapPath("/xslt/" + xsltfile.Value);
XmlReader reader = CreateXmlReader(node.OuterXml);
string transformedXml = Transform(path, reader);

private XmlReader CreateXmlReader(string text)
{
    StringReader reader = new StringReader(text);
    return XmlReader.Create(reader);
}

private string Transform(string xsltPath, XmlReader source)
{
    XsltCompiledTransform transformer = new XsltCompiledTransform();
    transformer.Load(
        xsltPath, 
        new XsltSettings(true, false), 
        new XmlUrlResolver());

    StringWriter writer = new StringWriter();
    transformer.Transform(source, null, writer);
    return writer.ToString();
}

The reason why I'd rewrite the code like this is because each block of code now has one and only one purpose. This makes it easier to read and understand. Additionally, the code requires less comments because a lot of information can be inferred from the names of the function and its parameters.

Lee
-1 for no using statements.
John Saunders
@John What in my code needs deterministic disposal? If I were working with disk files, then I could understand placing a using statement around the creation of the XmlReader ... but in this case we're not so I felt that letting the garbage collector handle it would be fine.
Lee
+1 for readability; thanks for your help. I have a separate "XMLHelper" class with some common utilities I'm using throughout the web application; these methods might integrate quite nicely in there.
attack
Anything you create that implements `IDisposable` needs to be disposed.
John Saunders
+2  A: 

Don't have time to do a full example, but some notes:

  1. XML is not the same as System.String. Get it from the class library as XDocument or XmlDocument; finish with it as XDocument or XmlDocument.
  2. You can use the ASP.NET Cache to store the compiled XSL, with a cache dependency on when the .XSLT file changes.
  3. Don't convert the XML to a string then back to XML. Use node.CreateNavigator().ReadSubTree().
  4. Similarly, use XPathNavigator.AppendChild to get an XmlWriter that will write into an XML Document.
John Saunders
Thanks for the tips, but sorry, I'm a little confused. I'm converting from XML to a string and then putting that directly onto a page. I'm not converting back into XML nor am I altering any XML. You mentioned that I should avoid strings altogether; if I need to plant transformed XML directly onto a web page is there a way to do that without converting to a string?
attack
How are you "planting" the XML into the web page? Instead, use `XmlDocument.WriteTo(Response.OutputStream)` or the equivalent.
John Saunders