XSLT用正则表达式替换文本中的url

时间:2011-05-23 12:05:37

标签: xml xslt

我有一个来自Twitter的xml源,我想用XSLT进行转换。我想要xslt做的是替换twittermessage中的每个出现的URL。我已经在stackoverflow上使用thisthis主题创建了以下xslt模板。我怎样才能做到这一点?如果我使用下面的模板我得到一个无限循环,但我没有看到在哪里。一旦我评论出对'replaceAll'模板的调用,一切似乎都有效,但当然没有任何twittermessage的内容被取代。我是XSLT的新手,所以欢迎任何帮助。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
    <xsl:output method="text" omit-xml-declaration="yes" indent="yes"  encoding="utf-8" />
    <xsl:param name="html-content-type" />
    <xsl:variable name="urlRegex" select="8"/>
    <xsl:template match="statuses">
        <xsl:for-each select="//status[position() &lt; 2]">
            <xsl:variable name="TwitterMessage" select="text" />
            <xsl:call-template name="replaceAll">
                <xsl:with-param name="text" select="$TwitterMessage"/>
                <xsl:with-param name="replace" select="De"/> <!--This should become an regex to replace urls, maybe something like the rule below?-->
                <xsl:with-param name="by" select="FOOOO"/> <!--Here I want the matching regex value to be replaced with valid html to create an href-->
                <!--<xsl:value-of select="replace(text,'^http://(.*)\.com','#')"/>
                <xsl:value-of select="text"/>-->
            </xsl:call-template>
            <!--<xsl:value-of select="text"/>-->
            <!--<xsl:apply-templates />-->
        </xsl:for-each>
    </xsl:template>

    <xsl:template name="replaceAll">
        <xsl:param name="text"/>
        <xsl:param name="replace"/>
        <xsl:param name="by"/>
        <xsl:choose>
            <xsl:when test="contains($text,$replace)">
                <xsl:value-of select="substring-before($text,$replace)"/>
                <xsl:value-of select="$by"/>
                <xsl:call-template name="replaceAll">
                    <xsl:with-param name="text" select="substring-after($text,$replace)"/>
                    <xsl:with-param name="replace" select="$replace"/>
                    <xsl:with-param name="by" select="$by"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$text"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

编辑: 这是xml feed的一个例子。

<?xml version="1.0" encoding="UTF-8"?>
<statuses type="array">
<status>
  <created_at>Mon May 16 14:17:12 +0000 2011</created_at>
  <id>10000000000000000</id>
  <text>This is an message from Twitter http://bit.ly/xxxxx http://yfrog.com/xxxxx</text>
<status>

这只是以下网址上的基本html twitter输出;

http://twitter.com/statuses/user_timeline.xml?screen_name=yourtwitterusername

此文字;

This is an message from Twitter http://bit.ly/xxxxx http://yfrog.com/xxxxx

应转换为;

This is an message from Twitter <a href="http://bit.ly/xxxxx>http://bit.ly/xxxxx</a> <a href="http://yfrog.com/xxxxx">http://yfrog.com/xxxxx</a>

2 个答案:

答案 0 :(得分:1)

通常,我不会实现新的替换功能。我使用EXSLT提供的那个。如果您的XSLT处理器支持exslt,您只需按如下方式设置样式表:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:regex="http://exslt.org/regular-expressions"
                extension-element-prefixes="regex"
                version="1.0">

否则从EXSLT下载并导出样式表。

对于全局替换,您可以使用以下函数:

<xsl:value-of select="regexp:replace(string($TwitterMessage), 'yourppatern', 'g', 'yourreplace')" />

很抱歉一般的答案,但我目前无法测试XSLT。

答案 1 :(得分:1)

所以,你的问题不是关于XSLT。你想要的是找到在XPath中操作文本字符串的最佳选项。如果你使用的是独立的XSLT引擎,你可以使用XPath 2,它几乎拥有你需要的功能,虽然使用正则表达式它会有点繁琐。如果您是从支持EXSLT的引擎运行它,则需要查找那里可用的功能。如果从PHP运行它,文本操作通常很好地交给PHP代码;你可以通过创建一个PHP函数来做你想做的事情,并使用php:function('f-name', inputs ...)作为XPath表达式从XSLT中调用它。

就正则表达而言,我猜你正在寻找几乎这些方面的东西:

(https?://.*?)(?=[.,:;)]*($|\s))发送给<a href="$1">$1</a>

如果它与所有网址都不匹配,那很好,你只需要处理传入的数据以及Twitter的重复数据。最后检查标点符号(正则表达式中的[])确实是用户期望你做的唯一棘手的事情。