-1

Using ruby/nokogiri I would like to wrap some elements starting at one element and ending before the next one of those elements. So lets say I have:

<div class="foo"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="foo"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
<div class="foo"></div>
<div class="foo"></div>
<div class="bar"></div>
<div class="bar"></div>

And I want to wrap all foos and their contiguous bars (if there are any) in a baz class that closes before the next foo (last one obvs doesn't have another foo), like this:

<div class="baz">
    <div class="foo"></div>
    <div class="bar"></div>
    <div class="bar"></div>
</div>
<div class="baz">
    <div class="foo"></div>
    <div class="bar"></div>
    <div class="bar"></div>
    <div class="bar"></div>
    <div class="bar"></div>
</div>
<div class="baz">
    <div class="foo"></div>
</div>
<div class="baz">
    <div class="foo"></div>
    <div class="bar"></div>
    <div class="bar"></div>
</div>

Thanks.

Edit: I found this that asks a similar question but I'm struggling to adapt it XPath axis, get all following nodes until

Edit 2:This will return the bars after the foo but not the foo:

body.xpath("(//div[@class='foo'])[1]/following-sibling::div[@class='bar']
    [1 = count(preceding-sibling::div[@class='foo'][1] | (//div[@class='foo'])[1])]")

Need to figure out how to include the foo!

Edit 3: Welp this will add the foo:

body.xpath("//div[@class='foo'][1]","//div[@class='foo']
    [1]/following-sibling::div[@class='bar']
    [1 = count(preceding-sibling::div[@class='foo'][1] | (//div[@class='foo'])[1])]")

But the bigger problem is I'm not sure how to iterate this? It just returns the first set of foo + bars.

Edit 4: Iterating through the foo-bar chunks:

var = 1
loop do 
  chunk = body.xpath("//div[@class='foo'][#{var}]","//div[@class='foo']
    [#{var}]/following-sibling::div[@class='bar']
    [1 = count(preceding-sibling::div[@class='foo'][#{var}] | 
    (//div[@class='foo'])[1])]")
  puts chunk
  var += 1
  break if chunk.length == 0
end

Not sure how to wrap them in divs now.

Community
  • 1
  • 1
j1mmy
  • 41
  • 6

1 Answers1

0

Welp I have a likely inelegant solution for the followers of this insanely popular question:

var = 1
loop do 
  chunk = body.xpath("//div[@class='foo'][#{var}]","//div[@class='foo']
    [#{var}]/following-sibling::div[@class='bar']
    [1 = count(preceding-sibling::div[@class='foo'][#{var}] | 
    (//div[@class='foo'])[1])]")
  break if chunk.length == 0      
  var += 1
  puts <div class="baz">
  puts chunk
  puts </div>
end
j1mmy
  • 41
  • 6