3

Problem Overview

Let's say I have a shipment of candy. The shipment has a number of boxes, and each box has a number of unique candy types. Every box has a unique id, different from every other box; the same is true for candy types. Furthermore, a candy has additional traits, like color, flavor and quantity.

Example Code

Take the following HTML example:

<div class="shipment">
    <div class="box" data-boxid="a">
        <div class="candy" data-candyid="1" data-color="orange" data-flavor="orange" data-qty="7">
            <!-- unimportant content -->
        </div>
        <div class="candy" data-candyid="2" data-color="red" data-flavor="strawberry" data-qty="4">
            <!-- unimportant content -->
        </div>
    </div>
    <div class="box" data-boxid="b">
        <div class="candy" data-candyid="3" data-color="green" data-flavor="lime">
            <!-- unimportant content -->
        </div>
    </div>
</div>

Previous Attempts

I've seen similar examples of table parsing with jQuery's .map() function, and I've also seen mention of .each(), but I've been unable to generate any working code.

Desired Output

I want to generate (with jQuery) a JSON object similar to the following:

{
    "shipment": {
        "a": {
            "1": {
                "color": "orange",
                "flavor": "orange",
                "qty": "7"
            },
            "2": {
                "color": "red",
                "flavor": "strawberry",
                "qty": "4"
            }
        },
        "b": {
            "3": {
                "color": "green",
                "flavor": "lime"
            }
        }
    }
}

Additional Notes

My app already uses jQuery extensively, so it seems like a logical tool for the job. However, if plain 'ol JavaScript is a more appropriate choice, feel free to say so.

The HTML is always going to be well-formed and always going to follow a the format specified. However, in some cases, information may be incomplete. Note that the third candy had no quantity specified, so quantity was simply ignored while building the object.

2
  • A combination of .each() and .find() should do the trick. Start at the top and work your way to the inner properties. Commented Mar 28, 2013 at 20:13
  • I've tried something similar, but I believe I encountered working with children of children (e.g., nested .each() functions). Could you please post an example? I'm not necessarily asking for a complete solution (after all, this is a fictional example). Just a step in the right direction. Commented Mar 28, 2013 at 20:15

3 Answers 3

8

This generates what you asked for:

var json = {};   

$('.shipment').each(function(i,a) {
    json.shipment = {};

    $(a).find('.box').each(function(j,b) {
        var boxid = $(b).data('boxid');
        json.shipment[boxid] = {};

        $(b).find('.candy').each(function(k,c) {
            var $c = $(c),
                candyid = $c.data('candyid'),
                color = $c.data('color'),
                flavor = $c.data('flavor'),
                qty = $c.data('qty');
            json.shipment[boxid][candyid] = {};
            if (color) json.shipment[boxid][candyid].color = color;
            if (flavor) json.shipment[boxid][candyid].flavor = flavor;
            if (qty) json.shipment[boxid][candyid].qty = qty;
        });
   });
});

http://jsfiddle.net/mblase75/D22mD/

As you can see, at each level it uses .each() to loop through the elements matching a certain class and then .find().each() to loop through the desired children. In between, .data() is used to grab the desired data- attributes and the json object is built level by level.

Sign up to request clarification or add additional context in comments.

1 Comment

Perfect, thanks! Also, I appreciate the explanation of the code.
3

Is this close to what you are looking for? – http://jsfiddle.net/4RPHL/

I have used data() and JSON.stringify to create the json.

Be sure to check your console where I have logged the output.

$(".candy").each(function() {
    console.log(JSON.stringify($(this).data()))
});

4 Comments

Simple and elegant. This seems like what I'm looking for. How do I nest the .each() function so I can .stringify recursively?
OP specified what the desired output should look like, and this is not it.
Blazemonger: OP used keyword "similar"
It's helpful. But I'm still not clear on how to achieve the nested structure.
1

Nice problem! Thanks to Chris' post I was able to get this to work.

var shipments = [],
    shipment  = {},
    boxes = {},
    candy = {};
$(".shipment").each(function() {
    var shipment = {},
        boxes = {};
    $(this).children().each(function(){
        var boxdata = $(this).data();
        candy = {};
        $(this).children().each(function(){
            var candydata = $(this).data();
            candy[candydata["candyid"]] = {
                color: candydata["color"],
                flavor: candydata["flavor"],
                qty: candydata["qty"]
            };
            boxes[boxdata["boxid"]] = candy;
        });
        //console.log(JSON.stringify(boxes)); // works
    });
    shipment = {shipment: boxes};
    shipments.push(shipment); // for multiples
});

console.log(JSON.stringify(shipments[0]));
console.log(shipments.length);  // 1 for the example html above

Comments

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.