Xalan (XSLT) 翻译方法翻译的内容超出了应有的范围

发布于 2024-09-08 17:28:41 字数 367 浏览 13 评论 0 原文

我似乎对 Xalan 的翻译方法有疑问。 我有以下代码:

translate(translate(string(name),'

这用于从 string(name) 中删除 。不幸的是,当我这样做时,似乎也从名称中删除了 s、u 和 p。 因此像 sony Braiva tm 这样的名字会变成 ony bravia tm

感谢您提前提供帮助:)

I seem to be having an issue with Xalan's translate method.
I have the following code:

translate(translate(string(name),'<sup>',''),'</sup>','')

This is used to remove <sup> and </sup> from string(name). Unfortunately when I do that, it seems to remove s, u and p from the names as well.
So names like sony Braiva <sup>tm</sup> become ony bravia tm

Thanks for you help in advance :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦幻的心爱 2024-09-15 17:28:41

因为您说 translate() 函数已成功删除 ,所以我假设 code> 不是 XML 文档中的元素,而是编码为文本。

translate()函数被定义为替换单个字符,通常不适合字符串长度大于1时的字符串替换

可以编写和使用通用字符串替换递归模板/ XSLT 中的函数。

XSLT 2.0 程序员可以使用标准 XPath 2.0 函数replace()。

在您的特定情况下,这可能就足够了:

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

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

 <xsl:template match="text()">
  <xsl:variable name="vPart1" select=
   "substring-before(., '<sup>')"/>

  <xsl:value-of select="$vPart1"/>

  <xsl:variable name="vPart2" select=
   "substring-before(substring-after(., '<sup>'),
                     '</sup>'
                     )"/>

  <xsl:value-of select="$vPart2"/>

  <xsl:variable name="vPart3" select=
   "substring-after(., '</sup>')"/>

  <xsl:value-of select="$vPart3"/>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于以下 XML 文档时

<name>
 <![CDATA[sony Braiva <sup>tm</sup> xxx]]>
</name>

生成所需的结果

<name>
sony Braiva tm xxx
</name>

< strong>或者,这里是成熟的递归模板解决方案:

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

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

 <xsl:template match="text()">
  <xsl:variable name="vFirstReplacement">
      <xsl:call-template name="replace">
       <xsl:with-param name="pText" select="."/>
       <xsl:with-param name="pPattern"
         select="'<sup>'"/>
       <xsl:with-param name="pReplacement" select="''"/>
      </xsl:call-template>
  </xsl:variable>

  <xsl:call-template name="replace">
   <xsl:with-param name="pText"
        select="$vFirstReplacement"/>
   <xsl:with-param name="pPattern"
     select="'</sup>'"/>
   <xsl:with-param name="pReplacement" select="''"/>
  </xsl:call-template>
 </xsl:template>

 <xsl:template name="replace">
  <xsl:param name="pText"/>
  <xsl:param name="pPattern"/>
  <xsl:param name="pReplacement"/>

  <xsl:choose>
   <xsl:when test="not(contains($pText, $pPattern))">
    <xsl:value-of select="$pText"/>
   </xsl:when>
   <xsl:otherwise>
     <xsl:value-of select=
      "substring-before($pText, $pPattern)"/>

     <xsl:value-of select="$pReplacement"/>

     <xsl:call-template name="replace">
      <xsl:with-param name="pText" select=
       "substring-after($pText, $pPattern)"/>
      <xsl:with-param name="pPattern"
           select="$pPattern"/>
      <xsl:with-param name="pReplacement"
           select="$pReplacement"/>
     </xsl:call-template>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于此 XML 文档时

<name>
 <![CDATA[sony Braiva <sup>tm</sup> xxx]]>
</name>

生成所需的正确结果:

<name>
 sony Braiva tm xxx
</name>

最后,这是 XSLT 2.0 解决方案

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

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

 <xsl:template match="text()">
  <xsl:value-of select=
   "replace(
            replace(., '<sup>', ''),
            '</sup>',
            ''
            )
   "/>
 </xsl:template>
</xsl:stylesheet>

Because you said that the translate() function is successfully removing <sup> and </sup>, I am assuming that <sup> is not an element in the XML document, but is encoded as text.

The translate() function is defined to substitute individual characters and generally isn't suitable for string replacement when the string length is greater than 1.

It is possible to write and use a general string replacement recursive template/function in XSLT.

XSLT 2.0 programmers can use the standard XPath 2.0 function replace().

In your particular case even this this may be sufficient:

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

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

 <xsl:template match="text()">
  <xsl:variable name="vPart1" select=
   "substring-before(., '<sup>')"/>

  <xsl:value-of select="$vPart1"/>

  <xsl:variable name="vPart2" select=
   "substring-before(substring-after(., '<sup>'),
                     '</sup>'
                     )"/>

  <xsl:value-of select="$vPart2"/>

  <xsl:variable name="vPart3" select=
   "substring-after(., '</sup>')"/>

  <xsl:value-of select="$vPart3"/>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the following XML document:

<name>
 <![CDATA[sony Braiva <sup>tm</sup> xxx]]>
</name>

the wanted result is produced:

<name>
sony Braiva tm xxx
</name>

