Converting XML to a JavaScript Object for Node.js

Source code for loading an XML file into a JavaScript object or vice versa to store the object in an XML file.

The HTML page will use the DOMParser object to transform the XML and the XMLHttpRequest object to load the document. But these are browser objects, they are not in Node.js. To replace them, the Sax.js module will be used, which loads XML tags one after another and converts them into elementary JS objects, as well as special code for assembling these elements into a single structured object.

This code is part of the runtime of the Script-JavaScript compiler since version 1.4.

XML tag and attribute names become object property names. If it is an attribute, this property is set to. If it is a tag, the entire XML element is assigned to the property.

Example:

<voiture vitesse="100" marque="Ferrari">
   <passagers>Alpha, Beta, Delta</passagers>
</voiture>

The object will be:

{
  voiture : {
   "vitesse": 100,
   "marque": Ferrari,
   "passagers": {
     "data": "Alpha, Beta, Delta"
   }
 }
} 

The content of the agreement tag is assigned to the "data" property.

This is simple, but there is still an obstacle: if an XML document contains several tags of the same name at the same level, this cannot be converted directly into object properties that must be unique. Then they are placed in a table and the property "array" is assigned to this table by convention.

Example:

<voiture vitesse="100" marque="Ferrari">
   <passager>Alpha</passager>
   <passager>Beta</passager>
   <passager>Delta</passager>
</voiture>

The object will be:

{
  voiture : {
   "vitesse": 100,
   "marque": Ferrari,
   "array" = [ 
     { "passager" : "Alpha" } ,
     { "passager" : "Beta" } ,
     { "passager" : "Delta" } 
    ]
   }
 }
} 

Load XML into object (deserialization)

Here is the JavaScript code that loads the XML file into the object. It is suitable for simple documents such as configuration files, but does not take into account CDATA and other complex document elements (XML can be very complex).

function parseXML(data)
{
  var data = data.toString("utf8");
  var sax = require("sax");
  
  var parser = sax.parser(true, { trim:true });
  parser.onerror = function (e) {
    console.log("XML error: ", e.toString());
    return{};
  };

  var ctag = null;
  var xmlroot = null;
  
  parser.ontext = function (t) {
      if (ctag && t.length > 0) { 
          ctag["data"] = t;
      }   
  }    
  
  parser.onopentag = function (node) {
    var name = node.name;
    var parent = ctag;
    ctag = {};
    ctag.array = [];
    ctag.idFlag = false;   // same tags at same level
    if (xmlroot === null) {
      xmlroot = {};
      xmlroot[name] = ctag;
    }
    else
    {
      ctag.parent = parent;
      var xtag = {};
      xtag[name]= ctag;
      parent.array.push(xtag);
    }
    
    for(var k in node.attributes) {
      ctag[k] = node.attributes[k];
    }

    while(parent && !parent.idFlag) 
    {
        for(var i=0; i < parent.array.length - 1 i var elem="parent.array[i];" for var key in elem if key="=" name parent.idFlag="true;" break break parser.onclosetag="function(name)" if ctag.idFlag="=" false only one child all childs different for var i="0;" i ctag.array.length i var xtag="ctag.array[i];" for var u in xtag ctag u="xtag[u];" delete ctag.array delete ctag.idFlag if ctag.parent var parent="ctag.parent;" delete ctag.parent ctag="parent;" parser.write data .end return xmlroot var filename=""test.xml";" var a="fs.readFileSync(filename).toString();var obj = parseXML(a);

Remplacer le nom de fichier assigné à filename par tout autre fichier XML.

Accéder au contenu

Pour accéder aux balises individuelles, le runtime offre la fonction getById().

function getById(d, idval) {
for(var k in d) {
if(typeof d[k] === "object") {
var dsub = d[k];
if("id" in dsub && dsub.id == idval) return d;
var dret = getById(dsub, idval)
if(dret !== false) return dret;
}
}
return false
}

La fonction prend en compte le problème des balises identiques.

Sauver un objet JavaScript dans un fichier XML (sérialiser)

Pour mettre à jour le fichier que l'on aura modifié dans un programme JavaScript, il faut convertir les propriétés et objets imbriqués en attributs et balises.

La valeur d'une propriété "data" devient le contenu d'une balise, les éléments d'une propriété "array" deviennent chacun une balise.

var XMLStorage = "";
function xmlSub(d, name) 
{
  var flag = true;
  if(name=='array') {
    for(var i = 0; i < d.length; i++)
    {
        var tag = d[i];
        var o;
        for(var k in tag) { o = tag[k]; break; }
        XMLStorage += "<" + k;
        flag = xmlSub(o, k);
        XMLStorage += "\n";
      flag = false;      
      continue;
    }
    if (x == "data") { 
      XMLStorage += ">" + d[x];
      flag = false;
    }  
    else { 
      XMLStorage += " " + x + "=\""+ d[x] + "\"";
      flag = true;
    }    
  }
  return flag;  
}

function saveXML(d, filename) 
{
  XMLStorage = '<?xml version="1.0" encoding="UTF-8"?>';
  if(xmlSub(d)) XMLStorage += ">\n";
  fs.writeFileSync(filename, XMLStorage);
}

Le code complet avec une démonstration sont disponibles en téléchargement.

Pour le faire fonctionner, vous devez installer Node.js et ensuite le module sax avec cette commande:

npm install sax

Après avoir téléchargé et extrait l'archive, allez dans xml-js et tapez:

node xml-js.js