cdata-section-elements无法正常工作

时间:2017-02-03 06:10:56

标签: c# xml xslt saxon

我试图通过设置全局参数在XSLT(使用Saxon-HE v9.7.0.14)生成的xml文件中设置密码。

密码可以包含任何字符,因此需要将其放在CDATA部分。

我正在尝试通过设置xslt' s cdata-section-elements元素的xsl:output属性来包含密码元素的名称来实现此目的:

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

这不起作用。我在下面列出了示例代码,输入,xslt,当前输出和所需的输出。

如果要在CDATA部分内获取密码,我需要更改哪些内容?

程序:

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>

密码不会放在CDATA部分内。

期望的结果:

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

3 个答案:

答案 0 :(得分:1)

xsl:output上的选项会影响序列化程序的操作,如果输出未序列化,则它们无效。您正在写一个DomDestination而不是一个Serializer(然后使用DOM方法序列化DOM,这些方法对XSLT xsl:output声明一无所知)。

在任何情况下,您的前提都是错误的:&#34;密码可以包含任何字符,因此需要将其放入CDATA部分。&#34;如果没有cdata-section-elements,特殊字符将使用&lt;&amp;等实体引用进行序列化,这应该可以正常工作。

答案 1 :(得分:0)

我测试了您的代码,它似乎工作正常。

输入行

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

返回所需的输出

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

您是否错过了password参数输入到XSLT处理器以提供<xsl:param name="password" />

答案 2 :(得分:0)

Michael Kay's answer解释了解决方案,即cdata-section-elements属性仅在写入Serializer而不是DomDestination时适用。

这是执行此操作的C#代码:

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);
    }