0

I have a large XML DOM Object which was parsed via jQuery's $.parseXML function, returning a JavaScript DOM Object. With this XML I want to create an normal JavaScript Object with the following structure:

{
    name: 'my_tree',
    children: [
        { name: 'hello' },
        { name: 'wat' },
        {
            name: 'child_folder',
            children: [
                {
                    name: 'child_folder',
                    children: [
                        { name: 'hello' },
                        { name: 'wat' }
                    ]
                },
                { name: 'hello' },
                { name: 'wat' },
                {
                    name: 'child_folder',
                    children: [
                        { name: 'hello' },
                        { name: 'wat' }
                    ]
                }
            ]
        }
    ]
}

The original XML would look something like this:

<my_tree>
    <hello></hello>
    <wat></wat>
    <child_folder>
        <child_folder>
            <hello></hello>
            <wat></wat>
        </child_folder>
        <hello></hello>
        <wat></wat>
        <child_folder>
            <hello></hello>
            <wat></wat>
        </child_folder>
    </child_folder>
</my_tree>

I have tried something like the code below, but to no avail:

function xmlDomToObject(domObject) {
    var result = {children: []};
    for (var i = 0; i < domObject.length; i++) {
        if (domObject[i].nodeName == "#text") {
            continue;
        }

        result['name'] = domObject[i].nodeName;
        result['children'].push(xmlDomToObject(domObject[i].childNodes));
    }

    return result;
}

var xmlObject = xmlDomToObject(xmlDomObject.childNodes);

1 Answer 1

1

One possible approach goes below. Using children (instead of childNodes) property allows to bypass text nodes and check Elements only:

function parseXml(node) {
  const el = {
    name: node.nodeName
  };

  const children = Array.prototype.map.call(node.children, parseXml);
  // ES6: const children = [...node.children].map(parseXml);
  if (children.length) {
    el.children = children;
  }

  return el;
}

You can use it as is, just remember to pass documentElement property of $.parseXML result - and not the result itself.

const xmlStr = `<my_tree>
    <hello></hello>
    <wat></wat>
    <child_folder>
        <child_folder>
            <hello></hello>
            <wat></wat>
        </child_folder>
        <hello></hello>
        <wat></wat>
        <child_folder>
            <hello></hello>
            <wat></wat>
        </child_folder>
    </child_folder>
</my_tree>`;

const xml = $.parseXML(xmlStr);
const parsed = parseXml(xml.documentElement);

console.log(parsed);

function parseXml(node) {
  const el = {
    name: node.nodeName
  };

  // const children = [...node.children].map(parseXml);
  const children = Array.prototype.map.call(node.children, parseXml);
  if (children.length) {
    el.children = children;
  }
 
  return el;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

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

1 Comment

Is there a chance to have this written in ES5? I don't really get this new syntax and I'm currently not using ES6.

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.