Search code examples
javascriptarraysxmlhierarchy

how to make hierarchy array from the following xml?


I have an XML data, which I need to convert into an array, XML data has a hierarchy but it is on the same level hence the problem to identify. I've given an expected output array below along with my work.

This following XML data can have multiple hierarchies

<data>
<GROUP NAME="Sundry Debtors">
    <PARENT></PARENT>
</GROUP>
<GROUP NAME="Sundry Debtors-Pune">
    <PARENT>Sundry Debtors</PARENT>
</GROUP>
<GROUP NAME="Sundry Debtors-Akurdi">
    <PARENT>Sundry Debtors-Pune</PARENT>
</GROUP>
<GROUP NAME="Sundry Creditors">
    <PARENT></PARENT>
</GROUP>
<GROUP NAME="Sundry Creditors-Pune">
    <PARENT>Sundry Creditors</PARENT>
</GROUP>
</data>

Following is expected output from the above xml data

let arr = [
  {
    name: "Sundry Debtors",
    data: [{ name: "Sundry Debtors-Pune", data: [{ name: "Sundry Debtors-Akurdi", data: [] }] }]
  },
  { name: "Sundry Creditors", data: [{ name: "Sundry Creditors-Pune", data: [] }] }
];

Following is what I've tried so far

<!DOCTYPE html>
<html>
  <title>test</title>
  <script>
    //Desired output
    let arr = [
      {
        name: "Sundry Debtors",
        data: [{ name: "Sundry Debtors-Pune", data: [{ name: "Sundry Debtors-Akurdi", data: [] }] }]
      },
      { name: "Sundry Creditors", data: [{ name: "Sundry Creditors-Pune", data: [] }] }
    ];
    let text =
      '<data><GROUP NAME="Sundry Debtors"><PARENT></PARENT></GROUP><GROUP NAME="Sundry Debtors-Pune"><PARENT>Sundry Debtors</PARENT></GROUP><GROUP NAME="Sundry Debtors-Akurdi"><PARENT>Sundry Debtors-Pune</PARENT></GROUP><GROUP NAME="Sundry Creditors"><PARENT></PARENT></GROUP><GROUP NAME="Sundry Creditors-Pune"><PARENT>Sundry Creditors</PARENT></GROUP></data>';
    let parser = new DOMParser();
    let xml = parser.parseFromString(text, "text/xml");
    var node = xml.getElementsByTagName("GROUP");
    let total = 0;
    let levels = [];
    let level = 0;
    let hirarchy = [];
    total = node.length;
    function getChilds(parent) {
      let arr = [];
      for (let j = 0; j < total; j++) {
        let e = node[j];
        let grpName = e.getAttribute("NAME");
        let parentCount = e.getElementsByTagName("PARENT")[0].childNodes.length;
        if (parentCount > 0) {
          let parentName = e.getElementsByTagName("PARENT")[0].childNodes[0].nodeValue;
          if (parentName === parent) {
            arr.push(grpName);
          }
        }
      }
      return arr;
    }
    function getParent(child) {
      let arr = [];
      for (let k = 0; k < total; k++) {
        let e = node[k];
        let grpName = e.getAttribute("NAME");
        if (grpName === child) {
          let parentCount = e.getElementsByTagName("PARENT")[0].childNodes.length;
          let parentName = parentCount > 0 ? e.getElementsByTagName("PARENT")[0].childNodes[0].nodeValue : undefined;
          return parentName;
        }
      }
    }
    function findNode(array, nodename) {
      for (let j = 0; j < array.length; j++) {
        const e = array[j];
        if (e.name === nodename) {
          return e;
        } else {
          if (e.data.length > 0) {
            //console.log(e.data, nodename);
            return findNode(e.data, nodename);
          } else {
            return null;
          }
        }
      }
    }
    let new_h = [];
    for (i = 0; i < total; i++) {
      let e = node[i];
      let grpName = e.getAttribute("NAME");
      let childs = getChilds(grpName);
      let parent = getParent(grpName);
      //console.log(i, grpName, " --->", childs, parent);
      if (!parent) {
        let arr = { name: grpName, data: [] };
        new_h.push(arr);
      } else {
        let arr = findNode(new_h, parent);
        if (arr) {
          arr.data.push({ name: grpName, data: [] });
        } else {
        }
      }
    }
    console.log(new_h);
  </script>
