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

前端 未结 4 1900
时光说笑
时光说笑 2021-01-05 11:58

I have the following Xpath expression:

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

I expect it to give me all elements - except input - w

相关标签:
4条回答
  • 2021-01-05 12:18
    //*[not(self::input)][@*[substring(., string-length(.) -8) = 'Copyright']]
    

    May be small correction with string-length(.)

    Now, it may work.

    0 讨论(0)
  • 2021-01-05 12:20

    I have the following Xpath expression:

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

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

    There are a few issues here:

    1. ends-with() is a standard XPath 2.0 function only, so the chances are you are using an XPath 1.0 engine and it correctly raises an error because it doesn't know about a function called ends-with().

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

    3. //*[not(input)] doesn't mean "select all elements that are not named input. The real meaning is: "Select all elements that dont have a child element named "input".

    Solution:

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

    2. In the case of XPath 1.0 use this expression:

    ....

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

    Here is a short and complete verification of the last 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 transformation is applied on the following XML document:

    <html>
     <input/>
     <a x="Copyright not"/>
     <a y="This is a Copyright"/>
    </html>
    

    the wanted, correct result is produced:

    <a y="This is a Copyright"/>
    

    In the case of the XML document being in a 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 on this XML document:

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

    the wanted, correct result is produced:

    <a xmlns="http://www.w3.org/1999/xhtml" y="This is a Copyright"/>
    
    0 讨论(0)
  • 2021-01-05 12:21

    I don't know Selenium but if //*[not(input)][starts-with(@*, 'Copyright')] is parsed successfully and if additionally the XPath 2.0 function ends-with is supported then I don't see any reason why //*[not(input)][ends-with(@*, 'Copyright')] is 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 not having any input child element while //*[not(self::input)] selects any elements not being themselves input elements. As for comparing [@*[ends-with(., 'Copyright')]] with what you have, my suggestion is true as long as there is any attribute node which ends with 'Copyright' while your test would only work if there is a single attribute which ends with 'Copyright', as ends-with http://www.w3.org/TR/xquery-operators/#func-ends-with allow a sequence with a single item as its first argument or an empty sequence but not several items.

    0 讨论(0)
  • 2021-01-05 12:24

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

    0 讨论(0)
提交回复
热议问题