1

Let's say I got an array of JSON objects like this:

const cars = [
    {
        "color": "purple",
        "type": "minivan",
        "registration": "2020-02-03",
        "capacity": 7
      },
      {
        "color": "orange",
        "type": "SUV",
        "registration": "2021-05-17",
        "capacity": 4
      },
      {
        "color": "green",
        "type": "coupe",
        "registration": "2019-11-13",
        "capacity": 2
      }

];

I want to convert this object to a valid XML. But the helper packages I use start tags as array indexes when converting it, and therefore the resulting XML is not valid.

For example: (function json2xml from goessner)

function json2xml(o, tab) {
    var toXml = function(v, name, ind) {
       var xml = "";
       if (v instanceof Array) {
          for (var i=0, n=v.length; i<n; i++)
             xml += ind + toXml(v[i], name, ind+"\t") + "\n";
       }
       else if (typeof(v) == "object") {
          var hasChild = false;
          xml += ind + "<" + name;
          for (var m in v) {
             if (m.charAt(0) == "@")
                xml += " " + m.substr(1) + "=\"" + v[m].toString() + "\"";
             else
                hasChild = true;
          }
          xml += hasChild ? ">" : "/>";
          if (hasChild) {
             for (var m in v) {
                if (m == "#text")
                   xml += v[m];
                else if (m == "#cdata")
                   xml += "<![CDATA[" + v[m] + "]]>";
                else if (m.charAt(0) != "@")
                   xml += toXml(v[m], m, ind+"\t");
             }
             xml += (xml.charAt(xml.length-1)=="\n"?ind:"") + "</" + name + ">";
          }
       }
       else {
          xml += ind + "<" + name + ">" + v.toString() +  "</" + name + ">";
       }
       return xml;
    }, xml="";
    for (var m in o)
       xml += toXml(o[m], m, "");
    return tab ? xml.replace(/\t/g, tab) : xml.replace(/\t|\n/g, "");
 }
 


const cars = [
{
    "color": "purple",
    "type": "minivan",
    "registration": "2020-02-03",
    "capacity": 7
  },
  {
    "color": "orange",
    "type": "SUV",
    "registration": "2021-05-17",
    "capacity": 4
  },
  {
    "color": "green",
    "type": "coupe",
    "registration": "2019-11-13",
    "capacity": 2
  }

];

console.log(json2xml(cars, ' '));

I tried xml2js, fast-xml-parser and jstoxml packages. Result is the same.

Edit:

Expected XML:

<element> 
    <color>purple</color>
    <type>minivan</type>
    <registration>2020-02-03</registration>
    <capacity>7</capacity>
</element>
<element>
    <color>orange</color>
    <type>SUV</type>
    <registration>2021-05-17</registration>
    <capacity>4</capacity>
</element>
<element>
    <color>green</color>
    <type>coupe</type>
    <registration>2019-11-13</registration>
    <capacity>2</capacity>
</element>
0

3 Answers 3

2

How about this?

This assumes that the array of JSON objects all have the same keys.

let xml = "";

const prefixXML = `<?xml version="1.0" encoding="UTF-8"?>\n<cars>\n`;
const suffixXML = "\n</cars>";

const keys = Object.keys(cars[0]);

cars.forEach((car) => {
  let valueXML = keys
    .map((key) => {
      return `<${key}>${car[key]}</${key}>`;
    })
    .join("\n\t");
  xml += `
    <car>
      ${valueXML}
    </car>
  `;
});

const final = prefixXML + xml + suffixXML;

console.log(final);

The XML output is:

<?xml version="1.0" encoding="UTF-8"?>
<cars>

    <car>
        <color>purple</color>   
    <type>minivan</type>    
    <registration>2020-02-03</registration> 
    <capacity>7</capacity>  
    </car>
  
    <car>
        <color>orange</color>   
    <type>SUV</type>    
    <registration>2021-05-17</registration> 
    <capacity>4</capacity>  
    </car>
  
    <car>
        <color>green</color>    
    <type>coupe</type>  
    <registration>2019-11-13</registration> 
    <capacity>2</capacity>  
    </car>
  
</cars> 
Sign up to request clarification or add additional context in comments.

Comments

2

If you're using FXP (fast-xml-parser), you can use folloing configuration to avoid array index as tag name

const parser = new j2xParser({
    rootNodeName: "car"
});
const result = parser.parse(cars);

FXP version must be > 3.21.0

Comments

0

I'm the creator of jstoxml. Just for reference, this is how you'd structure your object to pass into jstoxml:

const { toXML } = window.jstoxml;

const cars = [
    {
        _name: 'element',
        _content: {
            color: 'purple',
            type: 'minivan',
            registration: '2020-02-03',
            capacity: 7
        }
    },
    {
        _name: 'element',
        _content: {
            color: 'orange',
            type: 'SUV',
            registration: '2021-05-17',
            capacity: 4
        }
    },
    {
        _name: 'element',
        _content: {
            color: 'green',
            type: 'coupe',
            registration: '2019-11-13',
            capacity: 2
        }
    }
];

console.log(toXML(cars, { indent: '    ' }));

/**
Output:

<element>
    <color>purple</color>
    <type>minivan</type>
    <registration>2020-02-03</registration>
    <capacity>7</capacity>
</element>
<element>
    <color>orange</color>
    <type>SUV</type>
    <registration>2021-05-17</registration>
    <capacity>4</capacity>
</element>
<element>
    <color>green</color>
    <type>coupe</type>
    <registration>2019-11-13</registration>
    <capacity>2</capacity>
</element>
*/
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jstoxml.min.js"></script>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.