【问题标题】:XSLT parse text node as XML?XSLT 将文本节点解析为 XML?
【发布时间】:2010-10-28 08:49:06
【问题描述】:

在我正在转换的 XML 文档的中间,有一个 CDATA 节点,我知道它本身是由 XML 组成的。我希望将“递归解析”为 XML,以便我也可以对其进行转换。经过搜索,我认为我的问题与Handling node containing inner escaped XML非常相似。

那是一年前的事了:我可以澄清一下吗:

  1. 它说某些 XSLT 不能一次性完成:相反,您需要一个两阶段的方法。我刚买了一本关于 XSLT 2.0 的闪亮新书。是否仍然没有 XSLT 指令将字符串节点“重新解析”为 XML?
  2. 在我的例子中,XML 字符串节点只是整个节点中的一个。因此,在第 1 阶段,我将只转换输入 XML 文档的一个片段;其余的需要原封不动地通过第 2 阶段。我看到了几种将输入传递到输出不变的解决方案,但通常它们似乎“主要工作”,但跳过/不处理某种节点输入。是否有可靠的结构可以在不进行任何更改的情况下将其余输入传递给输出?
  3. 这种方法依赖于我能够分别应用 2 个转换。我被限制(现有应用程序)只能被允许 one 转换(XML 输出是固定的;它由一个 XSLT 文件转换;我唯一能做的就是将我喜欢的任何内容放入该 XSLT 文件中, 和/或添加更多 XSLT 文件,但我无法影响通过一个 XSLT 文件传递​​ XML 的顶级调用)。我可以将任何内容放入 XSLT 文件中,从而导致调用第二个 XSLT 转换吗?

【问题讨论】:

  • 这个问题很不清楚——即使它实际上是 3 个问题,也证明了这一点。 XSLT 功能中没有解析,但如果您等待 XSLT 3.0,可能会有。最好发布一个带有特定 XML 文档的具体示例并指定结果应该是什么。那么很有可能找到解决方案——你怎么知道你选择的方法是唯一可能的?
  • 同意@Dimitre,示例 XML 输入文档会有所帮助。
  • 无法想象什么是“不清楚”。如果一个人对某事有多个问题,那就不清楚了?!如果您真的想要一个示例文档,请使用链接问题中的那个。提供样本文档可能会鼓励其他人对其内容发表评论,或者如何生成 XML,这完全无关紧要。嗯嗯。
  • 我理解您关于示例文档在理论上无关紧要的观点,但只有当您确定您已将有关它的所有相关信息传输到我们。我想现在已经完成了,但它花了几个小时来回,而且我的大部分写作都是被误导的兔子足迹,其中一些可以通过示例文档保存。由于您不知道解决方案是什么,您如何确定您是否提到了所有相关细节?

标签: xml string parsing xslt


【解决方案1】:

见最后更新。

  1. 最重要的问题。有可能做到;问题是您是否必须在 XSLT 中手动编写 XML 解析器,或者使用扩展函数,或者是否有方便、可移植的解决方案。 更新:如果您可以使用 Saxon 的 parse() 扩展功能,那么这是迄今为止您最好的选择。你有权限吗?

  2. 很容易回答:是的,使用identity transform。这不会保留输入 XML 的所有词法详细信息,例如属性的顺序,或者 <foo/> 是否写为 <foo></foo>。但是,它将保留所有对 XML 处理器很重要的细节。

    但是,如果您不能在管道中运行 2 个样式表,这对您没有帮助,对吧?

  3. 嗯...不是很健壮。如果您的输出将由浏览器显示,或者由理解XML stylesheet processing instruction 的其他东西处理,您可以输出其中一个,并希望(违反规范的建议!)序列化和解析将在此样式表之间发生以及您在输出中关联的那个。但这会非常脆弱。我说“反对规范的建议”是因为 here 它说

    当这个或任何其他机制 产生一个以上的序列 要应用的 XSLT 样式表 同时到一个 XML 文档,然后 效果应该是一样的 应用一个样式表 将序列的每个成员导入 顺序

    这意味着,中间没有序列化和解析。不推荐。

