不区分大小写的XPath contains()可能吗?


94

我正在DOM的所有textnode上运行,并检查nodeValue是否包含某个字符串。

/html/body//text()[contains(.,'test')]

这是区分大小写的。但是,我也想抓住TestTEST或者TesT。XPath(在JavaScript中)可以实现吗?

Answers:


111

这是针对XPath 1.0的。如果您的环境支持XPath 2.0,请参见此处


是。可能,但是不漂亮。

/html/body//text()[
  contains(
    translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),
    'test'
  )
]

这适用于事先知道字母的搜索字符串。添加您希望看到的所有带重音符号的字符。


如果可以的话,请通过其他方式标记您感兴趣的文本,例如<span>在构建HTML时将其包含在具有特定类的文本中。与元素文本中的子字符串相比,使用XPath定位这些内容要容易得多。

如果这不是一种选择,则可以让JavaScript(或用于执行XPath的任何其他宿主语言)帮助您构建动态XPath表达式:

function xpathPrepare(xpath, searchString) {
  return xpath.replace("$u", searchString.toUpperCase())
              .replace("$l", searchString.toLowerCase())
              .replace("$s", searchString.toLowerCase());
}

xp = xpathPrepare("//text()[contains(translate(., '$u', '$l'), '$s')]", "Test");
// -> "//text()[contains(translate(., 'TEST', 'test'), 'test')]"

@KirillPolishchuk的答案的提示 -当然,您只需要翻译实际要搜索的字符即可。)

这种方法适用于任何搜索字符串,而无需先验字母知识,这是一个很大的优势。

当搜索字符串可以包含单引号时,上述两种方法都将失败,在这种情况下事情会变得更加复杂


谢谢!另外,添加项很好,只翻译了需要的字符。我很好奇这是性能上的胜利。请注意,xpathPrepare()可以以不同的方式处理出现的字符(例如,您得到TEEEEEST和teeeeest)。
阿隆·伍斯特

@AronWoost:好吧,可能会有一些收获,如果您想找出答案,可以对它进行基准测试。translate()本身并不关心您重复每个字符的频率- translate(., 'EE', 'ee')绝对等于translate(., 'E', 'e')PS:别忘了投票@KirillPolishchuk,这个主意是他的。
Tomalak

2
System.Xml.XmlNodeList x = mydoc.SelectNodes(“ // * [包含(翻译(text(),'ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜÉÈÊÁÁÒÓÒÇÅÏÕÑŒ','abcdefghijklmnopqrstuvwxyzäöö'é'')'),)
Stefan Steiger 2013年

1
否。请参见“当然,您只需要翻译实际要搜索的字符”部分。
Tomalak

61

更美丽:

/html/body//text()[contains(translate(., 'TES', 'tes'), 'test')]

4
+1。那是我没想到的。(我将在答案中使用它,这比我编写的原始JavaScript例程要好得多)
Tomalak

4
难道不只是转换TEST为原样test并保留Test原样吗?
Muhammad Adeel Zahid

6
@MuhammadAdeelZahid-不,它将“ T”替换为“ t”,将“ E”替换为“ e”,依此类推。这是一对一的匹配。
Daniel Haley 2013年

这样做可能更清晰translate(., 'TES', 'tes')。这样人们就会意识到这不是单词翻译,而是字母翻译。
mlissner '17

55

XPath 2.0解决方案

  1. 使用小写()

    /html/body//text()[contains(lower-case(.),'test')]

  2. 使用matches()正则表达式匹配不区分大小写的标志:

    /html/body//text()[matches(.,'test', 'i')]


1
Firefox和Chrome不支持此语法吗?我只是在控制台中尝试过,它们都返回语法错误。
分贝

1
Firefox和Chrome仅实现XPath 1.0。
kjhughes

8

是。您可以使用以下translate方法将要匹配的文本转换为小写:

/html/body//text()[contains(translate(., 
                                      'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
                                      'abcdefghijklmnopqrstuvwxyz'),
                   'test')]

6

如果您使用的是XPath 2.0,则可以将排序规则指定为contains()的第三个参数。但是,归类URI没有标准化,因此详细信息取决于您使用的产品。

请注意,先前使用translate()给出的解决方案均假定您仅使用26个字母的英语字母。

更新: XPath 3.1定义了用于区分大小写的标准排序规则URI。


3

我一直这样做的方式是使用XPath中的“翻译”功能。我不会说它非常漂亮,但是可以正常工作。

/html/body//text()[contains(translate(.,'abcdefghijklmnopqrstuvwxyz',
                                        'ABCDEFGHIJKLOMNOPQRSTUVWXYZ'),'TEST')]

希望这可以帮助,

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.