How to parse xml using JavaScript and identify elements based on attributes

5.5k views Asked by At

I am using xml2js to convert an xml file into a javascript object. I need to identify attributes within element tags in the xml file and manipulate the matching element(s).

For example, I have some a property element in test.xml:

...
<property name="TemporaryPort" type="input" required="true" order="0">
  <object>endpoint</object>
</property>
<property name="TemporaryPort" type="input" required="false" order="1">
  <object>endpoint</object>
</property>
<property name="TemporaryPort" type="output" required="false" order="2">
  <object>endpoint</object>
</property>
...

In my parse.js file that is parsing this xml file, I would like to identify elements based on their attributes:

const xml2js = require('xml2js');
const xml = fs.readFileSync("test.xml");

let output = "";
const parser = new xml2js.Parser();
parser.parseString(xml, function(err,result){
  // I would like to find all elements where:
  // required is set to "true", 
  // name is set to "TemporaryPort", and 
  // type is set to "input"
  output="";
  console.log(output);
});
2

There are 2 answers

0
Mister Jojo On

Maybe with DOMParser() ?

sample code:

const
  DomParser = new DOMParser()
, XMLtext = `
  <data_xml>
    <property name="TemporaryPort" type="input" required="true" order="0">
      <object>endpoint 1</object>
    </property>
    <property name="TemporaryPort" type="input" required="false" order="1">
      <object>endpoint 2</object>
    </property>
    <property name="TemporaryPort" type="output" required="false" order="2">
      <object>endpoint 3</object>
    </property>
  </data_xml>`
  ;
let XMLparsed = DomParser.parseFromString( XMLtext, 'application/xml')
  ;


  //  find all elements where:
// required is set to "true", 
// name is set to "TemporaryPort", and 
// type is set to "input"  
 
for (let nod of XMLparsed.querySelectorAll('data_xml property[name="TemporaryPort"][type="input"][required="true"]') )
  {
  for(let subChild of nod.children)
    {
    console.log( '---subChild name:', subChild.nodeName )  
    console.log( '----------content ->', subChild.textContent )  
    } 
  }
console.log('\n\n\n')

// otherwise:

for (let nod of XMLparsed.querySelector('data_xml').children )
  {
  console.log( 'nodeName =', nod.nodeName)
  for(let attr of nod.attributes)
    {
    console.log('---> attribute: name=', attr.name, ',  value=', attr.value)
    }
  for(let subChild of nod.children)
    {
      console.log( '---subChild name:', subChild.nodeName )  
      console.log( '----------content ->', subChild.textContent )  
    }  
  }
.as-console-wrapper {max-height: 100%!important;top:0; }

0
Paul Martin On

I made a slight change to your .xml file, as I can't see the whole thing, but I assume it's enclosed in a parent wrapper, which I've called props.

<props>
    <property name="TemporaryPort" type="input" required="true" order="0">
    <object>endpoint</object>
    </property>
    <property name="TemporaryPort" type="input" required="false" order="1">
    <object>endpoint</object>
    </property>
    <property name="TemporaryPort" type="output" required="false" order="2">
    <object>endpoint</object>
    </property>
</props>

I've also...

  1. Imported fs
  2. Changed output to an array, as your function parses the xml as an array of objects
  3. Looped through result (the array of objects), props (my made up parent wrapper) and property the children from the XML file in your example.
  4. The loop checks for your required conditions and pushes the object to the output array, which it logs at the end.
const xml2js = require('xml2js');
const fs = require('fs');

const xml = fs.readFileSync("test.xml");

const output = []
const parser = new xml2js.Parser();

parser.parseString(xml, function(err,result){
  result.props.property.forEach(prop => {
    prop['$'].required == 'true' &&
    prop['$'].name == 'TemporaryPort' &&
    prop['$'].type == 'input' &&
    output.push(prop)
  })
  console.log(output)
});