</html>


Solution

  • Try following code.

    <!DOCTYPE html>
    <html>
      <title>test</title>
      <script>
        let expected_output_array = [
          {
            name: "Sundry Debtors",
            data: [{ name: "Sundry Debtors-Pune", data: [{ name: "Sundry Debtors-Akurdi", data: [] }] }]
          },
          { name: "Sundry Creditors", data: [{ name: "Sundry Creditors-Pune", data: [] }] }
        ];
        let text =
          '<data><GROUP NAME="Sundry Debtors"><PARENT></PARENT></GROUP><GROUP NAME="Sundry Debtors-Pune"><PARENT>Sundry Debtors</PARENT></GROUP><GROUP NAME="Sundry Debtors-Akurdi"><PARENT>Sundry Debtors-Pune</PARENT></GROUP><GROUP NAME="Sundry Creditors"><PARENT></PARENT></GROUP><GROUP NAME="Sundry Creditors-Pune"><PARENT>Sundry Creditors</PARENT></GROUP></data>';
        let parser = new DOMParser();
        let xml = parser.parseFromString(text, "text/xml");
        var node = xml.getElementsByTagName("GROUP");
        let total = 0;
        total = node.length;
        function getChilds(parent) {
          let arr = [];
          for (let j = 0; j < total; j++) {
            let e = node[j];
            let grpName = e.getAttribute("NAME");
            let parentCount = e.getElementsByTagName("PARENT")[0].childNodes.length;
            if (parentCount > 0) {
              let parentName = e.getElementsByTagName("PARENT")[0].childNodes[0].nodeValue;
              if (parentName === parent) {
                arr.push(grpName);
              }
            }
          }
          return arr;
        }
        function getParent(child) {
          let arr = [];
          let total = node.length;
          for (let k = 0; k < total; k++) {
            let e = node[k];
            let grpName = e.getAttribute("NAME");
            if (grpName === child) {
              let parentCount = e.getElementsByTagName("PARENT")[0].childNodes.length;
              let parentName = parentCount > 0 ? e.getElementsByTagName("PARENT")[0].childNodes[0].nodeValue : undefined;
              return parentName;
            }
          }
        }
        function findNodeSequential(array, nodename) {
          for (let k = 0; k < array.length; k++) {
            const e = array[k];
            if (e.name === nodename) {
              return e;
            } else {
              if (e.data.length > 0) {
                return findNodeSequential(e.data, nodename);
              } else {
                return null;
              }
            }
          }
        }
        function findNode(array, nodename) {
          for (let j = 0; j < array.length; j++) {
            let e = array[j];
            if (e.name === nodename) {
              return e;
            } else {
              if (e.data.length > 0) {
                e = findNodeSequential(e.data, nodename);
                if (e !== null) {
                  return e;
                }
              }
            }
          }
        }
        let h = [];
        for (let i = 0; i < total; i++) {
          let e = node[i];
          let grpName = e.getAttribute("NAME");
          let childs = getChilds(grpName);
          let parent = getParent(grpName);
          if (!parent) {
            let arr = { name: grpName, data: [] };
            h.push(arr);
          }
        }
        for (let l = 0; l < total; l++) {
          let e = node[l];
          let grpName = e.getAttribute("NAME");
          let childs = getChilds(grpName);
          let parent = getParent(grpName);
          if (parent) {
            let arr = findNode(h, parent);
            if (arr) {
              arr.data.push({ name: grpName, data: [] });
            } else {
            }
          }
        }
        console.log("Expected output:", expected_output_array);
        console.log("Output: ", h);
      </script>
    </html>