j1mmy
j1mmy

Reputation: 41

Nokogiri: apply class to element that has a certain descendant

Let's say I have this html that has various depths of descendants and a mixture of element types:

<div class="foo">
    <div class="bar"></div>
</div>
<div class="foo">
    <div class="baz"></div>
</div>
<div class="foo">
    <u><span class="duh">
        <div class="bar"></div>
    </span></u>
</div>
<div class="foo">
    <div class="baz"></div>
</div>

And I want to apply a class of bex to all the foos that contain classes of bar so it looks like:

<div class="bex">
    <div class="bar"></div>
</div>
<div class="foo">
    <div class="baz"></div>
</div>
<div class="bex">
    <u><span class="duh">
        <div class="bar"></div>
    </span></u>
</div>
<div class="foo">
    <div class="baz"></div>
</div>

How wld I do that with ruby/nokogiri? Tried all sorts of things and can't quite get it. Thanks.

Edit: closed the duh, oops.

Upvotes: 1

Views: 116

Answers (1)

Eric Duminil
Eric Duminil

Reputation: 54223

I spent a long time wondering why the second foo wasn't found. Your data is broken, "duh isn't closed.

To select the nodes, you can use :

doc.xpath("//div[@class='foo' and .//div[@class='bar']]")

As an example :

data = %q(<div class="foo">
    <div class="bar"></div>
</div>
<div class="foo">
    <div class="baz"></div>
</div>
<div class="foo">
    <u><span class="duh">
        <div class="bar"></div>
    </span></u>
</div>
<div class="foo">
    <div class="baz"></div>
</div>)

require 'nokogiri'

doc = Nokogiri.HTML(data)

doc.xpath("//div[@class='foo' and .//div[@class='bar']]").each do |node|
  node["class"] = 'bex'
end

puts doc

Upvotes: 1

Related Questions