Alternatively, here is the full-blown recursive template solution:

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

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

 <xsl:template match="text()">
  <xsl:variable name="vFirstReplacement">
      <xsl:call-template name="replace">
       <xsl:with-param name="pText" select="."/>
       <xsl:with-param name="pPattern"
         select="'<sup>'"/>
       <xsl:with-param name="pReplacement" select="''"/>
      </xsl:call-template>
  </xsl:variable>

  <xsl:call-template name="replace">
   <xsl:with-param name="pText"
        select="$vFirstReplacement"/>
   <xsl:with-param name="pPattern"
     select="'</sup>'"/>
   <xsl:with-param name="pReplacement" select="''"/>
  </xsl:call-template>
 </xsl:template>

 <xsl:template name="replace">
  <xsl:param name="pText"/>
  <xsl:param name="pPattern"/>
  <xsl:param name="pReplacement"/>

  <xsl:choose>
   <xsl:when test="not(contains($pText, $pPattern))">
    <xsl:value-of select="$pText"/>
   </xsl:when>
   <xsl:otherwise>
     <xsl:value-of select=
      "substring-before($pText, $pPattern)"/>

     <xsl:value-of select="$pReplacement"/>

     <xsl:call-template name="replace">
      <xsl:with-param name="pText" select=
       "substring-after($pText, $pPattern)"/>
      <xsl:with-param name="pPattern"
           select="$pPattern"/>
      <xsl:with-param name="pReplacement"
           select="$pReplacement"/>
     </xsl:call-template>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on this XML document:

<name>
 <![CDATA[sony Braiva <sup>tm</sup> xxx]]>
</name>

the wanted, correct result is produced:

<name>
 sony Braiva tm xxx
</name>

Finally, here is the XSLT 2.0 solution:

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

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

 <xsl:template match="text()">
  <xsl:value-of select=
   "replace(
            replace(., '<sup>', ''),
            '</sup>',
            ''
            )
   "/>
 </xsl:template>
</xsl:stylesheet>
初见终念 2024-09-15 17:28:41

tl;dr 版本: 如果可以避免的话,不要将 html 或 xml 作为字符串进行操作。在 XSLT 中进行。

我假设您拥有的某个元素包含类似的内容

<name>Sony Braiva <sup>tm</sup></name>

,因此看起来您已经在 XSLT 中获得了一个已解析的 XML 文档。然后,您转身尝试使用字符串操作来拉出一些标签。这是个坏主意;有关匹配标签的信息,请参阅此问题 。 XSLT 正是用于这种操作,所以使用它! (如果我的假设是错误的,并且 tm 是实体化的或在 CDATA 部分或其他内容中,我想那是不同的。)

所以,首先。如果您想从名称中删除所有标签,只留下文本,您可以

<xsl:value-of select="name" />

这样做:

Sony Braiva tm

另一方面,如果您想删除所有sup标签及其内容,您首先要在其他地方定义一个与sup匹配的模板(并对您想要删除的任何内容执行相同的操作,例如脚本标签、img标签等):

<xsl:template match="sup" /> <!-- replace sup with nothing -->

然后您可以应用

<xsl:apply-templates select="name" />

如果您真的想要,你甚至可以做这样的事情并用一个漂亮的 unicode 符号替换 HTML。将其置于不同的模式中并使用该模式消除所有其他标签可能是个好主意。

<xsl:template match="sup" mode="mangle-name">
  <xsl:if test="'tm' = string(.)">
  ™
  </xsl:if>
</xsl:template>

<!-- Later, somewhere else: -->
<xsl:apply-templates select="name" mode="mangle-name" />

关于所有这些的免责声明:它是标准 XSLT(甚至可能是 1.0),但我只在在线 Saxon 解析器中尝试过它,而不是在 Xalan 中。

tl;dr version: Don't manipulate html or xml as strings if you can possibly avoid it. Do it in XSLT.

I'm assuming that what you have is some element contains something like

<name>Sony Braiva <sup>tm</sup></name>

So it looks like you've got a parsed XML document already in XSLT. Then, you're turning around and trying to use string manipulation to pull some tags out. That's a bad idea; see this question about matching tags. XSLT is exactly for this sort of manipulation, so use it! (If my assumption is wrong and that tm is entity-ized or in a CDATA section or whatever, that's different I guess.)

So, first. If you want to strip all tags out of name leaving just the text, you can do

<xsl:value-of select="name" />

which would give:

Sony Braiva tm

If, on the other hand, you want to strip all sup tags and their content, you would first elsewhere define a template matching sup (and do the same with anything you want to rip out, e.g. script tags, img tags, whatever):

<xsl:template match="sup" /> <!-- replace sup with nothing -->

And then you can apply

<xsl:apply-templates select="name" />

If you really wanted, you could even do something like this and replace that HTML with a nice unicode symbol. It might be a good idea to place this in a different mode and use that mode to eliminate all other tags.

<xsl:template match="sup" mode="mangle-name">
  <xsl:if test="'tm' = string(.)">
  ™
  </xsl:if>
</xsl:template>

<!-- Later, somewhere else: -->
<xsl:apply-templates select="name" mode="mangle-name" />

Disclaimer on all of this: It's standard XSLT (probably 1.0 even), but I've only tried it in an online Saxon parser and not in Xalan.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文