jela
jela

Reputation: 1469

why does this xpath selector fail?

given the following html

<p>
    <div class="allpricing">
      <p class="priceadorn">
          <FONT CLASS="adornmentsText">NOW:&nbsp;</FONT>
          <font CLASS="adornmentsText">$1.00</font>
      </p>
    </div>
</p>

why does

//div[@class="allpricing"]/p[@class="priceadorn"][last()]/font[@class="adornmentsText"][last()]

return the expected value of $1.00

but adding the p element

//p/div[@class="allpricing"]/p[@class="priceadorn"][last()]/font[@class="adornmentsText"][last()]

returns nothing?

Upvotes: 2

Views: 106

Answers (4)

Michael Kay
Michael Kay

Reputation: 163342

You describe your source as an HTML rather than an XML document, but you haven't explained how you parsed it. If you parse it using an HTML parser, the parser will "repair" it to turn it into valid HTML, which means that the tree it constructs doesn't directly reflect what you wrote in the source. XPath sees this "repaired" tree, not the original.

Upvotes: 0

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243479

XPath is case-sensitive.

None of the provided XPath expressions selects any node, because in the provided XML document there is no font element with an attribute named class (the element font has a CLASS attribute and this is different from having a class attribute due to the different capitalization).

Due to the same reason, font and FONT are elements with different names.

These two XPath expressions, when evaluated against the provided XML document, produce the same wanted result:

   //div[@class="allpricing"]
       /p[@class="priceadorn"]
                       [last()]
          /font[@CLASS="adornmentsText"]
                               [last()] 

and

//p/div[@class="allpricing"]
      /p[@class="priceadorn"]
                        [last()]
         /font[@CLASS="adornmentsText"]
                                   [last()]

XSLT - based verification:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:copy-of select=
  '//div[@class="allpricing"]
       /p[@class="priceadorn"]
                       [last()]
          /font[@CLASS="adornmentsText"]
                               [last()]'/>
=============
  <xsl:copy-of select=
   '//p/div[@class="allpricing"]
          /p[@class="priceadorn"]
                            [last()]
             /font[@CLASS="adornmentsText"]
                                       [last()]
   '/>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<p>
    <div class="allpricing">
      <p class="priceadorn">
          <FONT CLASS="adornmentsText">NOW:&#xA0;</FONT>
          <font CLASS="adornmentsText">$1.00</font>
      </p>
    </div>
</p>

the two expressions are evaluated and the results of this evaluation are copied to the output:

<font CLASS="adornmentsText">$1.00</font>
=============
  <font CLASS="adornmentsText">$1.00</font>

Upvotes: 0

fahad.hasan
fahad.hasan

Reputation: 912

I've often found that fixing the cases was the culprit. XPath 1.0 is case sensitive and unless you take care of the mixed cases explicitly, it will fail in a lot of cases.

Upvotes: 0

choroba
choroba

Reputation: 241918

You cannot place a div inside a p. The div start closes the p automatically. See Nesting block level elements inside the <p> tag... right or wrong?

Upvotes: 3

Related Questions