The caveat here is that you're doing this in the browser. JS doesn't treat XML natively, so if you can always prefer your data in JSON format. In the browser, however, we can make use of the DOMParser
and XMLSerializer
:
const xml = `<Data>
<Person>
<Name>ABC</Name>
<Transaction>123</Transaction>
</Person>
<Person>
<Name>ABC</Name>
<Transaction>999</Transaction>
</Person>
<Person>
<Name>XYZ</Name>
<Transaction>123</Transaction>
</Person>
</Data>`
// parse our xml to a an xmldocument
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xml, "text/xml");
// extract all the "Person nodes" and store them in a JS object
const peopleJS = {};
const people = [...xmlDoc.getElementsByTagName('Person')]
people.forEach(person => {
const name = person.getElementsByTagName('Name')[0].innerHTML;
const transaction = person.getElementsByTagName('Transaction')[0].innerHTML;
if (name in peopleJS) {
peopleJS[name].transactions.push(transaction);
} else {
peopleJS[name] = {
name,
transactions: [transaction]
}
}
})
// create a new XMLDocument
const doc = document.implementation.createDocument(null, 'Data');
// go through our JS object, and create our elements
for (let key in peopleJS) {
const personObj = peopleJS[key];
// the main Person element
const personEl = doc.createElement('Person');
// the Name element
const nameEl = doc.createElement('Name');
nameEl.innerHTML = personObj.name;
personEl.appendChild(nameEl);
// each Tranaction element for that person
personObj.transactions.forEach(transaction => {
const transactionEl = doc.createElement('Transaction');
transactionEl.innerHTML = transaction;
personEl.appendChild(transactionEl);
})
// attach the Person to our document
doc.documentElement.appendChild(personEl);
}
// write it back out to a string
const serializer = new XMLSerializer();
console.log(serializer.serializeToString(doc))
So basically, we take our xml data and parse it to return an XMLDocument
. This lets us use the normal getElementBy...
methods that we're used to, so we don't have to deal with regexs or anything.
NOTE: in your original example, your Name
element is written like <Name>ABC</name>
, which isn't valid XML, so I had to change the closing tag from </name>
to </Name>
Once the document is parsed, we run through it and pull out all of our information and store it in a temporary JS object. When that's done, we'll have a JS object in the form
{
"ABC": {
"name": "ABC",
"transactions": [
"123",
"999"
]
},
"XYZ": {
"name": "XYZ",
"transactions": [
"123"
]
}
}
Now all that's left is to transfer that object back to XML. To be honest, it'd nearly almost be easier to just run through the array and write it out as a string, but we'll do the DOM way for the sake of completeness.
We create a new XMLDocument (it's important that it's XML if you want to keep the case sensitivity (i.e. Data
and not data
)), run through our JS object and create elements for each of our properties.
Finally, we use XMLSerializer
to serialize our new XMLDocument
back out to a string.