ChatGPT解决这个技术问题 Extra ChatGPT

case-insensitive matching in XPath?

For example, for the XML below

<CATALOG>
    <CD title="Empire Burlesque"/>
    <CD title="empire burlesque"/>
    <CD title="EMPIRE BURLESQUE"/>
    <CD title="EmPiRe BuRLeSQuE"/>
    <CD title="Others"/>
<CATALOG>

How to match the first 4 records with xpath like //CD[@title='empire burlesque']. Is there xpath function to do this? Other solutions like PHP function are also accepted.

stackoverflow.com/questions/586231/… check out ben gripka's post for xpath 1.0
Here, I also have found 2 more solutions with description: (not my site/promotion) codingexplained.com/coding/php/…

C
Community

XPath 2 has a lower-case (and upper-case) string function. That's not quite the same as case-insensitive, but hopefully it will be close enough:

//CD[lower-case(@title)='empire burlesque']

If you are using XPath 1, there is a hack using translate.


Even works in SQL Server's XPath queries on XML columns. Excellent.
M
Mads Hansen

matches() is an XPATH 2.0 function that allows for case-insensitive regex matching.

One of the flags is i for case-insensitive matching.

The following XPATH using the matches() function with the case-insensitive flag:

//CD[matches(@title,'empire burlesque','i')]

This is regex-based which is an important difference to text-based matching.
Beware that this may also find partial matches; if that's not acceptable then use ^ and $, like matches(@title, '^empire burlesque$', 'i')
B
Bhuvanesh Mani

This does not work in Chrome Developer tools to locate a element, i am looking to locate the 'Submit' button in the screen

//input[matches(@value,'submit','i')]

However, using 'translate' to replace all caps to small works as below

//input[translate(@value,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz') = 'submit']

Update: I just found the reason why 'matches' doesnt work. I am using Chrome with xpath 1.0 which wont understand the syntax 'matches'. It should be xpath 2.0


It seems the translate concept is called 'case insensitive collation' in regards to internationalization
Also bear in mind that the translate solution in this answer won't work for languages (german for instance) having special rules for uppercase letters.
T
Tomalak

One possible PHP solution:

// load XML to SimpleXML
$x = simplexml_load_string($xmlstr);

// index it by title once
$index = array();
foreach ($x->CD as &$cd) {
  $title = strtolower((string)$cd['title']); 
  if (!array_key_exists($title, $index)) $index[$title] = array();
  $index[$title][] = &$cd;
}

// query the index 
$result = $index[strtolower("EMPIRE BURLESQUE")];

To the anonymous down-voter: Read the OP's question. Especially the "Other solutions like PHP function are also accepted." part.
j
jimp

You mentioned that PHP solutions were acceptable, and PHP does offer a way to accomplish this even though it only supports XPath v1.0. You can extend the XPath support to allow PHP function calls.

$xpathObj = new DOMXPath($docObj);
$xpathObj->registerNamespace('php','http://php.net/xpath'); // (required)
$xpathObj->registerPhpFunctions("strtolower"); // (leave empty to allow *any* PHP function)
$xpathObj->query('//CD[php:functionString("strtolower",@title) = "empire burlesque"]');

See the PHP registerPhpFunctions documentation for more examples. It basically demonstrates that "php:function" is for boolean evaluation and "php:functionString" is for string evaluation.


J
Jean-François Fabre

for selenium xpath lower-case will not work ... Translate will help Case 1 :

using Attribute //*[translate(@id,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='login_field'] Using any attribute //[translate(@,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='login_field']

Case 2 : (with contains) //[contains(translate(@id,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz'),'login_field')]

case 3 : for Text property //*[contains(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),'username')]


You helped me a lot. Many thanks!