sparklemotion/nokogiri

CSS `foo~:nth-child(2)` gives incorrect XPath

Open

#707 opened on Jun 18, 2012

View on GitHub
 (3 comments) (0 reactions) (0 assignees)Ruby (5,615 stars) (806 forks)batch import
help wantedneeds/fix-for-failing-testtopic/css

Description

Hi,

I’m the maintainer of cssselect, which does in Python pretty much the same as Nokogiri for CSS selectors: translate them to XPath. It looks like the SimonSapin/cssselect#12 bug also applies to Nokogiri. Namely, the XPath translation of :nth-child() and similar pseudo-classes is wrong when used after the + or ~ combinator. Here is a test case:

require 'nokogiri'
doc = Nokogiri::XML('<root><child1/><child2/><child3/></root>')
puts doc.css(':nth-child(2)').map { |e| e.name }
puts doc.css('child1 ~ :nth-child(2)').map { |e| e.name }

Expected output: child2 child2. Actual output child2 child3.

The problem is in the XPath translation of the later selector: //child1/following-sibling::*[position() = 2 and self::*] gives the element at position 2 when counting from child1, while we want the position among the parent’s children.

I am not sure it is even possible to correctly translate this selector to XPath: the = XPath operator on node-sets compares the text content of elements, not their identity.

The issue is similar for SimonSapin/cssselect#4 and Nokogiri’s #394.

Contributor guide