在XSLT中替换特殊字符

12

我想在XSLT中从字符串中删除除字母以外的字符。例如:

<Name>O'Niel</Name> = <Name>ONiel</Name>
<Name>St Peter</Name> = <Name>StPeter</Name>
<Name>A.David</Name> = <Name>ADavid</Name>

我们能在XSLT中使用正则表达式来实现这个吗?哪种方法是正确的?

编辑:这需要在XSLT 1.0上完成。


检查我的答案如何在不使用 RegExp 的情况下完成,顺便提一下,在 XSLT/XPath 1.0 中是不支持 RegExp 的。 - Flack
4个回答

24

有一种纯XSLT的方法可以做到这一点。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
    <xsl:variable name="vAllowedSymbols"
        select="'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'"/>
    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="text()">
        <xsl:value-of select="
            translate(
                .,
                translate(., $vAllowedSymbols, ''),
                ''
                )
            "/>
    </xsl:template>
</xsl:stylesheet>

针对此示例的结果:

<t>
    <Name>O'Niel</Name>
    <Name>St Peter</Name>
    <Name>A.David</Name>
</t>

将会是:

<t>
    <Name>ONiel</Name>
    <Name>StPeter</Name>
    <Name>ADavid</Name>
</t>

@Flack - 这太棒了。我的解决方案可用于将黑名单中的单个字符替换为任何其他字符序列,但“translate”是应用白名单或简单一对一替换的更好解决方案。 - Wayne
@lwburk。您可以使用“translate”来替换“blacklist”。这样会更简单。当您不需要“字符串到另一个字符串”的替换时,就不需要递归了。 - Flack
如何将此模板应用于类似 /Application/Contact/FirstName 的节点? - Amzath
@Amzath。每当您获取节点和属性的字符串值时,可以基本上使用以translate开头的XPath表达式。 - Flack
@Flack - 对的,这就是我试图表达的部分,最终也是我删除帖子的原因。在XSLT 1.0中,您需要递归方法来进行更复杂的替换,但在这种情况下完全是过度杀伤力。 - Wayne
如何将 '(撇号)添加为允许的特殊字符? - Pawan Lakhotia

14

以下是2.0版本的选项:

编辑:抱歉...在我回答之前添加了1.0要求。

XML

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <Name>O'Niel</Name>
  <Name>St Peter</Name>
  <Name>A.David</Name>
</doc>

XSLT 2.0

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

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

  <xsl:template match="text()">
    <xsl:value-of select="replace(.,'[^a-zA-Z]','')"/>
  </xsl:template>

</xsl:stylesheet>

输出

<?xml version="1.0" encoding="UTF-8"?>
<doc>
   <Name>ONiel</Name>
   <Name>StPeter</Name>
   <Name>ADavid</Name>
</doc>

以下是另外几种使用 replace() 的方式...

使用 "i"(不区分大小写模式)标志

replace(.,'[^A-Z]','','i')

使用类别转义

replace(.,'\P{L}','')

3

我刚刚基于这个示例中的代码创建了一个函数...

    <xsl:function name="lancet:stripSpecialChars">
    <xsl:param name="string" />
    <xsl:variable name="AllowedSymbols" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()*%$#@!~&lt;&gt;,.?[]=- +   /\ '"/>
    <xsl:value-of select="
        translate(
            $string,
            translate($string, $AllowedSymbols, ''),
            ' ')
        "/>
</xsl:function> 

以下是一个使用示例:
<xsl:value-of select="lancet:stripSpecialChars($string)"/>

1

最快的方法是<xsl:value-of select="translate(Name,translate(Name,'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',''),'')" />

内部的translate删除了字母(需要的字符)。该translate的结果留下了其他字符。外部的translate删除了这些不需要的字符。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接