Search code examples
c#xpathlinq-to-xml

XPathSelectElement crashes with "has an invalid token"


I am trying to use a list of possible values in an XPath condition to find a node in XML, but XPathSelectElement throws a System.Xml.XPath.XPathException 'an invalid token'.

Here is a samle code in .Net Framework 4.7.2.

First it looks for a single value 'data2' and it works, then it looks for 'data2' or 'xxx' and it fails.

using System;
using System.Xml.Linq;
using System.Xml.XPath;
                    
public class Program
{
    public static void Main()
    {
        XDocument doc = new XDocument(     
        new XElement("Root",  
            new XElement("El", "data1"),  
            new XElement("El", "data2")
        )  
        );  
        Console.WriteLine(doc.ToString());
        
        var found = doc.Root.XPathSelectElement("El[text()=('data2')]");
        
        Console.WriteLine("\r\nFound element:");
        Console.WriteLine(found.ToString());
        
        var found2 = doc.Root.XPathSelectElement("El[text()=('data2','xxx')]");

        Console.WriteLine("\r\nFound element2:");
        Console.WriteLine(found2.ToString());
    }
}

Output:

<Root>
  <El>data1</El>
  <El>data2</El>
</Root>

Found element:
<El>data2</El>
Run-time exception (line 23): 'El[text()=('data2','xxx')]' has an invalid token.

I tried 2 online XPath validators with an absolute version of the same XPath expression /*/El[text()=('data2','xxx')]. It works on https://www.freeformatter.com/xpath-tester.html, but fails with "XPath parse error" on https://www.atatus.com/tools/xpath-validator.

Is El[text()=('data2','xxx')] a valid XPath expression?

I know that it is possible to replace the expression with El[text()='data2' or text()='xxx'], but I receive the XPath from outside and want to avoid converting it if possible.


Solution

  • The issue is that your more complex expression uses the XPath 2.0 , operator to construct a sequence which is a data structure in XPath 2.0 and later but not in XPath 1.0.

    /*/El[text()=('data2','xxx')]
    

    In XPath 2.0, the expression ('data2') defines a string, which is the same thing as a sequence of one string, and the expression ('data2', 'xxx') defines a sequence of two strings.

    In XPath 1.0, the expression ('data2') defines a string, and the expression ('data2', 'xxx') is invalid.

    You will either need to upgrade your XPath processor to version 2 or later, or else you will, as you suspected, need to use a different XPath expression for your XPath 1 processor, such as e.g.

    /*/El[text()='data2' or text()='xxx']