【问题标题】:How to include CDATA when writing Saxon's XdmNode to Stream in C#在 C# 中将 Saxon 的 XdmNode 写入 Stream 时如何包含 CDATA
【发布时间】:2015-07-21 08:47:19
【问题描述】:

我有一个由转换生成的 XdmNode 对象,我需要将其写入包含一些 CDATA 的流,但我无法获得包含 CDATA 转义的输出。

这是因为我没有经历序列化过程,例如,使用 Serializer 类吗?如果是这样,我该怎么做?我可以看到 Serializer 类在 Java 中有一个 serializeNode() 方法,但在 C# 中没有……只有转换/等似乎能够“使用”它。或者这是 cdata-section-elements 语句的问题?

使用这里的 XML 和 XSLT 来说明: How do I force xslt transformation to load data into cdata sections?

这在 C# 中使用 .NET 4.5 和 Saxon 9.6.0.6。

C#代码:

Processor processor = new Processor();
XdmNode node = GetNode(processor);  //gets XdmNode for XML doc below
XsltTransformer transformer = GetTransformer(processor);  //gets transform below

transformer.InitialContextNode = node;
XdmDestination output = new XdmDestination();
transformer.Run(output);
string results = output.XdmNode.OuterXml;

using (XmlWriter writer = XmlWriter.Create(Console.Out))
{
    output.XdmNode.WriteTo(writer);
}

XSLT:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"
  cdata-section-elements="num"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

XML:

<nums>
  <num>01</num>
  <num>02</num>
  <num>03</num>
  <num>04</num>
  <num>05</num>
  <num>06</num>
  <num>07</num>
  <num>08</num>
  <num>09</num>
  <num>10</num>
</nums>

预期输出:

<nums>
   <num><![CDATA[01]]></num>
   <num><![CDATA[02]]></num>
   <num><![CDATA[03]]></num>
   <num><![CDATA[04]]></num>
   <num><![CDATA[05]]></num>
   <num><![CDATA[06]]></num>
   <num><![CDATA[07]]></num>
   <num><![CDATA[08]]></num>
   <num><![CDATA[09]]></num>
   <num><![CDATA[10]]></num>
</nums>

实际输出(在控制台和字符串中):

<nums>
    <num>01</num>
    <num>02</num>
    <num>03</num>
    <num>04</num>
    <num>05</num>
    <num>06</num>
    <num>07</num>
    <num>08</num>
    <num>09</num>
    <num>10</num>
</nums>

【问题讨论】:

  • 您是否因为其他原因需要XdmDestination?或者您是否正在寻找一种方法来编写包含 CDATA 部分和其他由 xsl:output 定义的选项的文件?在这种情况下,请使用 saxonica.com/html/documentation/dotnetdoc/Saxon/Api/… 而不是 XdmDestination。
  • @Martin - 是的,由于其他原因,我们需要转换来创建 XdmNode(与往常一样,上面代码背后的真正问题要复杂得多)。如果有帮助:我们的代码库的一部分进行各种转换并与 XdmNodes 一起使用,另一部分有时会采用其中的一些并将 XdmNodes 写入流(通过 HTTP)。这是我们遇到问题的后一个领域 - 接收端(并不总是在我们的控制范围内)没有看到它应该在的 CDATA 标记(只是 XML)(在上面重新创建,所以我们认为它是流输出而不是读入) .
  • XdmNode 表示的 XSLT/XPath/XQuery 数据模型不知道任何 CDATA 部分,因此当您的转换创建 XdmNodes 时,它们不包含任何 CDATA 部分,因为这是序列化级别上的语法糖,即未在节点的树模型中表示。
  • 啊。那就是我出错的地方-谢谢。 net.sf.saxon.s9api 中有第二个序列化程序类(我上面提到的那个在 Saxon.Api 命名空间中),它似乎支持设置输出属性(例如,cdata-section-elements),写入流,并且有 serializeNode(XdmNode node) 方法 - 这是正确的路径吗?如果是这样,是否有人对将.NET 流与该序列化程序接受的(可能)IKVM 的 java.io.Stream 类一起使用有任何提示? (这应该是一个单独的 SO 问题吗?)
  • 抱歉,我认为您必须等到 Michael Kay 或 Saxonica 的其他人出现才能回答这个问题。

标签: c# xslt transform cdata saxon


【解决方案1】:

看来您想要做的是将 XdmNode 发送到 Serializer 以使用在 Serializer 上设置的属性对其进行序列化。最简单的方法可能是运行一个虚拟查询:

QueryCompiler qc = Processor.NewQueryCompiler();
QueryEvaluator qe = qc.Compile(".").Load();
qe.ContextItem = xdmNode;
qe.Run(serializer);

XQuery 表达式“.”只返回上下文项。

顺便说一下,Serializer 的 API 文档没有说明 CDATA_SECTION_ELEMENTS 属性应该采用什么形式,但我认为它可能是 Clark 表示法中的 QName 的空格分隔序列,即Q{uri}local。如果没有命名空间,则仅使用本地名称。

(这类似于 Java JAXP 接口中经常使用的运行“身份转换”的方法。但身份查询要简单得多。)

【讨论】:

  • 谢谢 - 我们也在考虑身份转换;很高兴知道有一个更简单的选择。
猜你喜欢
  • 2017-06-28
  • 1970-01-01
  • 2018-05-04
  • 2016-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-29
  • 1970-01-01
相关资源
最近更新 更多