Преобразование XML в объект JavaScript для Node.js

Исходный код для загрузки XML-файла в объект JavaScript или наоборот, для сохранения объекта в XML-файле.

На HTML-странице для преобразования XML будет использоваться объект DOMParser, а для загрузки документа - XMLHttpRequest. Но это объекты браузера, их нет в Node.js. Для их замены будет использоваться модуль Sax.js, который загружает XML-теги один за другим и преобразует их в элементарные JS-объекты, а также специальный код для сборки этих элементов в единый структурированный объект.

Этот код является частью времени выполнения компилятора Script-JavaScript начиная с версии 1.4.

Имена тегов и атрибутов XML становятся именами свойств объекта. Если это атрибут, этому свойству присваивается значение. Если это тег, весь XML-элемент назначается свойству.

Пример:

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

Объект будет:

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

Содержимое тега по соглашению присваивается свойству «data».

Это просто, но все еще есть препятствие: если XML-документ содержит несколько одноимённых тегов на одном уровне, это не может быть преобразовано непосредственно в свойства объекта, которые должны быть уникальными. Затем их помещают в таблицу и по соглашению присваивают этой таблице свойство «array».

Пример:

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

Объект будет:

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

Загрузить XML в объект (дезериализация)

Вот код JavaScript, который загружает XML-файл в объект. Он подходит для простых документов, таких как конфигурационные файлы, но не учитывает CDATA и другие сложные элементы документов (XML может быть очень сложным).

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