Search code examples
javascriptjquerydomdom-traversal

(Re-) Modelling DOM as specific projection JavaScript || jQuery


I would like to create a specific projection of the DOM tree, with only some attributes instead of DOM nodes.

Let's say we have this HTML:

<div data-foo="bar0">
   <div data-foo="bar1">
      <div>
          <div data-foo="bar2">
          </div>
          <div data-foo="bar3">
          </div>
      </div>
   </div>
   <div data-foo="bar4">
   </div>
</div>

I would like to only get the data-foo attributes, but hold the DOM tree's arrangement. ( Every node, that doesn't have data-foo attribute shall be ignored. )

I imagine the result of the example above after the harvesting like this: ( As an array / object )

someStorageVariableForTheDOMFootPrint["bar0"]

shall have two indexes in it, bar1 and bar4. Going further, bar1 index shall be an array again, containing two indexes bar2 and bar3. These can all be empty variables, the index, and the array / object structure is important.

No DOM nodes, no context, nothing shall be stored only the data-foo attribute, but in the structure of the DOM tree.

How should I start right?


Solution

  • Basically, what you want to do is create an object graph that's a transformation of your DOM object graph, into a result probably looking something like this:

    {
        "foo": "bar0",
        "children": [
            {
                "foo": "bar1",
                "children": [
                    {
                        "foo": "bar2",
                        "children": []
                    },
                    {
                        "foo": "bar3",
                        "children": []
                    }
                ]
            },
            {
                "foo": "bar4",
                "children": []
            }
        ]
    }
    

    I got interested, and found it's surprisingly easy to do: Live Example

    function graph(element) {
        var rv, child, $element, index;
    
        // Wrap the element
        $element = $(element);
    
        // Our non-DOM equivalent object
        rv = {
            foo: $element.attr("data-foo")
        };
    
        // Get its children
        rv.children = $element.children().get().map(graph);
    
        // If any children are missing foo, replace them with their children
        index = 0;
        while (index < rv.children.length) {
            child = rv.children[index];
            if (!child.foo) {
                // No foo, replace the element with its children
                replaceElementWith(rv.children, index, child.children);
                index += child.children.length;
            } else {
                ++index;
            }
        }
        return rv;
    }
    
    // Replace the array element at the given position with the elements from
    // the given array
    function replaceElementWith(array, index, newElements) {
        var args = [index, 1];
        if (newElements.length) {
            args.push.apply(args, newElements);
        }
        array.splice.apply(array, args);
    }