I gone through the link Difference between nth-child() and eq()
. Which says that -
it is very straight forward. nth-child is 1 indexed while eq is 0 indexed. nth-child is based on the current elements parent, while .eq is based off of the index of the current element relative to the selected elements. they are two completely different methods with two completely different purposes.
Now to get the things properly I wrote the below code:
doc = Nokogiri::HTML::Document.parse(<<-eohtml)
<html>
<head>
<style>
div { float:left; }
span { color:blue; }
</style>
</head>
<body>
<div>
<p>div1 p1</p>
<p>div1 p2</p>
<p>div1 p3</p>
<p>div1 p4</p>
</div>
<div>
<p>div2 p1</p>
<p>div2 p2</p>
<p>div2 p3</p>
<p>div2 p4</p>
</div>
</body>
</html>
eohtml
p doc.css("div p:eq(2)").map { |e| e.text }
p doc.css("div p:nth-child(2)").map { |e| e.text }
# >> ["div1 p2", "div2 p2"] Expected ["div1 p3", "div2 p3"]
# >> ["div1 p2", "div2 p2"]
Can any on help me to understand where I did wrong? Actually with this output I don't understand the difference between these 2 css selectors.
EDIT
I am not good with XPATH
concept. I tried to convert the CSS rules
to XPATH
as below:
Nokogiri::CSS.xpath_for("div p:eq(2)")
Nokogiri::CSS.xpath_for("div p:nth-child(2)")
# >> ["//div//p[position() = 2]"]
# >> ["//div//*[position() = 2 and self::p]"]
Can anyone help me by explain the xpath
expression, hope then it will make sense to me ?
The first one:
Nokogiri::CSS.xpath_for("div p:eq(2)")
# >> ["//div//p[position() = 2]"]
This is also known as //div//p[2]
and it means "return the second p
elements" no matter whether they have other sibling elements.
The second one:
Nokogiri::CSS.xpath_for("div p:nth-child(2)")
# >> ["//div//*[position() = 2 and self::p]"]
This means "find all elements in the second position, and return them ONLY if they also happen to be a p
.
Example
Consider the following HTML:
<html>
<body>
<div>
<p>Div1p1</p>
<i>Div1i1</i>
<p>Div1p2</p>
</div>
<div>
<p>Div2p1</p>
<p>Div2p2</p>
<p>Div2p3</p>
</div>
</body>
</html>
The output of //p[2]
will be:
<p>Div1p2</p>
<p>Div2p2</p>
because "Div1p2" is the second p
in the first div
, and "Div2p2" is the second p
in the second div
.
The output of //*[position()=2 and self::p]
will be:
<p>Div2p2</p>
because the second element of the first div is an i
, not a p
. But the second element of the second div also happens to be a p
so it matches.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With