javascript converting a dom structure into a hash object
I need to produce a sensible hash from the selected elements of a DOM structure:
<div name="stuff" class="category">
<div class="category" name="Person">
<div class="option selected" >Kennedy</div>
</div>
<div class="category" name="fruit">
<div class="option" >Apple</div>
<div class="option selected" >Banana</div>
</div>
<div class="category" name="Org">
<div class="option" name="Association">
<div class="option" >NBA</div>
<div class="option selected" >MPAA</div>
</div>
<div class="option" name="Federation">
<div class="option" >Russian</div>
<div class="option" >United Federation of开发者_StackOverflow社区 Planets</div>
</div>
</div>
</div>
<div name="attributes" class="category">
<div class="category" name="color">
<div class="option selected" >red</div>
<div class="option" >yellow</div>
</div>
<div class="category" name="time">
<div class="option selected" >future</div>
<div class="option" >past</div>
</div>
</div>
What's the easiest way to get a sensible hash out of the selected elements here?
There are nested categories, and it is indeterminate how far the nesting goes.
The hash should look something like this:
{
"stuff" : {
"Person": "Kennedy",
"fruit": "Banana",
"Org" : {
"Association": "MPAA",
}
},
"attributes" : {
"color" : "red",
"time" : "future"
}
}
How do I do this? Thanks.
I took another shot at it today: A few things that I noticed were errors from the DOM above. Association and Federation should be categories, not options. It stands to reason that if they were options (eg if Federation and Association were mutually exclusive), then Association would be 'selected'.
Assuming they are categories, here is my code:
function DOMtoJSON(el){
el.find('div.option:not(.selected)').remove();
el.find('div.option:empty').remove();
var createObj = function (thisCategory, parentObj) {
if (thisCategory.children('.option').length > 0) {
parentObj[thisCategory.attr('name')] = thisCategory.children('.option').text();
}
if (thisCategory.children('.category').length > 0) {
parentObj[thisCategory.attr('name')] = {};
thisCategory.children('.category').each(function () {
createObj($(this), parentObj[thisCategory.attr('name')]);
});
} else {
return parentObj;
}
}
var obj = {}
el.children('.category').each(function () {
createObj($(this), obj)
});
return obj;
}
var root = DOMtoJSON($('#root'));
document.getElementById('root').innerHTML = JSON.stringify(root);
Could somebody give me any crituques. That would be great
I've put a working, if clunky-feeling, solution online here: http://jsfiddle.net/btJD6/2/
Here's the code:
function childrenWithAttribute(el,tagName,attrName){
if (!tagName) tagName = '*';
if (!attrName) attrName = 'name';
var kids = [];
for (var i=0,len=el.childNodes.length;i<len;++i){
var kid = el.childNodes[i];
if (tagName!='*' && kid.tagName != tagName) continue;
if (kid.nodeType!=1) continue;
if (!kid.hasAttribute(attrName)) continue;
kids.push(kid);
}
return kids;
}
function objectify(el,kidTags,kidAttr){
if (!kidTags) kidTags = '*';
if (!kidAttr) kidAttr = 'name';
var kids = childrenWithAttribute(el,kidTags,kidAttr);
if (kids.length){
var obj = {};
for (var i=0,len=kids.length;i<len;++i){
var key = kids[i].getAttribute(kidAttr);
obj[key] = objectify(kids[i],kidTags,kidAttr);
}
return obj;
}else{
return (el.getElementsByClassName('selected')[0] ||
el.getElementsByClassName('option')[0] ||
el.getElementsByTagName('*')[0]).textContent;
}
}
var root = objectify( document.getElementById('root') );
document.getElementById('output').innerHTML = JSON.stringify(root);
Here's the output (with formatting improved for display):
{
"stuff":{
"Person":"Kennedy",
"fruit":"Banana",
"Org":{
"Association":"MPAA",
"Federation":"Russian"
}
},
"attributes":{
"color":"red",
"time":"future"
}
}
It doesn't match your desired output exactly—it includes the "Federation" option even though no "option" has been "selected"—but it gets you 90% of the way there. Now you can finish it yourself.
you can use this jquery plugin to do it jQuery xmlObjectifier
精彩评论