Xpath error with not () and end-with ()

I have the following Xpath expression:

//*[not(input)][ends-with(@*, 'Copyright')] 

I expect it to provide me with all the elements - except input - with any attribute value that ends in "Copyright".

I execute it in the Selenium 2 Java interface using webDriver.findElements(By.xpath(expression)) and get the following error:

Expression is not legal Expression

But these expressions work without problems:

 //*[not(input)][starts-with(@*, 'Copyright')] //*[ends-with(@*, 'Copyright')] 

Any ideas?

+7
source share
4 answers

I have the following Xpath expression:

 //*[not(input)][ends-with(@*, 'Copyright')] 

I expect it to give me all the elements - except the input - with any attribute value that ends with "Copyright".

There are several issues here :

  • ends-with() is a standard XPath 2.0 function, so it is likely that you are using the XPath 1.0 engine and it will correctly throw an error because it does not know about a function called ends-with() .

  • Even if you are working with an XPath 2.0 processor, the ends-with(@*, 'Copyright') expression will lead to an error in the general case, because the ends-with() function is defined to accept the maximum allowable single string ( xs:string? ) as both its operands, however, @* creates a sequence of more than one line in the case when an element has more than one attribute.

  • //*[not(input)] does not mean "select all elements that are not called input . Actual value:" Select all elements that do not have a child named "input".

Decision

  • Use this XPath 2.0 expression: //*[not(self::input)][@*[ends-with(.,'Copyright')]]

  • For XPath 1.0, use this expression:

....

  //*[not(self::input)] [@*[substring(., string-length() -8) = 'Copyright']] 

Here is a short and complete check of the latest XPath expression using XSLT:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="/*"> <xsl:copy-of select= "//*[not(self::input)] [@*[substring(., string-length() -8) = 'Copyright' ] ]"/> </xsl:template> </xsl:stylesheet> 

when this conversion is applied to the following XML document:

 <html> <input/> <ax="Copyright not"/> <ay="This is a Copyright"/> </html> 

required, the correct result is obtained :

 <ay="This is a Copyright"/> 

In case the XML document is in the default namespace :

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:x="http://www.w3.org/1999/xhtml" > <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="/*"> <xsl:copy-of select= "//*[not(self::x:input)] [@*[substring(., string-length() -8) = 'Copyright' ] ]"/> </xsl:template> </xsl:stylesheet> 

when applied to this XML document :

 <html xmlns="http://www.w3.org/1999/xhtml"> <input z="This is a Copyright"/> <ax="Copyright not"/> <ay="This is a Copyright"/> </html> 

the desired, correct result is output:

 <a xmlns="http://www.w3.org/1999/xhtml" y="This is a Copyright"/> 
+5
source

I do not know Selenium, but if //*[not(input)][starts-with(@*, 'Copyright')] successfully parsed and if the XPath 2.0 ends-with function is additionally supported, then I see no reason why //*[not(input)][ends-with(@*, 'Copyright')] not accepted as a legal expression. Your verbal description, however, sounds as if you want //*[not(self::input)][@*[ends-with(., 'Copyright')]] .

//*[not(input)] selects any elements that do not have a child element, and //*[not(self::input)] selects any elements that are not input elements themselves. As for comparing [@*[ends-with(., 'Copyright')]] with what you have, my suggestion is true if there is any node attribute that ends with β€œCopyright” while your the test will work only if there is one attribute that ends with "Copyright", like end-with http://www.w3.org/TR/xquery-operators/#func-ends-with allow a sequence with one element as its first argument or an empty sequence, but not a few elements.

+1
source

Most likely, the explanation is that you are using XPath 1.0 processors. The end-with () function requires XPath 2.0 support.

0
source
 //*[not(self::input)][@*[substring(., string-length(.) -8) = 'Copyright']] 

There may be a slight correction with string-length(.)

Now it might work.

0
source

All Articles