cdata-section-elements 不工作
cdata-section-elements not working
我正在尝试通过设置全局参数在通过 XSLT(使用 Saxon-HE v9.7.0.14)生成的 xml 文件中设置密码。
密码可以包含任何字符,因此需要放在 CDATA
部分。
我试图通过设置我的 xslt xsl:output
元素的 cdata-section-elements
属性来包含密码元素的名称来实现此目的:
<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>
我测试了你的代码,它似乎工作正常。
输入行
xsltproc --stringparam password "1>2Ä-34" Transform.xslt Input.xml
returns 期望的输出
<?xml version="1.0"?>
<bar>
<username>john</username>
<password><![CDATA[1>2Ä-34]]></password>
</bar>
您是否错过了将 password
参数输入到 XSLT 处理器以提供给 <xsl:param name="password" />
?
xsl:output
上的选项会影响序列化程序的操作,如果输出未序列化,则它们无效。您正在写入 DomDestination 而不是 Serializer(然后使用 DOM 方法序列化 DOM,该方法对 XSLT xsl:output 声明一无所知)。
无论如何你的前提是错误的:"The password can contain any characters so it needs to be put in a CDATA section." 如果没有 cdata-section-elements,特殊字符将使用 <
和 &
等实体引用进行序列化,这应该有效就好了。
解释了解决方案,即 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);
}
我正在尝试通过设置全局参数在通过 XSLT(使用 Saxon-HE v9.7.0.14)生成的 xml 文件中设置密码。
密码可以包含任何字符,因此需要放在 CDATA
部分。
我试图通过设置我的 xslt xsl:output
元素的 cdata-section-elements
属性来包含密码元素的名称来实现此目的:
<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>
我测试了你的代码,它似乎工作正常。
输入行
xsltproc --stringparam password "1>2Ä-34" Transform.xslt Input.xml
returns 期望的输出
<?xml version="1.0"?>
<bar>
<username>john</username>
<password><![CDATA[1>2Ä-34]]></password>
</bar>
您是否错过了将 password
参数输入到 XSLT 处理器以提供给 <xsl:param name="password" />
?
xsl:output
上的选项会影响序列化程序的操作,如果输出未序列化,则它们无效。您正在写入 DomDestination 而不是 Serializer(然后使用 DOM 方法序列化 DOM,该方法对 XSLT xsl:output 声明一无所知)。
无论如何你的前提是错误的:"The password can contain any characters so it needs to be put in a CDATA section." 如果没有 cdata-section-elements,特殊字符将使用 <
和 &
等实体引用进行序列化,这应该有效就好了。
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);
}