Ergwun
Ergwun

Reputation: 12978

cdata-section-elements not working

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

Answers (3)

Ergwun
Ergwun

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

Michael Kay
Michael Kay

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 &lt; and &amp;, which should work just fine.

Upvotes: 1

zx485
zx485

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

Related Questions