Skip to content

Commit

Permalink
another fix for the 'descendant' problem in cssselect to undo a serio…
Browse files Browse the repository at this point in the history
…us performance regression in 2.3.1

--HG--
extra : rebase_source : 2c4c89423870a16cc9aedc19532032d2a10bae5e
  • Loading branch information
scoder committed Nov 3, 2011
1 parent ba9b186 commit 5fc9eac
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 8 deletions.
16 changes: 12 additions & 4 deletions CHANGES.txt
Expand Up @@ -20,6 +20,13 @@ Features added
Bugs fixed
----------

* Fixed the "descendant" bug in cssselect a second time (after a first
fix in lxml 2.3.1). The previous change resulted in a serious
performance regression for the XPath based evaluation of the
translated expression. Note that this breaks the usage of some of
the generated XPath expressions as XSLT location paths that
previously worked in 2.3.1.

Other changes
--------------

Expand Down Expand Up @@ -69,10 +76,11 @@ Bugs fixed
* Assertion error in lxml.html.cleaner when discarding top-level elements.

* In lxml.cssselect, use the xpath 'A//B' (short for
'A/descendant-or-self::node()/B') instead of 'A/descendant::B' for the css
descendant selector ('A B'). This makes a few edge cases to be consistent
with the selector behavior in WebKit and Firefox, and makes more css
expressions valid location paths (for use in xsl:template match).
'A/descendant-or-self::node()/B') instead of 'A/descendant::B' for
the css descendant selector ('A B'). This makes a few edge cases
like ``"div *:last-child"`` consistent with the selector behavior in
WebKit and Firefox, and makes more css expressions valid location
paths (for use in xsl:template match).

* In lxml.html, non-selected ``<option>`` tags no longer show up in the
collected form values.
Expand Down
2 changes: 1 addition & 1 deletion src/lxml/cssselect.py
Expand Up @@ -494,7 +494,7 @@ def xpath(self):

def _xpath_descendant(self, xpath, sub):
# when sub is a descendant in any way of xpath
xpath.join('//', sub.xpath())
xpath.join('/descendant-or-self::*/', sub.xpath())
return xpath

def _xpath_child(self, xpath, sub):
Expand Down
6 changes: 3 additions & 3 deletions src/lxml/tests/test_css.txt
Expand Up @@ -95,7 +95,7 @@ Now of translation:
>>> xpath('E:nth-last-of-type(1)')
*/e[position() = last() - 1]
>>> xpath('div E:nth-last-of-type(1) .aclass')
div//e[position() = last() - 1]//*[contains(concat(' ', normalize-space(@class), ' '), ' aclass ')]
div/descendant-or-self::*/e[position() = last() - 1]/descendant-or-self::*/*[contains(concat(' ', normalize-space(@class), ' '), ' aclass ')]
>>> xpath('E:first-child')
*/*[name() = 'e' and (position() = 1)]
>>> xpath('E:last-child')
Expand All @@ -119,15 +119,15 @@ Now of translation:
>>> xpath('E:not(:contains("foo"))')
e[not(contains(css:lower-case(string(.)), 'foo'))]
>>> xpath('E F')
e//f
e/descendant-or-self::*/f
>>> xpath('E > F')
e/f
>>> xpath('E + F')
e/following-sibling::*[name() = 'f' and (position() = 1)]
>>> xpath('E ~ F')
e/following-sibling::f
>>> xpath('div#container p')
div[@id = 'container']//p
div[@id = 'container']/descendant-or-self::*/p
>>> xpath('p *:only-of-type')
Traceback (most recent call last):
...
Expand Down

0 comments on commit 5fc9eac

Please sign in to comment.