[deprecated] XslTransform wird zu XslCompiledTransform -> Umstellungsprobleme
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.