[deprecated] XslTransform wird zu XslCompiledTransform -> Umstellungsprobleme

Published Mittwoch, 2. Juni 2010 02:59
Mit unserer Umstellung auf das neue Framework habe ich mich mit dem Problem beschäftigt, dass XslTransform veraltet ist. Die Anweisung, dass nun XslCompiledTransform zu verwenden ist, ist zwar schön und gut, aber wir stießen dabei auf 2 markante Probleme:

Fehler 1:
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.

Fehler 2:
The 'xsl:stylesheet' element is not declared.

Im Folgenden erkläre ich nun Schritt für Schritt, worin die Probleme lagen. Hierfür soll folgendes Ausgangsszenario gelten:

Ausgangssituation:

Gegeben sei folgender Quellcode:
        static void Main(string[] args)
        {
            XPathDocument doc = new XPathDocument("PocTest1_log.xml");
            StreamWriter swriter = new StreamWriter("PocTest1_log.html");

            XslTransform trans = new XslTransform();
            trans.Load("XSLTFile1.xslt");
            trans.Transform(doc, null, swriter);
        }

dabei ist das zu transformierende Dokument "PocTest1_log.xml" erst einmal unwichtig, es enthält ein valides und vollständiges Xml DOM Objekt.
Interessant ist das XSLT Stylesheet, das für eine Transformation zu einem HTML Dokument verwendet werden soll. Die Besonderheit ist, dass dieses einen DTD Teil definiert, also eine Entity mit definiert. Zu Demozwecken, und damit den Fehler zu provozieren, genügt folgendes Dummy Stylesheet:
<!DOCTYPE xsl:stylesheet [ <!ENTITY jquerysrc SYSTEM 'test.js'> ]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Wenn nun der o.g. Code ausgeführt wird läuft alles zunächst wunderbar, außer, dass die Warnung XslTransform ist deprecated ausgegeben wird.

Umstellung auf XslCompiledTransform Schritt 1:

Eine Umstellung auf XslCompiledTransform ergibt zunächst folgender Code:
        static void Main(string[] args)
        {
            XPathDocument doc = new XPathDocument("PocTest1_log.xml");
            StreamWriter swriter = new StreamWriter("PocTest1_log.html");

            XslCompiledTransform trans = new XslCompiledTransform();
            trans.Load("XSLTFile1.xslt");
            trans.Transform(doc, null, swriter);
        }

Die Laufzeit ergibt den o.g. Fehler 1 (Zeile trans.Load): "For security reasons DTD is prohibited in this XML document ..."

Umstellung auf XslCompiledTransform Schritt 2 (Lösung zu Schritt 1):

Im Netz findet sich hier die bereits etablierte Lösung, dass man mittels einem XmlReader und der darin enthaltenen Möglichkeit XmlReaderSettings mitzugeben die Lösung enthalten sei:
        static void Main(string[] args)
        {
            XPathDocument doc = new XPathDocument("PocTest1_log.xml");
            StreamWriter swriter = new StreamWriter("PocTest1_log.html");

            XmlReaderSettings xmlReadSet = new XmlReaderSettings();
            xmlReadSet.ValidationType = ValidationType.DTD;
            xmlReadSet.DtdProcessing = DtdProcessing.Parse;

            XslCompiledTransform trans = new XslCompiledTransform();
            trans.Load(XmlReader.Create("XSLTFile1.xslt", xmlReadSet));
            trans.Transform(doc, null, swriter);
        }

Übrigens, die Eigenschaft XmlReaderSettings.ProhibitDtd ist ebenso veraltet, hierzu kann man wie im Code angegeben die Eigenschaft XmlReaderSettings.DtdProcessing verwenden.

Die Laufzeit ergibt allerdings den o.g. Fehler 2 (Zeile trans.Load): "The 'xsl:stylesheet' element is not declared."

Diese Fehlermeldung ist alles andere als selbsterklärend, und total irreführend. Ich habe lange herumgespielt, aber im Netz war nichts zu finden, und auch ein intensives Debugging brachte leider keine Lösung. Ich habe nur folgende Erkenntnisse gehbt (zunächst):
- Entfernung des DTD (DOCTYPE Knoten) -> Code funktioniert
- Verwendung von XsltSettings mit diversen Einstellmöglichkeiten (z.B. TrustedXslt) -> keine Veränderung, Code funktioniert nicht
- XsltArgumentList kann nicht verwendet werden, da das Problem schon bei Load auftritt, nicht erst bei Transform
- ...

Umstellung auf XslCompiledTransform vollständige Lösung:
Ich weiß nicht warum ich versucht habe noch einmal mit den XmlReaderSettings herumzuspielen, aber die Änderung des ValidationType brachte dann die funktionierende Lösung:
        static void Main(string[] args)
        {
            XPathDocument doc = new XPathDocument("PocTest1_log.xml");
            StreamWriter swriter = new StreamWriter("PocTest1_log.html");

            XmlReaderSettings xmlReadSet = new XmlReaderSettings();
            xmlReadSet.DtdProcessing = DtdProcessing.Parse;
            xmlReadSet.ValidationType = ValidationType.Schema;

            XslCompiledTransform trans = new XslCompiledTransform();
            trans.Load(XmlReader.Create("XSLTFile1.xslt", xmlReadSet));
            trans.Transform(doc, null, swriter);
        }

So ganz kann ich die Fehlermeldung nicht nachvollziehen, ich wüsste nicht, wenn ich das Stylesheet als DTD behandle, was darin syntaktisch verkehrt wäre, und warum eine Validierung fehlschlägt, aber eine Umstellung auf Schema brachte dann schlußendlich die Lösung.
von Timo Rehl

Kommentare

Keine Kommentare

Kommentar abgeben

(verpflichtend) 
(verpflichtend) 
(optional)
(verpflichtend)