Search code examples
javascriptrecursionxml-parsingservicenow

Parse a highly nested XML to fetch all the sys_id's till 'TestBS4' for each child of `<childrenOfCurrentCI>` using recursion


Tool: ServiceNow. Language: JavaScript

My approach: I am iterating using a while loop at each level to reach the sys_id of 'TestBS4', I have to put 4 while loops one inside the other once I have the first <CI>...</CI> node inside <childrenOfCurrentCI> tag. I feel this can be done through recursion, but I am unable to.

What if I have like 50 CI child one inside the other (not siblings), and I need the 45th one? I'd appreciate someone's help to achieve this using recursion. The sys_id's can be put in an array for further processing.

In this case, I need all the sys_id's till the 4th level (TestBS4) of each child of <childrenOfCurrentCI> tag.


Below is the sample XML.

<?xml version="1.0" encoding="UTF-8"?>
<xmlTree>
   <sys_id>e9c23f4adbf31300ae2af28239961974</sys_id>
   <name>Test CI One</name>
   <relType>SELF</relType>
   <childrenOfCurrentCI>
      <CI>
         <sys_id>68b1b746dbf31300ae2af2823996197a</sys_id>
         <name>TestBS1</name>
         <relType>Depends on::Used by</relType>
         <children>
            <CI>
               <sys_id>964477cedbf31300ae2af28239961913</sys_id>
               <name>TestBS2</name>
               <relType>Depends on::Used by</relType>
               <children>
                  <CI>
                     <sys_id>88643fcedbf31300ae2af2823996190b</sys_id>
                     <name>TestBS3</name>
                     <relType>Depends on::Used by</relType>
                     <children>
                        <CI>
                           <sys_id>0264f7cedbf31300ae2af28239961971</sys_id>
                           <name>TestBS4</name>
                           <relType>Depends on::Used by</relType>
                           <children>
                              <CI>
                                 <sys_id>fb64ffcedbf31300ae2af282399619e8</sys_id>
                                 <name>TestBS5</name>
                                 <relType>Depends on::Used by</relType>
                              </CI>
                           </children>
                        </CI>
                     </children>
                  </CI>
               </children>
            </CI>
         </children>
      </CI>
      <CI>
         <sys_id>ae1ff02fdbfb1300ae2af2823996195d</sys_id>
         <name>Test Side Parent One</name>
         <relType>Depends on::Used by</relType>
      </CI>
   </childrenOfCurrentCI>
</xmlTree>

Solution

  • Just coded for the case

    In this case, I need all the sys_id's till the 4th level (TestBS4) of each child of tag.

    Hope you get the idea.

    var text = `
    <xmlTree>
       <sys_id>e9c23f4adbf31300ae2af28239961974</sys_id>
       <name>Test CI One</name>
       <relType>SELF</relType>
       <childrenOfCurrentCI>
          <CI>
             <sys_id>68b1b746dbf31300ae2af2823996197a</sys_id>
             <name>TestBS1</name>
             <relType>Depends on::Used by</relType>
             <children>
                <CI>
                   <sys_id>964477cedbf31300ae2af28239961913</sys_id>
                   <name>TestBS2</name>
                   <relType>Depends on::Used by</relType>
                   <children>
                      <CI>
                         <sys_id>88643fcedbf31300ae2af2823996190b</sys_id>
                         <name>TestBS3</name>
                         <relType>Depends on::Used by</relType>
                         <children>
                            <CI>
                               <sys_id>0264f7cedbf31300ae2af28239961971</sys_id>
                               <name>TestBS4</name>
                               <relType>Depends on::Used by</relType>
                               <children>
                                  <CI>
                                     <sys_id>fb64ffcedbf31300ae2af282399619e8</sys_id>
                                     <name>TestBS5</name>
                                     <relType>Depends on::Used by</relType>
                                  </CI>
                               </children>
                            </CI>
                         </children>
                      </CI>
                   </children>
                </CI>
             </children>
          </CI>
          <CI>
             <sys_id>ae1ff02fdbfb1300ae2af2823996195d</sys_id>
             <name>Test Side Parent One</name>
             <relType>Depends on::Used by</relType>
          </CI>
       </childrenOfCurrentCI>
    </xmlTree>
    
    `;
    
    if (window.DOMParser)
    {
        parser = new DOMParser();
        xmlDoc = parser.parseFromString(text, "text/xml");
    }
    else // Internet Explorer 
    {
        xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
        xmlDoc.async = false;
        xmlDoc.loadXML(text);
    }
    let sysIds = xmlDoc.getElementsByTagName("childrenOfCurrentCI")[0].getElementsByTagName("sys_id");
    function getMeSysId(position) {
      console.log(sysIds[position-1].textContent);
    }
    console.log("to get the 4th level sys_Id");
    getMeSysId(4);
    console.log("for all the sysid's inside childrenOfCurrentCI");
    for (let i=0; i<sysIds.length;i++) {
      console.log(sysIds[i].textContent);
    }

    Use var instead of let else condition can be skipped ( required for IE versions ) and try using serviceNow xml dom parser

    So updated code chunk is

        xmlDoc = new XMLDocument(text);
    
    var sysIds = xmlDoc.getElementsByTagName("childrenOfCurrentCI")[0].getElementsByTagName("sys_id");