XML and XSLT transformation in ASP.NET MVC - XmlActionResult
In previous post I have written about HtmlHelper extensions for rendering XML in ASP.NET MVC. There are scenarios for which that approach is a little bit too much. For example, if all what we want to put in response is transformation result, we would have to make additional view to call our extension method. In such case it would be better to have dedicated ActionResult for XML transformation. So let's write one:
Complete class can be downloaded here. I hope someone will find it useful.
public class XmlActionResult: ActionResultWe will start by adding some necessary fields. Most of them will be also properties, but I will skip their code here (at the end you can find link to complete class).
{
...
}
public class XmlActionResult: ActionResultLet's also add a static contructor with some initialization logic:
{
#region Fields
private XmlDocument _xmlDocument;
private XPathNavigator _xpathNavigator;
private string _documentContent;
private string _documentSource;
private XslCompiledTransform _transform;
private static XslCompiledTransform _transparentTransform;
private string _transformSource;
private XsltArgumentList _transformArgumentList;
#endregion
...
}
public class XmlActionResult: ActionResultNow it's time for heart of our ActionResult class- the ExecuteResult method:
{
...
#region Constructor
static XmlActionResult()
{
XmlTextReader copyTransformReader = new XmlTextReader(new StringReader(
"<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:template match=\"/\">
<xsl:copy-of select=\".\"/>
</xsl:template>
</xsl:stylesheet>"));
_transparentTransform = new XslCompiledTransform();
_transparentTransform.Load(copyTransformReader);
}
#endregion
...
}
public class XmlActionResult: ActionResultThe XmlActionResult class is ready, so we can prepare a controller action which will use it:
{
...
#region
public override void ExecuteResult(ControllerContext context)
{
XPathDocument xpathDocument = null;
//Checking if we have been given XmlDocument or XPathNavigator directly,
if ((_xmlDocument == null) && (_xpathNavigator == null))
{
//Checking if we have document content
if (!String.IsNullOrEmpty(_documentContent))
{
StringReader documentReader = new StringReader(_documentContent);
xpathDocument = new XPathDocument(documentReader);
}
//Checking if we have path for document
else if (!String.IsNullOrEmpty(_documentSource) && (_documentSource.Trim().Length != 0))
{
//Checking if path is absolute or relative
if (!Path.IsPathRooted(_documentSource))
//Mapping the relative path
documentSource = context.HttpContext.Server.MapPath(_documentSource);
//Loading XML from file into XPathDocument
using (FileStream documentStream = new FileStream(_documentSource,
FileMode.Open, FileAccess.Read, FileShare.Read))
{
XmlTextReader documentReader = new XmlTextReader(documentStream);
xpathDocument = new XPathDocument(documentReader);
}
}
}
//Checking if we have been given XslCompiledTransform directly,
//or do we have path for transform
if ((_transform == null) &&
(!String.IsNullOrEmpty(_transformSource) && (_transformSource.Trim().Length != 0)))
{
//Checking if path is absolute or relative
if (!Path.IsPathRooted(_transformSource))
//Mapping the relative path
_transformSource = context.HttpContext.Server.MapPath(_transformSource);
//Loading XSLT from file into XslCompiledTransform
using (FileStream transformStream = new FileStream(_transformSource,
FileMode.Open, FileAccess.Read, FileShare.Read))
{
XmlTextReader tranformReader = new XmlTextReader(transformStream);
_transform = new XslCompiledTransform();
_transform.Load(tranformReader);
}
}
//Checking if we have XML in any form
if (((_xmlDocument != null) || (xpathDocument != null)) || (_xpathNavigator != null))
{
context.HttpContext.Response.ContentType = "text/html";
//Checking if we have XSLT
if (_transform == null)
//If not, let's use transparent one
_transform = _transparentTransform;
//Perform transformation based on form in which we have our XML
if (_xmlDocument != null)
_transform.Transform((IXPathNavigable)_xmlDocument, _transformArgumentList,
context.HttpContext.Response.Output);
else if (_xpathNavigator != null)
_transform.Transform(_xpathNavigator, _transformArgumentList,
context.HttpContext.Response.Output);
else
_transform.Transform((IXPathNavigable)xpathDocument, _transformArgumentList,
context.HttpContext.Response.Output);
}
}
#endregion
}
public ActionResult XmlResult()This is the result of our hard work:
{
XmlDocument cdCatalogDocument = new XmlDocument();
cdCatalogDocument.Load(Server.MapPath("~/App_Data/CDCatalog.xml"));
XmlActionResult result = new XmlActionResult();
result.Document = cdCatalogDocument;
result.TransformSource = Server.MapPath("~/Xslt/CDCatalog.xsl");
return result;
}
Complete class can be downloaded here. I hope someone will find it useful.