0

Edit: My solution, based on the chosen answer:

var $brs, 
    $chunks = [];

$brs = $('hr:eq(1)').nextUntil($('hr:eq(2)')).filter('br');
$chunks.push($('hr:eq(1)').nextUntil($brs.eq(0)));
for (i = 0; i < $brs.length - 1; i++) {
    $chunks.push($brs.eq(i).nextUntil($brs.eq(i+1)));
}

I have an unusual case that's resulted from a VERY poorly written website I am attempting to parse with javascript. I won't delve into the fun parsing, but I've finally managed to mangle it down to a meaningful structure. I now have a DOM that looks like this (for all intents and purposes, look at this as a flat listing of tags, each closed before the next starts):

<hr>
<a>
<span class="desc">
[<a>*]      // 0 or more anchor tags can show up here
<br>
<br>
<a>
<span class="desc">
[<a>*]
<br>
<br>
.
.
.

What I am looking to do is grab each cluster of tags into its own array/jquery object/whatever by, essentially, running a .split() on the <br> tags. It is possible to do such a thing? if not, how would you go about separating this into chunks? So the result would be this:

[<a>, <span class="desc">, <a>],
[<a>, <span class="desc">],
[<a>, <span class="desc">, <a>, <a>, <a>],
[<a>, <span class="desc">],
...
2
  • If you try and index i+1 within the for-loop your index goes out of bounds on the very last case and .eq() will return an empty object; this means there's no stopping condition for the last .nextUntil() and everything (siblings) following the last br will be pushed into the last index of $chunks (including the second hr). Take a look at the array and you should notice that happening. If there's nothing following the last br, consider changing the loop condition to i<brs.length-1. Commented Jul 19, 2012 at 0:34
  • @nbrooks Ah yes, good call. The console was compressing the last 246 array entries, so I didn't see that happenening. (I'm dealing with ~617 sets of the above structure.) Commented Jul 19, 2012 at 18:30

1 Answer 1

1

I'm not sure why you're doing that instead of just modifying the html, but it's technically possible using the .nextUntil jQuery method.

Starting at the hr, select all sibling elements until the first br and push the jQuery set into an array. Repeat this process between each pair of line-breaks. .eq() can be used to target a specific br.

var $brList = $("br");
var domArray = [];
for(var i=0; i < $brList.length; i++){
    if(i==0){
        domArray.push($("hr").nextUntil($brList.eq(i)));
        continue;
    }
    domArray.push($brList.eq(i-1).nextUntil($brList.eq(i)));
}

Of course the specified selectors will find all br or hr elements on the page, so you will need to make your selectors more specific if there are others. You can do this by providing a context for the selector to look in.


If you don't want to keep the entire jQuery object in the array (though you probably do want to because you can retrieve DOM elements using the regular array methods -- with the added benefit of having all of the jQuery functionality available) you can convert the jQuery object to a regular array. jQuery's .toArray() method will take care of that for you:

domArray.push(
    $brList.eq(i-1)
           .nextUntil($brList.eq(i))
           .toArray()
);
Sign up to request clarification or add additional context in comments.

8 Comments

Excellent, nextUntil() is the kind of thing I was looking for, I think. I'll try this out tonight. What do you mean by "instead of just modifying the html"? I've basically stripped the website of all its structure at this point to get something with a pattern that's actually useful, so I'm not afraid to modify it further if that would result in a nice easy way to pull out the chunks.
@coldcandor Glad it was helpful. By modifying the html though what I meant was wrapping each relevant section of code (e.g. everything between two br elements) in a <div></div> then just getting the children of each div. But that's just an alternative
I see what you mean, but I think I would have needed the nextUntil() for that too. That was the key I was missing, though your br indexing was a great idea too. Thanks!
Nope, no need for .nextUntil(): <div class='top'> <div></div>...<div></div> </div>. $('.top div').each(function() { $chunks.push( $(this).children() ); } ); :)
It's still a flat DOM though. How would I know where to create and end the divs without nextUntil? Processing them once I got them in that form is certainly easy enough, it's the getting there that hurts.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.