Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between nth-child() and eq()

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 ?

like image 730
Arup Rakshit Avatar asked Jan 14 '23 05:01

Arup Rakshit


1 Answers

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.

like image 170
Mark Thomas Avatar answered Jan 19 '23 00:01

Mark Thomas