2

I have a DOM:

<body>
      <div>
         <h1 id="header1">home1</h1>
         <a id="link1">link1</a>
         <p id="para1">things1</p>
      </div>
      <span>
         <h1 id="header2">home2</h1>
         <a id="link2">link2</a>
         <p id="para2">para2</p>
      </span>
</body>

I want to index this to JSON like:

{
"body": {
    "div": [
        {
            "h1": "header1",
            "a": "link1",
            "p": "para1"
        }
    ],
    "span": [
        {
            "h1": "header2",
            "a": "link2",
            "p": "para2"
        }
    ]
  }
}

I've tried this:

  function indexELEMS()
  {
    listy = $("*[id]").map(function(){

        outy = this.tagName+":"+this.id;

        return outy;
    }).get();

    DOMobj = $.extend({}, listy);

    console.log(DOMobj);

  }

But I get something like this:

0:"h1:home"
1:"a:link1"
2:"p:things1"

Understandable, I've just told the function to do that.

But if I try it on just the h1's like this:

  function indexELEMS()
  {
           outy = {};
    listy = $("h1[id]").map(function(){

        outy.h1s = this.tagName+":"+this.id;

        return outy;
    }).get();

    DOMobj = $.extend({}, listy);

    console.log(DOMobj);

  }

It will overwrite the outy.h1s with the last one, how do I add it to the (JSON)object?

Or better yet, how do I get the whole document element structure output in nice JSON form?

I could do: $('document > body > div > h1').attr('id') every time, but that's pretty inefficient and resource intensive, I want to cache all the elements and then read them out, and when they change, (maybe I'll watch the object with .watch), or is added in the object, create an element in the appropriate position.

Or is there a better way get an overview of which elements have IDs (and check if that ID is duplicate or not), some native function?

I'm also afraid that the JSON Object won't allow multiple div: entries?

Or should I just go for the jQuery selector completely and stop whining about efficiency?

(edit: Ok, the multiple div part is maybe not possible, or can't I access the second one with .div[1] ?)

So, my main question would be, if you take the indexELEMS function, how can I get an object that is accesibly by:

DOMobj.body.div.h1 

So I can do an If == on it, or cycle through it with div.[index] in a $.each loop

I would think, cycling through DOMobj.body[index] instead of $(''), oh wait, can I actually access the object created from $('')? like .body? It can't be that easy..

TrySpace
  • 2,233
  • 8
  • 35
  • 62
  • JavaScript objects are not JSON. But apart from that, IDs don't seem to be relevant in the output what exactly are you trying to accomplish? Do you want a list of elements which have IDs? – Felix Kling Jun 21 '12 at 17:08
  • Yes, but that I already have, I just want an index that's readable like JSON. And then do stuff with it, clone elements etc. Especially handy when an elements innerHTML changes. I don't want to set a listener to every individual element, nor do I want' to 'scan' the whole page again each time something changes. If I know which element i'm changing, then I can modify the object, and when that object changes a value/property, it will change or replace the specific element, ok, maybe I would want to c# that, but I don't – TrySpace Jun 21 '12 at 17:51
  • Oh i see what you mean, I now edited the JSON to match the IDs. I could also have another level, where I put in the innerHTML of that element in a 'subbranch' [{"":""}] after h1, a, p, etc. – TrySpace Jun 21 '12 at 17:55
  • Ok... I still don't understand what you want to achieve with that, but creating such an object is not difficult. – Felix Kling Jun 21 '12 at 17:56

1 Answers1

1

Your structure is internally inconsistent: <body> has an object child, but all its children are array-with-a-single-object. Should this map to any page DOM or just some custom one of your own?

If you want any DOM to be able to be represented as JSON, is what you seek rather something like this?

[ { "tag": "body"
  , "children":
    [ { "tag": "div"
      , "children":
        [ { "tag": "h1"
          , "id": "header1"
          }
        , { "tag": "a"
          , "id": "link1"
          }
        , { "tag": "p"
          , "id": "para1"
          }
        ]
      }
    , { "tag": "span"
      , "children":
        [ { "tag": "h1"
          , "id": "header2"
          }
        , { "tag": "a"
          , "id": "link2"
          }
        , { "tag": "p"
          , "id": "para2"
          }
        ]
      }
    ]
  }
]

If you only use case for this JSON object to answer queries about the DOM, and do some iteration, you're probably best off using $('your.selector.here').each and similar code performing the tests you want.

If you want to index manually all the way down through the DOM (find the <body>'s second <div> child's fifth <a> element, and tell me if its id attribute is "link5"), you want XPath:

document.evaluate('//body/div[2]/a[5]/@id = "link5"', document).booleanValue
ecmanaut
  • 5,030
  • 2
  • 44
  • 66