1

I just recently started learning js and trying to solve the problem of converting xml source file

<ns1:input xmlns:ns1="ns1:test" xmlns:ns2="ns2:test">
    <ns1:element id="1">
        <ns2:field1>1</ns2:field1>
        <ns2:field2>2</ns2:field2>
        <ns2:field3>3</ns2:field3>
    </ns1:element>
    <ns1:element id="2">
        <ns2:field1>4</ns2:field1>
        <ns2:field2>5</ns2:field2>
        <ns2:field3>6</ns2:field3>
    </ns1:element>
</ns1:input>

to json of the following content

{
   "elements":[
      {
         "element":{
            "field1":"1",
            "field2":"2",
            "field3":"3",
            "id":"1"
         }
      },
      {
         "element":{
            "field1":"4",
            "field2":"5",
            "field3":"6",
            "id":"2"
         }
      }
   ]
}

using javascript. I tried to solve the problem using the xml2json library - it turned out not quite what I needed. Can you please tell me how this can be implemented?

Below is code and output

var convert = require('xml-js');
var xml =
    '<ns1:input xmlns:ns1="ns1:test" xmlns:ns2="ns2:test">'+
    '<ns1:element id="1">'+
        '<ns2:field1>1</ns2:field1>'+
        '<ns2:field2>2</ns2:field2>'+
        '<ns2:field3>3</ns2:field3>' +
    '</ns1:element>'+
    '<ns1:element id="2">'+
        '<ns2:field1>4</ns2:field1>'+
        '<ns2:field2>5</ns2:field2>'+
        '<ns2:field3>6</ns2:field3>'+
    '</ns1:element>'+
    '</ns1:input>';
var result2 = convert.xml2json(xml, {compact: true, spaces: 2, ignoreAttributes:true});
console.log(result2);

result

{
  "ns1:input": {       
    "ns1:element": [   
      {
        "ns2:field1": {
          "_text": "1" 
        },
        "ns2:field2": {
          "_text": "2" 
        },
        "ns2:field3": {
          "_text": "3" 
        }
      },
      {
        "ns2:field1": {
          "_text": "4"
        },
        "ns2:field2": {
          "_text": "5"
        },
        "ns2:field3": {
          "_text": "6"
        }
      }
    ]
  }
}
  • 1
    Off-topic, but why does the expected result consist of objects that all have one `element` property only, that then stores the actual data? Why not `[ { id: ... }, { id: ... }, ... ]` – Andreas Mar 18 '22 at 08:36
  • What have you tried so far to solve this on your own? Does the library you're using allow you to remove the namespace from the property names? [Working with objects - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects) – Andreas Mar 18 '22 at 08:37

2 Answers2

1

Rather then doing a generic convert you can read the XML using DOM+Xpath and build up the JSON. The main benefit is that the JSON structure does not directly depend on the XML structure.

This works in any modern browser, in node.js you need the xmldom and xpath packages.

// provide namespace resolution for the Xpath expressions
const resolver = function(prefix) {
    const namespaces = {
        n1: 'ns1:test',
        n2: 'ns2:test'
    }
    return namespaces[prefix || ''] || null;
}

const data = new DOMParser().parseFromString(getXMLString(), 'text/xml');
// fetch "{ns1:test}element" nodes 
const elementNodes = data.evaluate(
    "//n1:element", data, resolver, XPathResult.ANY_TYPE, null
);
let elementNode;
const elements = [];
while (elementNode = elementNodes.iterateNext()) {
  const element = {
    // read the id attribute
    id: elementNode.getAttribute('id'),
    // fetch the text contents of the first "{ns2:test}field1"
    // note the string cast in the expression
    field1: data.evaluate(
      'string(n2:field1)', elementNode, resolver, XPathResult.STRING_TYPE, null
    ).stringValue,
    field2: data.evaluate(
      'string(n2:field2)', elementNode, resolver, XPathResult.STRING_TYPE, null
    ).stringValue,
    field3: data.evaluate(
      'string(n2:field3)', elementNode, resolver, XPathResult.STRING_TYPE, null
    ).stringValue
  }
  elements.push({element});
}

console.log({elements});

function getXMLString() {
  return `<ns1:input xmlns:ns1="ns1:test" xmlns:ns2="ns2:test">
    <ns1:element id="1">
        <ns2:field1>1</ns2:field1>
        <ns2:field2>2</ns2:field2>
        <ns2:field3>3</ns2:field3>
    </ns1:element>
    <ns1:element id="2">
        <ns2:field1>4</ns2:field1>
        <ns2:field2>5</ns2:field2>
        <ns2:field3>6</ns2:field3>
    </ns1:element>
</ns1:input>
`;
}
ThW
  • 19,120
  • 3
  • 22
  • 44
0

Try lib named x2js

    var x2js = new X2JS();
    var xmlText = "your_xml_string";
    var jsonObj = x2js.xml_str2json( xmlText );

For more documentation refer to github page