Ruan Mendes
Ruan Mendes

Reputation: 92294

XQuery looking for text with 'single' quote

I can't figure out how to search for text containing single quotes using XPATHs.

For example, I've added a quote to the title of this question. The following line

$x("//*[text()='XQuery looking for text with 'single' quote']")

Returns an empty array.

However, if I try the following

$x("//*[text()=\"XQuery looking for text with 'single' quote\"]")

It does return the link for the title of the page, but I would like to be able to accept both single and double quotes in there, so I can't just tailor it for the single/double quote.

You can try it in chrome's or firebug's console on this page.

Upvotes: 8

Views: 30106

Answers (6)

Mohamed Allal
Mohamed Allal

Reputation: 20900

Well I was in the same quest, and after a moment I found that's there is no support in xpath for this, quiet disappointing! But well we can always work around it!

I wanted something simple and straight froward. What I come with is to set your own replacement for the apostrophe, kind of unique code (something you will not encounter in your xml text) , I chose //apos// for example. now you put that in both your xml text and your xpath query . (in case of xml you didn't write always we can replace with replace function of any editor). And now how we do? we search normally with this, retrieve the result, and replace back the //apos// to '.

Bellow some samples from what I was doing: (replace_special_char_xpath() is what you need to make)

function repalce_special_char_xpath($str){
    $str = str_replace("//apos//","'",$str);
    /*add all replacement here */
    return $str;
}

function xml_lang($xml_file,$category,$word,$language){ //path can be relative or absolute
    $language = str_replace("-","_",$language);// to replace - with _ to be able to use "en-us", .....
    $xml = simplexml_load_file($xml_file);
    $xpath_result = $xml->xpath("${category}/def[en_us = '${word}']/${language}");
    $result = $xpath_result[0][0];
    return repalce_special_char_xpath($result);
}

the text in xml file:

<def>
     <en_us>If you don//apos//t know which server, Click here for automatic connection</en_us>   <fr_fr>Si vous ne savez pas quelle serveur, Cliquez ici pour une connexion automatique</fr_fr>    <ar_sa>إذا لا تعرفوا أي سرفير, إضغطوا هنا من أجل إتصال تلقائي</ar_sa>
</def>

and the call in the php file (generated html):

<span><?php echo xml_lang_body("If you don//apos//t know which server, Click here for automatic connection")?>

Upvotes: 0

Ruan Mendes
Ruan Mendes

Reputation: 92294

Here's a hackaround (Thanks Dimitre Novatchev) that will allow me to search for any text in xpaths, whether it contains single or double quotes. Implemented in JS, but could be easily translated to other languages

function cleanStringForXpath(str)  {
    var parts = str.match(/[^'"]+|['"]/g);
    parts = parts.map(function(part){
        if (part === "'")  {
            return '"\'"'; // output "'"
        }

        if (part === '"') {
            return "'\"'"; // output '"'
        }
        return "'" + part + "'";
    });
    return "concat(" + parts.join(",") + ")";
}

If I'm looking for I'm reading "Harry Potter" I could do the following

var xpathString = cleanStringForXpath( "I'm reading \"Harry Potter\"" );
$x("//*[text()="+ xpathString +"]");
// The xpath created becomes 
// //*[text()=concat('I',"'",'m reading ','"','Harry Potter','"')]

Here's a (much shorter) Java version. It's exactly the same as JavaScript, if you remove type information. Thanks to https://stackoverflow.com/users/1850609/acdcjunior

String escapedText = "concat('"+originalText.replace("'", "', \"'\", '") + "', '')";!

Upvotes: 13

Danielle Madeley
Danielle Madeley

Reputation: 2826

You can do this using a regular expression. For example (as ES6 code):

export function escapeXPathString(str: string): string {
    str = str.replace(/'/g, `', "'", '`);

    return `concat('${str}', '')`;
}

This replaces all ' in the input string by ', "'", '.

The final , '' is important because concat('string') is an error.

Upvotes: 1

BeniBela
BeniBela

Reputation: 16917

Additionally, if you were using XQuery, instead of XPath, as the title says, you could also use the xml entities:

   "&quot; for double and &apos; for single quotes"

they also work within single quotes

Upvotes: 1

Michael Kay
Michael Kay

Reputation: 163458

In XPath 2.0 and XQuery 1.0, the delimiter of a string literal can be included in the string literal by doubling it:

let $a := "He said ""I won't"""

or

let $a := 'He said "I can''t"'

The convention is borrowed from SQL.

Upvotes: 8

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243529

This is an example:

/*/*[contains(., "'") and contains(., '"') ]/text()

When this XPath expression is applied on the following XML document:

<text>
    <t>I'm reading "Harry Potter"</t>
    <t>I am reading "Harry Potter"</t>
    <t>I am reading 'Harry Potter'</t>
</text>

the wanted, correct result (a single text node) is selected:

I'm reading "Harry Potter"

Here is verification using the XPath Visualizer (A free and open source tool I created 12 years ago, that has taught XPath the fun way to thousands of people):

enter image description here

Your problem may be that you are not able to specify this XPath expression as string in the programming language that you are using -- this isn't an XPath problem but a problem in your knowledge of your programming language.

Upvotes: 6

Related Questions