0

I've created a custom HTMLHelper which is supposed to render parsed XML. The method takes the XML and the path to an XSL file and should return HTML.

When I access the page, I get the error

XmlException: For security reasons DTD is prohibited in this XML document. To enable DTD processing set the DtdProcessing property on XmlReaderSettings to Parse and pass the settings into XmlReader.Create method.

As you can see in my code below, I'm setting DtdProcessing toParse in the XmlReaderSettings (as the exception suggests), which I thought would resolve the issue. On closer inspection, the exception is occurring at the line:

transformObj.Load(xsltPath);

But I can't see how I can pass XmlReaderSettings to that method so as to set the DtdProcessing property. The only overloads of XslCompiledTransform.Load which accept a settings object expect a XsltSettings object, which doesn't have a DtdProcessing property.

The full method is as follows:

public static IHtmlContent RenderXml(this IHtmlHelper htmlHelper, string xml, string xsltPath)
{
    XsltArgumentList args = new XsltArgumentList();
    // Create XslCompiledTransform object to load and compile XSLT file.  
    XslCompiledTransform transformObj = new XslCompiledTransform();
    transformObj.Load(xsltPath);

    // Create XMLReaderSetting object to assign DtdProcessing, Validation type  
    XmlReaderSettings xmlSettings = new XmlReaderSettings();
    xmlSettings.DtdProcessing = DtdProcessing.Parse;
    xmlSettings.MaxCharactersFromEntities = 1024; // Prevent DoS attacks
    xmlSettings.ValidationType = ValidationType.DTD;

    // Create XMLReader object to Transform xml value with XSLT setting
    XmlReader reader = XmlReader.Create(new StringReader(xml), xmlSettings);

    using (reader)
    {
        StringWriter writer = new StringWriter();
        transformObj.Transform(reader, args, writer);

        // Generate HTML string from StringWriter  
        HtmlString htmlString = new HtmlString(writer.ToString());
        return htmlString;
    }
}

And in my view I'm using:

@Html.RenderXml(ViewBag.XML as string, ViewBag.XSL as string);

I've reviewed the advice in the answers to this question but as far as I can tell I've already taken the steps suggested. The accepted answer to this MSDN question seems to hint at an answer but I haven't been able to work out how to make use of it.

Philip Stratford
  • 4,513
  • 4
  • 45
  • 71

1 Answers1

2

If the XSLT uses or references a DTD, pass an XmlReader with the necessary XmlReaderSettings to the Load method, i.e. use the overload https://learn.microsoft.com/en-us/dotnet/api/system.xml.xsl.xslcompiledtransform.load?view=netframework-4.8#System_Xml_Xsl_XslCompiledTransform_Load_System_Xml_XmlReader_ with

using (XmlReader xsltReader = XmlReader.Create(xsltPath, new XmlReaderSettings() { DtdProcessing = DtdProcessing.Parse }))
{
  transformObj.Load(xsltReader);
}
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • Thanks Martin, that's what I was missing - that there was an overload that accepted a `XmlReader` parameter. Fourteen years on from that MSDN answer and you're still helping people out with XSL transformations! – Philip Stratford Mar 25 '20 at 22:58