Search tag name in XML Dom from user input and display the content in between- Node JS

84 views Asked by At

I would like to ask how do find a tag name in XML dom from user input then loop through and display everything within it if I enter 'unit', then it would display everything within the unit tag

eg. XML

<course>
     <name>course name</name>
     <duration>3 years</duration>
     <unit>
          <title>Testing 1</title>
          <lecturer>
              <surname language="English">Lecturer</surname>
              <othernames language="English">1</othernames>
              <email>[email protected]</email>
          </lecturer>
     </unit>
     <unit>
          <title>Testing 2</title>
          <lecturer>
              <surname>Lecturer</surname>
              <othernames>2</othernames>
              <email>[email protected]</email>
          </lecturer>
     </unit>
</course>

This is the Node js code I am using,

fs.readFile('course.xml', 'utf-8', function (err, data) {
    if (err) {
        throw err;
    }
    // construct parser
    parser = new xmldom();
    // call method to parse document - not the type
    doc = parser.parseFromString(data, 'application/xml');

    userInput = readLineSync.question("Enter tag to be printed: ");

    // use DOM Node method
    targetNodes = doc.getElementsByTagName(userInput.toLowerCase());
    console.log("Tag " + userInput + " entered");

    for (i in targetNodes) {
        // process current ith node
        targetObj = targetNodes[i];
    
        // if it is the firstchild
        if (targetObj.firstChild) {
            // obtain the node value
            fcObj = targetObj.childNodes;
            parentObj = targetObj.parentNode;

            if (parentObj == null && count == 0){
                console.log("No identical tag found.");
            } else {
                count = 1;
                if (parentObj != null) {
                    // if (fcObj[count].nodeName === userInput) {
                        output = parentObj.getElementsByTagName(userInput)[count].childNodes[0].nodeValue;
                        console.log(output);
                    // }
                }
            }
        }
    }
});

The expect output if user enter 'unit'

Testing 1
Lecturer 1
[email protected]

Testing 2
Lecturer 2
[email protected]
1

There are 1 answers

0
ThW On

XML is a tree, if you want to output it as a list you need to flatten it - for example with a recursive function. Reduce the tree to a list based on the element nodes without an element child node.

const dataSource = (new DOMParser).parseFromString(getXML(), 'text/xml');

const selectedTag = 'unit';
//const selectedTag = 'duration';

const targetNodes = [...dataSource.getElementsByTagName(selectedTag)]
  .map(
    (targetNode) => {
      return {
        name: targetNode.localName,
        descendants: getDescendantList(targetNode),
        textContent: targetNode.textContent
      }
    }
  );
  
//debug generated array of descendant lists 
console.log(targetNodes);  

// write output
const demo = document.getElementById('demo'); 
demo.textContent = targetNodes.map(
  (targetNodeData) => {
    if (targetNodeData.descendants.length > 0) {
      return targetNodeData.descendants.map(
        (data) =>  `${'  '.repeat(data.depth)} ${data.name}: ${data.textContent}`
      ).join('\n') + '\n';
    } else {
      return `${targetNodeData.name}: ${targetNodeData.textContent}\n\n`;
    }
  }
).join('');
  

function getDescendantList(parentNode, depth = 0) {
  return [...parentNode.childNodes]
    // filter for element nodes
    .filter(
       (node) => node.nodeType === node.ELEMENT_NODE
    )
    .reduce(
    (carry, node) => {
       // get descendant data
       const descendants = getDescendantList(node, depth + 1);
       // no descendant data, leaf node, add data
       if (descendants.length < 1) {
         carry.push(
           {
             depth, 
             name: node.localName,
             textContent: node.textContent
           }
         );
       } else {
         // add descendants to list
         carry.push(
           ...descendants
         );
       }
       return carry;
    },
    []
  );
}

function getElementChildren(parentNode) {
  return ;
}



function getXML() {
  return `<course>
     <name>course name</name>
     <duration>3 years</duration>
     <unit>
          <title>Testing 1</title>
          <lecturer>
              <surname language="English">Lecturer</surname>
              <othernames language="English">1</othernames>
              <email>[email protected]</email>
          </lecturer>
     </unit>
     <unit>
          <title>Testing 2</title>
          <lecturer>
              <surname>Lecturer</surname>
              <othernames>2</othernames>
              <email>[email protected]</email>
          </lecturer>
     </unit>
</course>`
}
<pre id="demo"></pre>