【问题标题】:XSLT search XML using regex, word boundriesXSLT 使用正则表达式搜索 XML,单词边界
【发布时间】:2012-03-28 04:53:46
【问题描述】:

是否可以使用正则表达式通过 XSLT 搜索 XML 内容?我可以使用包含搜索节点,但是我需要使用单词边界(例如/\bmy phrase\b/i)来搜索短语而不仅仅是单个单词。

当使用以下搜索“血压”时,将返回所有具有“血”、“压力”和“血压”的节点。

我只希望返回包含“血压”的节点。使用 PHP preg_match,我可以使用:/\b$keywords\b/i

<xsl:template match="//item">
    <xsl:choose>
        <xsl:when test="contains(translate(title, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), $keyword) or contains(translate(content, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), $keyword)">
            <item>
                <title><xsl:value-of select="title"/></title>
                <content><xsl:value-of select="content"/></content>
                <date><xsl:value-of select="date"/></date>
                <author><xsl:value-of select="author"/></author>
            </item>
        </xsl:when>
    </xsl:choose>
</xsl:template>

【问题讨论】:

    标签: php xml xslt


    【解决方案1】:

    我。你可以在 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:template match="s">
      <xsl:variable name="vWords" select=
      "tokenize(lower-case(string(.)),
                '[\s.?!,;—:\-]+'
                ) [.]
      "/>
      <xsl:sequence select=
       " for $current in .,
             $i in 1 to count($vWords)
         return
            if($vWords[$i] eq 'blood'
              and
               $vWords[$i+1] eq 'pressure'
               )
               then .
               else ()
      "/>
     </xsl:template>
     <xsl:template match="text()"/>
    </xsl:stylesheet>
    

    当此 XSLT 2.0 转换应用于以下 XML 文档时(问题中未提供此类文档!!!):

    <t>
     <s>He has high blood pressure.</s>
     <s>He has high Blood Pressure.</s>
     <s>He has high Blood
     Pressure.</s>
    
      <s>He was  coldblood Pressured.</s>
    
    </t>
    

    想要的正确结果(只产生包含“血液”和“压力”(不区分大小写,作为两个相邻的词)的元素:

    <s>He has high blood pressure.</s>
    <s>He has high Blood Pressure.</s>
    <s>He has high Blood
     Pressure.</s>
    

    解释:

    1. 使用 tokenize() 函数拆分 nn 字母字符的字符串,并带有不区分大小写和多行模式的标志。

    2. 遍历tokenize() 的结果以查找"blood" 字词后紧跟"pressure" 字词。


    二。 XSLT 1.0 解决方案:

    <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:variable name="vUpper" select=
     "'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
    
     <xsl:variable name="vLower" select=
     "'abcdefghijklmnopqrstuvwxyz'"/>
    
     <xsl:variable name="vSpaaaceeees" select=
     "'                                                                               '
     "/>
    
     <xsl:variable name="vAlpha" select="concat($vLower, $vUpper)"/>
    
     <xsl:template match="s">
       <xsl:variable name="vallLower" select="translate(., $vUpper, $vLower)"/>
         <xsl:copy-of select=
         "self::*
           [contains
            (concat
             (' ',
              normalize-space
               (translate($vallLower, translate($vallLower, $vAlpha, ''), $vSpaaaceeees)),
              ' '
              ),
    
             ' blood pressure '
             )
           ]
      "/>
     </xsl:template>
     <xsl:template match="text()"/>
    </xsl:stylesheet>
    

    当此转换应用于同一个 XML 文档(上图)时,会产生相同的正确结果:

    <s>He has high blood pressure.</s>
    <s>He has high Blood Pressure.</s>
    <s>He has high Blood
     Pressure.</s>
    

    解释:

    1. 转换为小写。

    2. 使用 double-translate 方法将任何非字母字符替换为空格。

    3. 然后使用normalize-space() 将任意一组相邻的空格替换为单个空格。

    4. 然后用空格包围这个结果。

    5. 最后,验证当前结果是否包含字符串" blood pressure "。

    【讨论】:

    • 很好的回应 Dimitre,谢谢。经过我的代码后,我实际上产生了正确的结果。我正在使用我认为导致问题的表单发布数据。再次感谢
    【解决方案2】:

    http://www.w3.org/TR/xslt20/#regular-expressions

    该指令使用的正则表达式,以及控制这些正则表达式解释的标志,必须符合 [函数和运算符] (请参阅Section 7.6.1 Regular Expression Syntax),它本身基于在 [XML Schema Part 2]中定义的语法。

    来自引用的第一个链接显示我们不存在\b。

    第二个链接Single Character Escape也一样

    但是如果我们在最后一个文档中滚动一下,我们可以找到字符类 (Category Escape)。并使用punctuation 和space 类的组合:[\p{P}\p{Z}] 以达到类似的效果。

    【讨论】:

    • 感谢您的信息,是否可以在 LAMP 环境中使用 XSLT 2.0?
    • 是的,但不是直接的。例如:stackoverflow.com/questions/2085632/…
    • @rossjha:不,AFAIK,除非您安装 XSLT 2.0 处理器,例如基于 Java 的 Saxon 9.x。请参阅我对 both XSLT 1.0 和 XSLT 2.0 解决方案的回答。 :)
    【解决方案3】:

    XSLT 和 XPath 2.0 确实有支持正则表达式的匹配函数,XSLT 和 XPath 1.0 没有这样的函数,您需要使用 XSLT 处理器支持的扩展函数:http://www.exslt.org/regexp/functions/match/index.html。 然而,即使使用 XSLT/XPath 2.0,我认为支持的正则表达式语言也不支持任何“单词边界”模式。

    【讨论】:

    • 谢谢 Martin,您知道我在使用 XSLT 后还有其他方法可以返回结果吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-14
    • 2011-03-28
    • 2012-03-10
    • 2014-06-07
    • 2012-09-24
    • 1970-01-01
    相关资源
    最近更新 更多