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"/>