Reputation: 12978
I am trying to set a password in an xml file generated via XSLT (using Saxon-HE v9.7.0.14), by setting a global parameter.
The password can contain any characters so it needs to be put in a CDATA
section.
I am trying to achieve this by setting the cdata-section-elements
attribute of my xslt's xsl:output
element to include the name of the password element:
<xsl:output method="xml" indent="yes" cdata-section-elements="password"/>
This is not working. I have included example code, input, xslt, current output and desired output below.
What do I need to change to get the password inside a CDATA
section?
Program:
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>
The password is not put inside a CDATA
section.
Desired result:
<bar>
<username>john</username>
<password><![CDATA[secret]]></password>
</bar>
Upvotes: 4
Views: 2181
Reputation: 12978
Michael Kay's answer explained the solution, which was that the cdata-section-elements
attribute is only applicable when writing to a Serializer
not a DomDestination
.
Here's the C# code for doing that:
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);
}
Upvotes: 0
Reputation: 163322
The options on xsl:output
affect the actions of the serializer, and if the output is not serialized, they have no effect. You are writing to a DomDestination rather than to a Serializer (and then serializing the DOM using DOM methods, which know nothing about the XSLT xsl:output declaration).
In any case your premise is wrong: "The password can contain any characters so it needs to be put in a CDATA section." Without cdata-section-elements, special characters will be serialized using entity references such as <
and &
, which should work just fine.
Upvotes: 1
Reputation: 29022
I tested your code and it appears to be working correctly.
The input line
xsltproc --stringparam password "1>2Ä-34" Transform.xslt Input.xml
returns the desired output
<?xml version="1.0"?>
<bar>
<username>john</username>
<password><![CDATA[1>2Ä-34]]></password>
</bar>
Did you miss the input of the password
parameter to the XSLT processor to feed the <xsl:param name="password" />
?
Upvotes: 0