【问题标题】:XSLT convert xml block under a specific node to xml-escaped content of that nodeXSLT 将特定节点下的 xml 块转换为该节点的 xml 转义内容
【发布时间】:2015-03-10 13:06:27
【问题描述】:

任何关于如何解决以下问题的想法都将受到高度赞赏。

输入:

<p>
    <div>
     Original<br/>This is the original <b>acid</b>, a hydroxy monocarboxylic <span class="hl1">acid</span>.
    </div>
</p>

期望的输出:

<p>
    <div>
     Original&lt;br/&gt;This is the original &lt;b&gt;acid&lt;/b&gt;, a hydroxy monocarboxylic &lt;span class=&quot;hl1&quot;&gt;acid&lt;/span&gt;.
    </div>
</p>

尝试 1:

`<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output omit-xml-declaration="yes" indent="no" encoding="UTF-8"/>
<!--The identity template -->
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="div">
    <xsl:copy>
            <xsl:value-of select="/" disable-output-escaping="no"/>
    </xsl:copy>
</xsl:template>

`

尝试2: 作为替代方案,我考虑将子元素的内容放入 CDATA 包装器中。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output omit-xml-declaration="yes" indent="no" encoding="UTF-8"/>
<!--The identity template -->
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="div">
    <xsl:copy>
            <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
            <xsl:value-of select="/" />
            <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
    </xsl:copy>
</xsl:template>

但这并没有给我我想要的。 有人有更好的主意吗?我正在使用 XSLT 2.0

【问题讨论】:

  • 您使用哪种 XSLT 2.0 处理器?如果那是 Saxon 9,例如 Saxon 9.6,那么我只需设置 version="3.0" 并使用 w3.org/TR/xpath-functions-30/#func-serialize 函数。旧版本的 Saxon 有一个扩展来做同样的事情。
  • 您好,谢谢!我正在使用撒克逊 9.1.0。我不认为切换到较新版本是一种选择,因为它在许多地方都使用过,而且升级的努力可能会很高!

标签: xslt escaping xslt-2.0 cdata


【解决方案1】:

这是一个使用 XSLT 3.0 serialize() 的建议,由 Saxon 9.6 HE、PE 和 EE 支持:

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs">

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

<xsl:template match="div">
  <xsl:copy>
    <xsl:apply-templates mode="serialize"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="node()" mode="serialize">
  <xsl:variable name="ser-params">
    <output:serialization-parameters xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization">
      <output:omit-xml-declaration value="yes"/>
    </output:serialization-parameters>
  </xsl:variable>
  <xsl:value-of select="serialize(., $ser-params/*)"/>
</xsl:template>

</xsl:stylesheet>

对于旧版本的 Saxon 9,您可以使用扩展功能序列化,如 http://xsltransform.net/pPqsHTx 所示:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs">

<xsl:output name="inline" omit-xml-declaration="yes"/>

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

<xsl:template match="div">
  <xsl:copy>
    <xsl:apply-templates mode="serialize"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="node()" mode="serialize">

  <xsl:value-of xmlns:saxon="http://saxon.sf.net/" select="saxon:serialize(., 'inline')"/>
</xsl:template>

</xsl:stylesheet>

【讨论】:

  • 在我对 Saxon 9.6 PE 的测试中,XSLT 3.0 支持的函数是 XPath 3.0 函数。因此serializeparse-xml 函数可用于version="3.0" 样式表模块中的9.6 PE。
  • 抱歉,我的错,我想说的是,在 9.6 HE 中,serializeparse-xml 等 XPath 3.0 函数在带有 version="3.0" 的样式表模块中得到支持。据我测试,saxon.markmail.org/message/… 确认了这一点。
  • 好的,谢谢马丁的澄清。我只在 oXygen 中使用 PE 和 EE,并在尝试使用 HE 运行 3.0 版样式表时收到警告。现在,XPath 3.0 函数实际上在 HE 中可用是有道理的。
  • 是否有任何选项可以在不使用外部功能的情况下执行此操作。我们可以在 xslt 中定义一个自定义函数来执行此操作吗?
  • 我看不出 XPath 3.0 或 Saxon 的扩展函数是如何外部的。当然,在 9.6 版之前的 Saxon 9 中提供了一个扩展,因为纯 XSLT/XPath 不提供序列化功能作为干净和简单的方法,除非您确保使用两个转换步骤并且每个步骤的结果都是序列化的。但是,即使在 XSLT 1.0 中,也有纯粹但复杂的 XSLT 方法可以做到这一点,例如,参见 lenzconsulting.com/xml-to-string
【解决方案2】:

如果您将xsl:value-of 更改为xsl:copy-of 并调整select,您的第二次尝试应该会起作用:

<xsl:template match="div">
    <xsl:copy>
        <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
        <xsl:copy-of select="node()" />
        <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>
    </xsl:copy>
</xsl:template>

【讨论】:

  • 虽然这适用于这个简单的示例,但当我在链接 2 个 xslt 转换的实际项目中应用它时,我最终插入了一些处理指令,并且最终有两个级别的 CDATA 包装器,如:&lt;?javax.xml.transform.disable-output-escaping?&gt;&lt;![CDATA[&lt;![CDATA[]]&gt;
猜你喜欢
  • 2014-07-16
  • 2020-01-07
  • 1970-01-01
  • 2013-02-17
  • 2014-12-27
  • 2019-04-26
  • 1970-01-01
  • 1970-01-01
  • 2011-01-07
相关资源
最近更新 更多