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

IT技术 javascript html xml xslt xpath
2021-01-27 10:15:56

我正在运行我的 DOM 的所有文本节点并检查 nodeValue 是否包含某个字符串。

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

这是区分大小写的。但是,我也想赶上Test,TESTTesTXPath(在 JavaScript 中)可以实现吗?

6个回答

这适用于 XPath 1.0。如果您的环境支持 XPath 2.0,请参见此处


是的。可能,但并不美丽。

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

这适用于预先知道字母表的搜索字符串。添加您希望看到的任何重音字符。


如果可以,请用其他方式标记您感兴趣的文本,例如<span>在构建 HTML 时将其包含在具有特定类的 a 中。与元素文本中的子字符串相比,使用 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)。
2021-03-13 10:15:56
@AronWoost:好吧,可能会有一些收获,如果您想知道的话,只需对其进行基准测试即可。translate()本身并不关心您重复每个字符的频率 -translate(., 'EE', 'ee')绝对等同于translate(., 'E', 'e'). PS:不要忘记给@KirillPolishchuk 投票,这个想法是他的。
2021-03-16 10:15:56
不。请参阅“当然,您只需要翻译您实际搜索的那些字符”部分。
2021-03-18 10:15:56
System.Xml.XmlNodeList x = mydoc.SelectNodes("//*[contains(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜÉÈÊÀÁÂÒÓÔÙÚÛÇÏÕÑŒ'),âüqdefghijkuvåéŒ');'abcdefghijkuvåés');
2021-04-10 10:15:56

不区分大小写 contains

/html/body//text()[contains(translate(., 'EST', 'est'), 'test')]
这样做可能更清楚translate(., 'TES', 'tes')这样人们就会意识到这不是单词翻译,而是字母翻译。
2021-03-15 10:15:56
它不会只是转换TESTtest并保持Test原样吗?
2021-03-20 10:15:56
+1 绝对。这是我没有想到的。(我将在我的回答中使用它,这比我编写的原始 JavaScript 例程要好得多)
2021-03-21 10:15:56
@MuhammadAdeelZahid - 不,它将“T”替换为“t”,将“E”替换为“e”等。这是一对一的匹配。
2021-03-29 10:15:56
或“EST”、“est”,虽然它看起来很酷(虽然有点神秘),但搜索词的一部分出现在映射中(删除了重复的字母)
2021-04-04 10:15:56

XPath 2.0 解决方案

  1. 使用小写()

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

  2. 使用matches() regex 与其不区分大小写的标志匹配:

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

Firefox 和 Chrome 仅实现 XPath 1.0。
2021-03-30 10:15:56
我可以在哪里验证这是否会按预期工作?
2021-03-31 10:15:56
@AnkitGupta:当然,任何支持 XPath 2.0 的在线或离线工具都可以用来验证这个答案,但是 (1) 工具推荐在 SO 上是题外话和 (2) 鉴于 56 个赞成票、0 个反对票和没有六年多来反对意见,您可以非常确信这个答案是正确的。;-)
2021-04-03 10:15:56
Firefox 和 Chrome 不支持此语法吗?我只是在控制台中尝试过,它们都返回语法错误。
2021-04-08 10:15:56

是的。您可以使用translate将要匹配的文本转换为小写,如下所示:

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

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

请注意,之前使用 translate() 给出的解决方案都假定您仅使用 26 个字母的英文字母表。

更新: XPath 3.1 定义了一个用于大小写匹配的标准排序规则 URI。