更新:一条新评论说您事先不知道哪些元素将包含 CDATA 部分。我立即得出结论,这意味着您不知道哪些元素将包含未解析的数据(因为 XML 处理器官方不知道也不关心 CDATA 部分中的元素本身)。在这种情况下,所有赌注都取消了。您可能知道,XML 处理器不应该知道 XML 输入文档的哪些部分位于 CDATA 部分中。 CDATA 只是转义标记的另一种方式,是 < 等的替代方法。一旦解析了数据(这不正确地在 XSLT 处理器的管辖范围内),您就无法知道它最初是如何在标记中表达的。左尖括号仍然是左尖括号,无论它表示为<![CDATA[ < ]]> 还是<。就像在 C 中一样,将字符指定为 'A' 或 65 或 0x41 都没有关系;一旦程序编译完成,您的代码将无法区分。

因此,如果您没有其他方法来确定需要解析输入文档中的哪些数据,那么上述方法都不会帮助您:您无法知道在哪里应用 saxon:parse(),也不是手动解析,也不是使用以下 XSLT 转换禁用输出转义。

解决方法:

  • 你可以猜测,例如test="contains(., '<')",其中节点包含未解析的数据。 (请注意,这会测试左尖括号,无论它是表示为字符实体、CDATA 部分的一部分还是任何其他方式。)您有时会得到误报,例如如果文本节点包含字符串“year

  • 或者您可以使用非 XML 工具(如 LexEv)预处理 XML,因此可以“看到”CDATA 标记。但是您说过您无法控制单个 XSLT 之外的任何内容。

  • 或者,理想情况下,您可以将消息发送回链,表明您获得的 XML 不可用:他们需要以某种方式进行标记,而不是使用 CDATA 标记,哪些部分包含未解析的数据。通常这可以通过指定某些元素名称或使用属性标志来完成。显然,这取决于谁提供 XML。

另一个更新 好的,现在我明白了:所以您知道哪个元素包含未解析的数据(并且您知道它用 CDATA 标记),但您不知道哪些其他数据可能用 CDATA 标记。

这个想法是改变 [i.e. parse -Lars] 已知的 CDATA 节点(“fred”)转换为 XML 节点 同时留下其余的全部 文档作为原始输入, 这样它就可以通过管道 “一般”转换

为此,“将文档的其余部分作为原始输入”并不意味着保留任何 CDATA 标记。 (下游的一般转换不会知道或关心哪些数据是 CDATA 转义的。)所需要的只是解析一个未解析的节点,其余的不解析。 identity transform 会做后者就好了;您可以忽略该页面对输出中 CDATA 部分的说明……下游 XSLT 不会知道或关心。 (除非您对未告诉我们的输出有其他(非 XML)要求。)

因此,如果您可以进行两个样式表转换,在两者之间进行序列化和解析(例如,不在传统的 SAX 管道中),那么身份转换将起作用:您只需要一个用于已知未解析节点的附加模板,并带有禁用输出转义,如 Tomalak 的回答 here

但是,如果您不能进行两步转换...您使用的是什么 XSLT 处理器?可能还有其他特定的途径。

【讨论】:

  • 感谢您的尝试!但我认为我违反了所有 3 条建议!
  • 1.不,我是诺曼人,不可能是撒克逊人!我会需要原版 XSLT 中的一些东西。
  • 2.正如我所说,您展示的“身份转换”不足以对未知输入进行“无变化”。如果我理解正确,我必须知道它需要哪些 CDATA 部分才能稳健地工作,而我不知道。
  • 3.正如您所说,似乎没有足够可靠的非流水线方法可用。
  • @JonBrave,关于#2,对于 XML 信息模型而言,身份转换足以“无变化”;特别是它将保留 CDATA 部分中的信息,但不保留标记。但是我认为您是在说您 确实 想要将数据(在 CDATA 部分中)从未解析更改为已解析,您是对的,如果您没有,则任何转换都不会允许一种了解哪些部分未解析的独立方法。在这种情况下,saxon:parse() 和两阶段方法都不会帮助您。正在编辑答案...
猜你喜欢
  • 2012-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-20
  • 1970-01-01
  • 2015-03-31
  • 2015-08-30
相关资源
最近更新 更多