1

When I try to running the following xpath expression in Java using VTD-XML I get an unexpected error.

Code:

..
AutoPilot ap = new AutoPilot(vn);
ap.selectXPath("/a//b[text() = 'apple''banana']");

Error:

Syntax error after or around the end of ==> /a//b[text() = 'apple'
Caused by: com.ximpleware.XPathParseException: XPath Syntax error: #29
    at com.ximpleware.xpath.parser.unrecovered_syntax_error(parser.java:492)
    at java_cup.runtime.lr_parser.parse(lr_parser.java:601)
    at com.ximpleware.AutoPilot.selectXPath(AutoPilot.java:809)

Is this not a bug? I was under the impression that escaping single quotes in XPath 2.0 was acceptable? When I try running the xpath query in XML Spy with the same document it runs fine.

Bigby Wolf
  • 31
  • 4
  • My usual recommendation for injecting parameters into an XPath expression would be to use the facilities provided by your XPath library to set variables, and then refer to the variables in the expression (`/a//b[. = $targetValue]`). But VTD-XML only allows you to set a variable by evaluating another XPath expression, unlike all the other XPath implementations I'm aware of that let you directly inject a Java string or number as the variable's value. – Ian Roberts Aug 28 '14 at 16:01
  • I think a back slash in front of double quote should resolve the problem. – vtd-xml-author Aug 30 '14 at 04:34

3 Answers3

1

Since XPath can also supports ".." strings which can contain unescaped '-s, you could just use:

   ap.selectXPath("/a//b[text() = \"apple'banana\"]");
BeniBela
  • 16,412
  • 4
  • 45
  • 52
  • If you escape the double quotes like this, then they are likely considered part of the string and do not delimit anything. – Mathias Müller Aug 29 '14 at 09:29
  • @MathiasMüller: Ofc they are considered part of the string. That's the point, the string becomes the XPath expression – BeniBela Aug 29 '14 at 10:40
  • But then, this string is not _delimited_ anymore, which will result in an error (or XPath will decide that it is meant to be an element name). In my opinion, at least. Apologies if I miss something obvious. – Mathias Müller Aug 29 '14 at 10:42
  • XPath only sees the final unescaped string. Aka `/a//b[text() = "apple'banana"]` – BeniBela Aug 29 '14 at 12:10
0

Escaping is a matter that is entirely left to the host language that uses XPath to query data. The escaping rules of that higher-level language usually also apply to XPath expressions used therein.

I quote from Michael Kay's XPath 2.0 Programmer's Reference:

Similarly, when XPath expressions are written within character strings in a host language such as Java, you will need to use the escaping conventions of that language: for example, [...] a quotation mark as \".

In other words, '' does escape a single quote, in XSLT 2.0. In Java, the single quote must be escaped as \' I guess.

ap.selectXPath("/a//b[text() = 'apple\'banana']");
Community
  • 1
  • 1
Mathias Müller
  • 22,203
  • 13
  • 58
  • 75
  • Thanks, I tried this with no luck. I now get acom.ximpleware.XPathParseException: Invalid char in XPath Expression exception. – Bigby Wolf Aug 27 '14 at 20:25
  • @BigbyWolf Is the single quote really relevant to uniquely identify the element? If you show the XML file you are querying, perhaps we can find another expression that returns the same node. – Mathias Müller Aug 27 '14 at 21:48
  • @BigbyWolf Also, are you sure that VTD-XML uses XPath 2.0? On the sourceforge page [here](http://vtd-xml.sourceforge.net/faq.html#Is_VTD-XML_conformant) I found: "VTD-XML fully conforms with W3C XPath 1.0 recommendation.". Is this outdated? – Mathias Müller Aug 28 '14 at 08:27
  • Thanks for the help. I believe you are correct, VTD-XML is using XPath 1.0 (my mistake). Based on this I tried " and &apos which I believe is supposed to work in XPath 1.0 - but no luck. I ended up writing a custom method that splits a string up and uses the Xpath concat function. – Bigby Wolf Aug 28 '14 at 15:35
0

Unfortunately it looks like escaping isn't an option, I had to write a custom function based on the following:

XQuery looking for text with 'single' quote

It was written in javascript so I converted it to Java:

private static String cleanStringForXPath(String dirtyString)
    {
        Pattern pattern = Pattern.compile("([^'\"]+|['\"])");
        Matcher matcher = pattern.matcher(dirtyString);

        int count = 0;
        StringBuilder sb = new StringBuilder();

        while(matcher.find()) {
            String part = matcher.group(1);
            if(part.equals("'")) {
                sb.append("\"'\"");
            } else if(part.equals("\"")) {
                sb.append("'\"'");
            } else { 
                sb.append("'" + part + "'");
            }
            sb.append(",");
            count++;
        }

    String result = sb.length() > 0 ? sb.substring(0, sb.length() - 1): "";
    return (count > 1) ? "concat(" + result + ")" : result;
}

I tested this function and it seems to resolve my problem.

Community
  • 1
  • 1
Bigby Wolf
  • 31
  • 4