2017-02-03 13 views
4

Ich versuche ein Passwort in einer xml-Datei zu setzen, die über XSLT erzeugt wurde (mit Saxon-HE v9.7.0.14), indem ich einen globalen Parameter festlege.cdata-section-elements funktioniert nicht

Das Kennwort kann beliebige Zeichen enthalten, so dass es in einen Abschnitt CDATA eingefügt werden muss.

Ich versuche, dies zu erreichen, indem xsl:output Element das cdata-section-elements Attribut meines Xslt der Einstellung den Namen des Passworts Element aufzunehmen:

<xsl:output method="xml" indent="yes" cdata-section-elements="password"/> 

Das funktioniert nicht. Ich habe Beispielcode, Eingabe, xslt, aktuellen Ausgang und gewünschte Ausgabe darunter eingefügt.

Was muss ich ändern, um das Passwort in einem CDATA Abschnitt zu erhalten?

Programm:

using System; 
using System.IO; 
using Saxon.Api; 

namespace XsltTest { 
    class Program { 
     static void Main(string[] args) { 
      var xslt = new FileInfo(@"transform.xslt"); 
      var input = new FileInfo(@"input.xml"); 
      var output = new FileInfo(@"output.xml"); 
      var processor = new Processor(); 
      var compiler = processor.NewXsltCompiler(); 
      var executable = compiler.Compile(new Uri(xslt.FullName)); 
      var transformer = executable.Load(); 
      var destination = new DomDestination(); 
      using (var inputStream = input.OpenRead()) {    
       transformer.SetInputStream(inputStream, new Uri(Path.GetTempPath())); 
       transformer.SetParameter(
        new QName("password"), 
        new XdmAtomicValue("secret")); 
       transformer.Run(destination); 
      } 
      destination.XmlDocument.Save(output.FullName); 
     } 
    } 
} 

Transform.xslt:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> 
    <xsl:output method="xml" indent="yes" cdata-section-elements="password"/> 
    <xsl:param name="password" /> 
    <xsl:template match="@* | node()"> 
    <bar> 
     <username> 
     <xsl:value-of select="//username"/> 
     </username> 
     <password> 
     <xsl:value-of select="$password"/> 
     </password> 
    </bar> 
    </xsl:template> 
</xsl:stylesheet> 

Input.xml:

<?xml version="1.0" encoding="utf-8" ?> 
<foo> 
    <username>john</username> 
</foo> 

Output.xml:

<bar> 
    <username>john</username> 
    <password>secret</password> 
</bar> 

Das Passwort wird in einem CDATA Abschnitt nicht setzen.

Wunschergebnis:

<bar> 
    <username>john</username> 
    <password><![CDATA[secret]]></password> 
</bar> 

Antwort

1

Die Optionen unter xsl:output beeinflussen die Aktionen des Serialisierers, und wenn die Ausgabe nicht serialisiert ist, haben sie keine Auswirkungen. Sie schreiben nicht in einen Serializer, sondern in ein DomDestination-Objekt (und serialisieren das DOM dann mithilfe von DOM-Methoden, die nichts über die XSLT-Deklaration xsl: output wissen).

In jedem Fall ist Ihre Prämisse falsch: "Das Passwort kann beliebige Zeichen enthalten, so dass es in einen CDATA-Abschnitt eingefügt werden muss." Ohne cdata-section-elements werden Sonderzeichen mit Entity-Referenzen wie &lt; und &amp; serialisiert, was gut funktionieren sollte.

+0

Danke. Ich habe jetzt 'Serializer' anstelle von' DomDestination' verwendet und es funktioniert. Danke auch für den Kommentar zur Entitätscodierung ohne CDATA. Ich ersetze tatsächlich ein System, das bereits XML-Nachrichten mit dem Passwort in CDATA sendet, und das Team vor mir sagte, sie hätten Probleme, bevor sie CDATA verwenden. Wir haben keine Kontrolle über das externe System, das die Nachrichten liest, daher nahm ich an, dass das Problem nicht am Ende des XML-Codes funktionierte und ich weiß, dass es funktioniert, wenn CDATA verwendet wird. – Ergwun

+0

Das Generieren von XML für Leute, die es inkompetent analysieren, ist nur unwesentlich problematischer als das Lesen von (sogenanntem) XML, das von Leuten erstellt wird, die es inkompetent erzeugen - leider gibt es in unserem Beruf viel Inkompetenz. –

0

ich Ihren Code getestet und es scheint, richtig zu arbeiten.

Die Eingangsleitung

xsltproc --stringparam password "1>2Ä-34" Transform.xslt Input.xml 

gibt die gewünschte Ausgabe

<?xml version="1.0"?> 
<bar> 
    <username>john</username> 
    <password><![CDATA[1>2Ä-34]]></password> 
</bar> 

Haben Sie den Eingang des password Parameter an den XSLT-Prozessor verpassen die <xsl:param name="password" /> zu füttern?

+0

Ich bin nicht xsltproc verwenden. Ich verwende Saxon in einer C# -Anwendung wie im Beispielprogramm. – Ergwun

+0

Ja. Ich wusste. Aber es ist ähnlich: Übergeben Sie den String-Parameter "password" mit seinem Wert an die XSLT. Es sollte funktionieren, wie ich es in meiner Antwort beschrieben habe. Das leere '' auf der 'xsl: stylesheet' Ebene wird für solche Zwecke bestimmt. – zx485

0

Michael Kay's answer erklärten die Lösung, die, dass das cdata-section-elements Attribut nur anwendbar ist, wenn sie auf ein Serializer keine DomDestination zu schreiben.

Hier ist der C# -Code zu tun, dass:

static void Main(string[] args) { 
    var xslt = new FileInfo(@"transform.xslt"); 
    var input = new FileInfo(@"input.xml"); 
    var output = new FileInfo(@"output.xml"); 
    var processor = new Processor(); 
    var compiler = processor.NewXsltCompiler(); 
    var executable = compiler.Compile(new Uri(xslt.FullName)); 
    var transformer = executable.Load(); 
    var serializer = new Serializer(); 
    using (var writer = new StreamWriter(output.FullName)) 
    using (var inputStream = input.OpenRead()) { 
     serializer.SetOutputWriter(writer); 
     transformer.SetInputStream(inputStream, new Uri(Path.GetTempPath())); 
     transformer.SetParameter(
      new QName("password"), 
      new XdmAtomicValue("secret")); 
     transformer.Run(serializer); 
    } 
Verwandte Themen