【问题标题】:XSLT Get string length of CDATA sectionXSLT 获取 CDATA 部分的字符串长度
【发布时间】:2017-07-27 16:59:32
【问题描述】:

我正在寻找一些提示,获取Cdata元素的字符串长度

<root>
<description><![CDATA[This handbook covers the major topics <b>in</b> Spanish, but is by no means complete.]]></description>
</root>

我所尝试的,我正在使用 XSLT 1.0

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xlink="http://www.w3.org/1999/xlink">
<xsl:variable name="Values">
<xsl:value-of select="root/description"  disable-output-escaping="yes"/>
</xsl:variable>
<xsl:value-of select="string-length($Values)"/>
</xsl:stylesheet>

总字符串长度为 85 它包括 &lt;b&gt;&lt;/b&gt;,但我需要 79 除了 &lt;b&gt;&lt;/b&gt;

请让我有一些想法。

【问题讨论】:

  • disable-output-escaping 在变量中不起作用,这就是为什么你没有得到你想要的结果。在没有扩展函数的 XSLT 1.0 或 2.0 中,没有简单的方法可以解决这个问题。
  • 如果您想将&lt;b&gt;&lt;/b&gt; 视为标记,那么您到底为什么要将它放在CDATA 部分? CDATA 的意思是“将此处的所有内容视为文本,即使它看起来像标记”。这就是 CDATA 的用途,也是它唯一的用途。

标签: xml xslt-1.0 xsl-fo


【解决方案1】:

抱歉,现在是 78:

<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="text" />

<xsl:template match="description">
  <xsl:call-template name="string-length" />
</xsl:template>

<xsl:template name="string-length">
  <xsl:param name="string" select="." />
  <xsl:param name="length" select="0" />

  <xsl:choose>
    <xsl:when test="string-length($string) = 0">
      <xsl:value-of select="$length" />
    </xsl:when>
    <xsl:when test="not(contains($string, '&lt;'))">
      <xsl:value-of select="$length + string-length($string)" />
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable
          name="before"
          select="string-length(substring-before($string, '&lt;'))" />
      <xsl:call-template name="string-length">
        <xsl:with-param name="string"
                        select="substring-after($string, '>')" />
        <xsl:with-param name="length"
                        select="$length + $before" />
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
</xsl:stylesheet>

这将无法处理后面没有 &gt;&amp;lt;

现在开始讲课:

  • &lt;![CDATA[...]]&gt; 不是元素。正确的术语是“CDATA 部分”。见https://www.w3.org/TR/xml/#sec-cdata-sect
  • 转义您实际想要作为标记处理的标记的 CDATA 部分很少(更有可能,永远不会)是个好主意
  • CDATA 部分对于将标记示例放入 XML 文档等操作很有用,但除此之外,请勿使用 CDATA 部分

【讨论】:

  • 这是一项勇敢的努力,但它很容易失败,因为 - 与适当的 XML 解析器不同 - 它无法区分标记和作为文本一部分的 &amp;lt;&gt; 字符。 XSLT 1.0 或 2.0 中的正确解决方案是禁用输出转义,将结果保存到文件中,然后处理生成的文件。
  • “Valiant”夸大其词:“又快又脏”更接近事实。我已经说过它不会像无与伦比的&amp;lt; 那样工作,并警告不要将标记放在 CDATA 部分然后尝试用它做某事的整个想法。只有 OP 知道是否有可能在不表示为 &amp;lt;(甚至 &amp;#38;#60;)的 CDATA 部分中有不匹配的 &amp;lt;。我们不知道 OP 为什么要计算字符数,但如果 OP 说该元素包含 TeX 标记并想要计算 {} 之外的字符,我们将毫不犹豫地提供帮助。
  • 你一直在强调“无与伦比”;我的观点是,即使 &amp;lt;&gt; 字符匹配但不代表标记,它也可能失败。
  • 是的,但我们不知道匹配的非标记文字 &amp;lt;&gt; 是否会出现。如果我怀疑description 内容来自表单,那么表单软件很可能会正确转义文字&amp;lt;&gt;。我们只是不知道。在 CDATA 部分中使用标记做一些事情是一个非常糟糕的主意,但我们不知道在这种情况下它到底有多糟糕。给出的解决方案还将&amp;lt; 计为四个字符而不是一个,但它是 OP 可以使用和改进的。
【解决方案2】:

要干净利落地执行此操作,您需要切换到支持 XPath 3 parse-xml-fragment(https://www.w3.org/TR/xpath-functions-30/#func-parse-xml-fragment) 的处理器,例如

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

    <xsl:template match="/">
        <xsl:value-of select="string-length(parse-xml-fragment(root/description))"/>
    </xsl:template>

</xsl:stylesheet>

需要当前版本的 Saxon 9 或 AltovaXML 或 Exselt。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多