You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
While working on #2560 (re-implementing the CSS-selector-to-XPath-expression subsystem), I realized that the current code has incorrectly implemented the pseudo-class functions nth-of-type et al.
This should be fixed by the ongoing work, but I wanted to capture this bug for posterity (and to help support the value of the rewrite!).
Help us reproduce what you're seeing
#! /usr/bin/env rubyrequire"bundler/inline"gemfiledosource"https://rubygems.org"gem"nokogiri",path: "."end# A table with 20 rows, each row has one class in common and a rotating set of five other classes.html=<<~HTML<html><body><divid="container-1"><spanclass="common first-in-5n" >1</span><bclass="common second-in-5n">2</b><iclass="common third-in-5n" >3</i><spanclass="common fourth-in-5n">4</span><bclass="common fifth-in-5n" >5</b><iclass="common first-in-5n" >6</i><spanclass="common second-in-5n">7</span><bclass="common third-in-5n" >8</b><iclass="common fourth-in-5n">9</i><spanclass="common fifth-in-5n" >10</span><bclass="common first-in-5n" >11</b><iclass="common second-in-5n">12</i><spanclass="common third-in-5n" >13</span><bclass="common fourth-in-5n">14</b><iclass="common fifth-in-5n" >15</i><spanclass="common second-in-5n">99</span><spanclass="common second-in-5n">100 here just to prove a point</span></div></body></html>HTMLdoc=Nokogiri::HTML5(html)# In a browser, "#container-1 span.second-in-5n:nth-of-type(3)" returns:## <span class="common second-in-5n">7</span>## This is the correct behavior that Nokogiri should exhibit. It's asking for the third "span" but# only if it ALSO has the class `second-in-5n`. That is, the returned node must match BOTH# conditions.# But Nokogiri returns a different row:doc.css("#container-1 span.second-in-5n:nth-of-type(3)").to_html# => "<span class=\"common second-in-5n\">100 here just to prove a point</span>"# Let's look at the XPath generated by Nokogiri ...Nokogiri::CSS.xpath_for("#container-1 span.second-in-5n:nth-of-type(3)")# => ["//*[@id='container-1']//span[contains(concat(' ',normalize-space(@class),' '),' second-in-5n ')][position()=3]"]## Ruh roh! Because this uses a separate predicate for the position check:## [position()=3]"]## this query will return the third "span.second-in-5n"!# Let's try to fix this by using "and" to combine the conditions into a single complex predicate.## Here's the original expression for easy comparison:# # "//*[@id='container-1']//span[contains(concat(' ',normalize-space(@class),' '),' second-in-5n ')][position()=3]"fixed_xpath_expr="//*[@id='container-1']//span[contains(concat(' ',normalize-space(@class),' '),' second-in-5n ') and position()=3]"doc.xpath(fixed_xpath_expr).to_html# => "<span class=\"common second-in-5n\">7</span>"## Woot! This results in the correct behavior.# For comparison, this bug doesn't appear to affect `nth-child` queries. For example:## document.querySelectorAll('#container-1 span.second-in-5n:nth-child(7)')## returns## <span class="common second-in-5n">7</span>## and so does Nokogiri:doc.css('#container-1 span.second-in-5n:nth-child(7)').to_html# => "<span class=\"common second-in-5n\">7</span>"# The XPath generated by Nokogiri is:Nokogiri::CSS.xpath_for("#container-1 span.second-in-5n:nth-child(7)")# => ["//*[@id='container-1']//span[contains(concat(' ',normalize-space(@class),' '),' second-in-5n ') and count(preceding-sibling::*)=6]"]## This is right! It counts the number of overall siblings, and puts the conditional into the single predicate.
This will be fixed by the work being done for #2560.
The text was updated successfully, but these errors were encountered:
Please describe the bug
While working on #2560 (re-implementing the CSS-selector-to-XPath-expression subsystem), I realized that the current code has incorrectly implemented the pseudo-class functions nth-of-type et al.
This should be fixed by the ongoing work, but I wanted to capture this bug for posterity (and to help support the value of the rewrite!).
Help us reproduce what you're seeing
This will be fixed by the work being done for #2560.
The text was updated successfully, but these errors were encountered: