mozilla

Revision 61978 of Costruire e decostruire un documento XML

  • Slug della versione: Costruire_e_decostruire_un_documento_XML
  • Titolo della versione: Costruire e decostruire un documento XML
  • ID versione: 61978
  • Data di creazione
  • Autore: fusionchess
  • Versione corrente? No
  • Commento Traduzione parziale; 1232 words added, 833 words removed

Contenuto della versione

{{ T() }}

Mozilla gestisce ampiamente XML. Sono gestite diverse Raccomandazioni e bozze del World Wide Web Consortium (W3C) per la famiglia XML, così come altre tecnologie relative.

Che cos'è un albero DOM?

Per albero DOM s'intende un'istanza di Document. Si tratta quindi di un oggetto Javascript e non è da confondere con una stringa di testo contenente il codice sorgente di un documento XML ancora da parsare.

DOM trees can be queried using XPath expressions, converted to strings or written to a local or remote files using XMLSerializer (without having to first convert to a string), POSTed to a web server (via XMLHttpRequest),

You can use DOM trees to model data which isn't well-suited for RDF (or perhaps you just don't like RDF). Another application is that, since XUL is XML, the UI of your application can be dynamically manipulated, downloaded, uploaded, saved, loaded, converted, or transformed quite easily.

Mozilla offre le seguenti tecnologie native per lavorare con documenti XML:

  • XPath per indirizzare parti diverse di un documento XML,
  • XMLSerializer per convertire alberi DOM in stringhe o files,
  • DOMParser costruire un documento XML convertendo delle stringhe in alberi DOM,
  • XMLHttpRequest per parsare a partire da file documenti XML in albero DOM. Sebbene anche le istanze di DOMParser abbiano un metodo chiamato parseFromStream(), è più facile utilizzare XMLHttpRequest che lavore sia con file remoti (non confinati al solo protocollo HTTP) che con file locali,
  • XSLT e XLink per manipolare il contenuto di un documento XML.

È possibile comunque creare manualmente propri algoritmi per la serializzazione o la conversione di un documento XML, come si vedrà in seguito.

Costruire un albero DOM

In questa sezione iniziale il nostro scopo sarà quello di ottenere un albero DOM.

Un albero DOM è un oggetto Javascript. Ci sono molti modi per costruirlo/ottenerlo, a seconda delle proprie esigenze. Di seguito verranno elencate varie strade: a partire da una stringa di codice sorgente, a partire da file o a partire da strutture di differente natura.

Creare dinamicamente un albero DOM

Questo paragrafo illustra come utilizzare l'API JavaScript DOM Core per creare e modificare oggetti DOM. Essa è attiva in tutte le applicazioni Gecko-based (come Firefox, per esempio) sia in privileged code (estensioni) che in unprivileged code (pagine internet).

Scrivendolo a mano

L'API JavaScript W3C DOM può essere invocata manualmente.

Si consideri il seguente documento XML:

<?xml version="1.0"?>
<people>
  <person first-name="eric" middle-initial="H" last-name="jung">
    <address street="321 south st" city="denver" state="co" country="usa"/>
    <address street="123 main st" city="arlington" state="ma" country="usa"/>
  </person>

  <person first-name="jed" last-name="brown">
    <address street="321 north st" city="atlanta" state="ga" country="usa"/>
    <address street="123 west st" city="seattle" state="wa" country="usa"/>
    <address street="321 south avenue" city="denver" state="co" country="usa"/>
  </person>
</people>

L'API Javascript W3C DOM, supportata da Mozilla, può essere usata per creare una rappresentazione di esso come questa, presente unicamente nella memoria dell'interprete:

var doc = document.implementation.createDocument("", "", null);
var peopleElem = doc.createElement("people");

var personElem1 = doc.createElement("person");
personElem1.setAttribute("first-name", "eric");
personElem1.setAttribute("middle-initial", "h");
personElem1.setAttribute("last-name", "jung");

var addressElem1 = doc.createElement("address");
addressElem1.setAttribute("street", "321 south st");
addressElem1.setAttribute("city", "denver");
addressElem1.setAttribute("state", "co");
addressElem1.setAttribute("country", "usa");
personElem1.appendChild(addressElem1);

var addressElem2 = doc.createElement("address");
addressElem2.setAttribute("street", "123 main st");
addressElem2.setAttribute("city", "arlington");
addressElem2.setAttribute("state", "ma");
addressElem2.setAttribute("country", "usa");
personElem1.appendChild(addressElem2);

var personElem2 = doc.createElement("person");
personElem2.setAttribute("first-name", "jed");
personElem2.setAttribute("last-name", "brown");

var addressElem3 = doc.createElement("address");
addressElem3.setAttribute("street", "321 north st");
addressElem3.setAttribute("city", "atlanta");
addressElem3.setAttribute("state", "ga");
addressElem3.setAttribute("country", "usa");
personElem2.appendChild(addressElem3);

var addressElem4 = doc.createElement("address");
addressElem4.setAttribute("street", "123 west st");
addressElem4.setAttribute("city", "seattle");
addressElem4.setAttribute("state", "wa");
addressElem4.setAttribute("country", "usa");
personElem2.appendChild(addressElem4);

var addressElem5 = doc.createElement("address");
addressElem5.setAttribute("street", "321 south avenue");
addressElem5.setAttribute("city", "denver");
addressElem5.setAttribute("state", "co");
addressElem5.setAttribute("country", "usa");
personElem2.appendChild(addressElem5);

peopleElem.appendChild(personElem1);
peopleElem.appendChild(personElem2);
doc.appendChild(peopleElem);

Si veda anche Il capitolo sul DOM del Tutorial XUL (in inglese).

Automatizzando la creazione dinamica dell'albero DOM

L'invocazione dell'API Javascript W3C DOM, può anche essere automatizzata.

Sezione da scrivere

Costruire un albero DOM XML a partire da stringhe di codice sorgente

Il seguente esempio mostra la costruzione di un albero DOM tramite parsing di un codice sorgente.

var sMyString = "<a id=\"a\"><b id=\"b\">hey!<\/b><\/a>";
var oParser = new DOMParser();
var oDOM = oParser.parseFromString(sMyString, "text\/xml");
// print the name of the root element or error message
dump(oDOM.documentElement.nodeName == "parsererror" ? "error while parsing" : oDOM.documentElement.nodeName);

Tutorial su come rendere questo codice cross browser (in inglese)

Costruire un albero DOM a partire da un file

Preambolo da scrivere.

Usando DOMParser

Sezione da scrivere

Usando XMLHttpRequest

Come già precedentemente accennato, sebbene ciascuna istanza di DOMParser possegga un metodo chiamato parseFromStream(), è più facile utilizzare XMLHttpRequest per parsare documenti XML in alberi DOM (XMLHttpRequest funziona bene sia in locale che in remoto). Di seguito c'è un codice di esempio che legge e parsa in un albero DOM un file XML locale:

var oReq = new XMLHttpRequest();
oReq.open("GET", "chrome://passwdmaker/content/people.xml", false);
oReq.send(null);
// print the name of the root element or error message
var oDOM = oReq.responseXML;
dump(oDOM.documentElement.nodeName == "parsererror" ? "error while parsing" : oDOM.documentElement.nodeName);

N.B. Il metodo responseXML è sempre un'istanza di Document – e di conseguenza un oggetto – a differenza del metodo responseText, che è sempre un valore primario (in questo caso una stringa).

Usando l'elemento {{ HTMLElement("object") }}.

Di seguito è presentata un'altra via possibile per parsare un file XML in un albero DOM: usando il tag {{ HTMLElement("object") }}. Prima di lanciare il seguente esempio è necessario creare un file XML valido chiamato purchase_order.xml:

<!DOCTYPE html>
<html>
<head>
<title>XML Data Block Demo</title>
<script>
function runDemo() {
  var doc = document.getElementById("purchase-order").contentDocument;
  var lineItems = doc.getElementsByTagNameNS("http://example.mozilla.org/PurchaseOrderML", "lineItem");
  var firstPrice = lineItems[0].getElementsByTagNameNS("http://example.mozilla.org/PurchaseOrderML", "price")[0].textContent;
  document.getElementById("output-box").textContent = "The purchase order contains " + lineItems.length + " line items. The price of the first line item is " + firstPrice + ".";
}
</script>
</head>
<body onload="runDemo()";>
<object id="purchase-order" data="purchase_order.xml" type="text/xml" style="display: none;"></object>
<div id="output-box">Demo did not run</div>
</body>
</html>

Per ulteriori approfondimenti, si rimanda all'articolo: Usare le XML Data Islands in Mozilla.

Decostruire un albero DOM

Da adesso in poi daremo per scontato il fatto che abbiamo già un albero DOM nella memoria dell'interprete Javascript e che il nostro scopo è invece quello di utilizzare tale istanza di Document nei modi più disparati.

Convertire un documento XML in stringhe di codice sorgente

L'esempio seguente mostra come ottenere dalla variabile doc — il nostro albero DOM — una stringa contenente l'intero suo codice sorgente:

var oSerializer = new XMLSerializer();
var sXML = oSerializer.serializeToString(doc);

Non è possibile creare un istanza di XMLSerializer (ovvero lanciare: new XMLSerializer()) dall'interno di un componente JS XPCOM o dall'interno di un modulo. Per farlo bisogna lanciare:

var oSerializer = Components.classes["@mozilla.org/xmlextras/xmlserializer;1"].createInstance(Components.interfaces.nsIDOMSerializer);
var sXML = oSerializer.serializeToString(doc);

Come ottenere stringhe di codice sorgente di facile lettura

You can pretty print a DOM tree using XMLSerializer and E4X. First, create a DOM tree as described in the Come creare un albero DOM article. Alternatively, use a DOM tree obtained from XMLHttpRequest. We assume it's in the doc variable.

var oSerializer = new XMLSerializer();
var sPrettyXML = XML(oSerializer.serializeToString(doc)).toXMLString();

Indents are provided with two spaces. You can, of course, use DOM:treeWalker to write your own, more performant version which also has the advantage that you can customize the indent string to be whatever you like.

Note: When using the E4X toXMLString method your CDATA elements will be lost and only the containing text remains. So using the above method might not be useful if you have CDATA elements in your XML.

<content><![CDATA[This is the content]]></content>

Will become

<content>This is the content</content>

Convertire un foglio XML in un albero di oggetti Javascript (JXON)

JXON (lossless Javascript XML Object Notation) è un nome generico col quale viene definita la rappresentazione di oggetti Javascript in linguaggio XML. Non esistono veri e propri standard per questa rappresentazione, ma da poco tempo a questa parte cominciano ad affacciarsi in rete alcune convenzioni.

JXON non è un metodo per indirizzare poche parti di un documento XML, dato che il suo punto di forza è la conversione per intero di un albero DOM. Se il nostro scopo è quello di accedere a delle informazioni limitate di un albero DOM, si raccomanda vivamente di Usare XPath.

Ci sono casi invece in cui un documento XML è costruito in maniera tale da avere come principale destinatario del proprio contenuto proprio l'interprete Javascript. In tal caso JXON si presenta come la via migliore.

Per questo tutto questo capitolo immaginiamo di aver parsato, come al solito nella nostra variabile doc, questo documento XML di esempio:

esempio.xml
<?xml version="1.0"?>
<!DOCTYPE catalog SYSTEM "catalog.dtd">
<catalog>
   <product description="Cardigan Sweater">
      <catalog_item gender="Men's">
         <item_number>QWZ5671</item_number>
         <price>39.95</price>
         <size description="Medium">
            <color_swatch image="red_cardigan.jpg">Red</color_swatch>
            <color_swatch image="burgundy_cardigan.jpg">Burgundy</color_swatch>
         </size>
         <size description="Large">
            <color_swatch image="red_cardigan.jpg">Red</color_swatch>
            <color_swatch image="burgundy_cardigan.jpg">Burgundy</color_swatch>
         </size>
      </catalog_item>
      <catalog_item gender="Women's">
         <item_number>RRX9856</item_number>
         <discount_until>Dec 25, 1995</discount_until>
         <price>42.50</price>
         <size description="Medium">
            <color_swatch image="black_cardigan.jpg">Black</color_swatch>
         </size>
      </catalog_item>
   </product>
   <script type="text/javascript"><![CDATA[function matchwo(a,b) {
    if (a < b && a < 0) { return 1; }
    else { return 0; }
}]]></script>
</catalog>

Adesso proviamo a ottenere una rappresentazione della variabile doc — l'albero DOM — attraverso un albero di oggetti Javascript (you can read more about working with Objects and how Javascript is Object-Oriented). Per far ciò possiamo utilizzare diversi algoritmi di conversione.

Per semplicità gli algoritmi qui proposti (si veda: #1, #2, #3, #4) prenderanno in considerazione solamente i seguenti tipi di nodi e i loro attributi:

  1. Document (solo come argomento della funzione),
  2. DocumentFragment (solo come argomento della funzione),
  3. Element,
  4. Text (mai come argomento della funzione),
  5. CDATASection (mai come argomento della funzione).

Si tratta di un buon compromesso per un uso Javascript, dacché la gran parte delle informazioni di un documento XML è contenuta in questo tipo di nodi. Ogni altra informazione (come processing instructions, xml schemas, commenti, etc.) andrà persa. Allo scopo di evitare conflitti, la lettura dei nomi dei nodi e dei loro attributi è case insensitive (resa sempre in minuscolo) e di conseguenza le proprietà locali dell'albero di oggetti così ottenuto aggiunte via JavaScript dovranno avere un qualche tipo di lettera maiuscola al loro interno, per evitare di sovrascrivere le proprietà ottenute dal foglio XML, come si può vedere di seguito. I seguenti algoritmi sono liberamente basati sulla Convenzione di Parker, versione 0.4, che prevede il riconoscimento del typeof del contenuto di testo di ogni singolo nodo letto.

Algoritmo #1: una via prolissa

Questo semplice costruttore ricorsivo converte un albero DOM XML in un albero di oggetti Javascript. Il contenuto di testo di ogni nodo è salvato all'interno della proprietà keyValue, mentre i nodeAttributes, se esistono, sono annidati come proprietà dell'oggetto-figlio keyAttributes. L'argomento del costruttore può essere l'intero Document, un DocumentFragment o, più semplicemente, un nodo di tipo Element di esso.

function buildValue(sValue) {
  if (/^\s*$/.test(sValue)) { return null; }
  if (/^(true|false)$/i.test(sValue)) { return sValue.toLowerCase() === "true"; }
  if (isFinite(sValue)) { return parseFloat(sValue); }
  if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
  return sValue;
}

function XMLData (oXMLParent) {
  var nAttrLen = 0, nLength = 0, sCollectedTxt = "";
  // children
  if (oXMLParent.hasChildNodes()) {
    for (var oItChild, sItKey, sItVal, nChildId = 0; nChildId < oXMLParent.childNodes.length; nChildId++) {
      oItChild = oXMLParent.childNodes.item(nChildId);
      if ((oItChild.nodeType - 1 | 1) === 3) { sCollectedTxt += oItChild.nodeType === 3 ? oItChild.nodeValue.replace(/^\s+|\s+$/g, "") : oItChild.nodeValue; } // nodeType is "Text" (3) or "CDATASection" (4)
      else if (oItChild.nodeType === 1 && !oItChild.prefix) { // nodeType is "Element" (1)
        sItKey = oItChild.nodeName.toLowerCase();
        sItVal = new XMLData(oItChild);
        if (this.hasOwnProperty(sItKey)) {
          if (this[sItKey].constructor !== Array) { this[sItKey] = [this[sItKey]]; }
          this[sItKey].push(sItVal);
        } else { this[sItKey] = sItVal; nLength++; }
      }
    }
    this.keyValue = buildValue(sCollectedTxt);
  } else { this.keyValue = null; }
  // node attributes
  if (oXMLParent.hasAttributes()) {
    var oItAttr;
    this.keyAttributes = {};
    for (nAttrLen; nAttrLen < oXMLParent.attributes.length; nAttrLen++) {
      oItAttr = oXMLParent.attributes.item(nAttrLen);
      this.keyAttributes[oItAttr.nodeName.toLowerCase()] = buildValue(oItAttr.nodeValue);
    }
  }
  // optional properties and methods; you could safely adjoust/remove them...
  this.keyLength = nLength;
  this.attributesLength = nAttrLen;
  // this.DOMNode = oXMLParent;
  this.valueOf = function() { return this.keyValue; };
  this.toString = function() { return String(this.keyValue); };
  this.getItem = function(nItem) {
    if (nLength === 0) { return null; }
    var iItem = 0;
    for (var sKeyName in this) { if (iItem === nItem) { return this[sKeyName]; } iItem++; }
    return null;
  };
  this.getAttribute = function(nAttrib) {
    if (nAttrLen === 0 || nAttrib + 1 > nAttrLen) { return null; }
    var nItAttr = 0;
    for (var sAttrName in this.keyAttributes) { if (nItAttr === nAttrib) { return this.keyAttributes[sAttrName]; } nItAttr++; }
    return null;
  };
  this.hasChildren = function() { return this.keyLength > 0; };
}

var myObject = new XMLData(doc);
// abbiamo ottenuto il nostro albero di oggetti Javascript! provare per credere: alert(JSON.stringify(myObject));

Con questo algoritmo il nostro esempio diventerà:

{
  "catalog": {
    "product": {
      "catalog_item": [{
        "item_number": {
          "keyValue": "QWZ5671",
          "keyLength": 0,
          "attributesLength": 0
        },
        "price": {
          "keyValue": 39.95,
          "keyLength": 0,
          "attributesLength": 0
        },
        "size": [{
          "color_swatch": [{
            "keyValue": "Red",
            "keyAttributes": {
              "image": "red_cardigan.jpg"
            },
            "keyLength": 0,
            "attributesLength": 1
          }, {
            "keyValue": "Burgundy",
            "keyAttributes": {
              "image": "burgundy_cardigan.jpg"
            },
            "keyLength": 0,
            "attributesLength": 1
          }],
          "keyValue": null,
          "keyAttributes": {
            "description": "Medium"
          },
          "keyLength": 1,
          "attributesLength": 1
        }, {
          "color_swatch": [{
            "keyValue": "Red",
            "keyAttributes": {
              "image": "red_cardigan.jpg"
            },
            "keyLength": 0,
            "attributesLength": 1
          }, {
            "keyValue": "Burgundy",
            "keyAttributes": {
              "image": "burgundy_cardigan.jpg"
            },
            "keyLength": 0,
            "attributesLength": 1
          }],
          "keyValue": null,
          "keyAttributes": {
            "description": "Large"
          },
          "keyLength": 1,
          "attributesLength": 1
        }],
        "keyValue": null,
        "keyAttributes": {
          "gender": "Men's"
        },
        "keyLength": 3,
        "attributesLength": 1
      }, {
        "item_number": {
          "keyValue": "RRX9856",
          "keyLength": 0,
          "attributesLength": 0
        },
        "discount_until": {
          "keyValue": new Date(1995, 11, 25),
          "keyLength": 0,
          "attributesLength": 0
        },
        "price": {
          "keyValue": 42.5,
          "keyLength": 0,
          "attributesLength": 0
        },
        "size": {
          "color_swatch": {
            "keyValue": "Black",
            "keyAttributes": {
              "image": "black_cardigan.jpg"
            },
            "keyLength": 0,
            "attributesLength": 1
          },
          "keyValue": null,
          "keyAttributes": {
            "description": "Medium"
          },
          "keyLength": 1,
          "attributesLength": 1
        },
        "keyValue": null,
        "keyAttributes": {
          "gender": "Women's"
        },
        "keyLength": 4,
        "attributesLength": 1
      }],
      "keyValue": null,
      "keyAttributes": {
        "description": "Cardigan Sweater"
      },
      "keyLength": 1,
      "attributesLength": 1
    },
    "script": {
      "keyValue": "function matchwo(a,b) {\n  if (a < b && a < 0) { return 1; }\n  else { return 0; }\n}",
      "keyAttributes": {
        "type": "text/javascript"
      },
      "keyLength": 0,
      "attributesLength": 1
    },
    "keyValue": null,
    "keyLength": 2,
    "attributesLength": 0
  },
  "keyValue": null,
  "keyLength": 1,
  "attributesLength": 0
}

È un approccio raccomandato nel caso in cui ci sia completamente ignota la struttura del documento XML che andremo a leggere.

Algoritmo #2: una via un po' meno prolissa

Quello che segue è un altro, più semplice, metodo di conversione. Dove i nodeAttributes sono annidati nello stesso oggetto contenente la trascrizione dei nodi figli sebbene, a differenza di quelli, questi siano contrassegnati dal prefisso “@”. Come sopra, il contenuto di testo di ciascun nodo è affidato alla proprietà keyValue. L'argomento del costruttore può essere l'intero Document, un DocumentFragment o, più semplicemente, un nodo di tipo Element di esso.

function buildValue(sValue) {
  if (/^\s*$/.test(sValue)) { return null; }
  if (/^(true|false)$/i.test(sValue)) { return sValue.toLowerCase() === "true"; }
  if (isFinite(sValue)) { return parseFloat(sValue); }
  if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
  return sValue;
}

function XMLData (oXMLParent) {
  if (oXMLParent.hasChildNodes()) {
    var sCollectedTxt = "";
    for (var oItChild, sItKey, sItVal, nChildId = 0; nChildId < oXMLParent.childNodes.length; nChildId++) {
      oItChild = oXMLParent.childNodes.item(nChildId);
      if ((oItChild.nodeType - 1 | 1) === 3) { sCollectedTxt += oItChild.nodeType === 3 ? oItChild.nodeValue.replace(/^\s+|\s+$/g, "") : oItChild.nodeValue; }
      else if (oItChild.nodeType === 1 && !oItChild.prefix) {
        sItKey = oItChild.nodeName.toLowerCase();
        sItVal = new XMLData(oItChild);
        if (this.hasOwnProperty(sItKey)) {
          if (this[sItKey].constructor !== Array) { this[sItKey] = [this[sItKey]]; }
          this[sItKey].push(sItVal);
        } else { this[sItKey] = sItVal; }
      }
    }
    if (sCollectedTxt) { this.keyValue = buildValue(sCollectedTxt); }
  }
  if (oXMLParent.hasAttributes()) {
    var oItAttr;
    for (var iAttrId = 0; iAttrId < oXMLParent.attributes.length; iAttrId++) {
      oItAttr = oXMLParent.attributes.item(iAttrId);
      this["@" + oItAttr.nodeName.toLowerCase()] = buildValue(oItAttr.nodeValue);
    }
  }
}

var myObject = new XMLData(doc);
// abbiamo ottenuto il nostro albero di oggetti Javascript! provare per credere: alert(JSON.stringify(myObject));

Con questo algoritmo il nostro esempio diventerà:

{
  "catalog": {
    "product": {
      "catalog_item": [{
        "item_number": {
          "keyValue": "QWZ5671"
        },
        "price": {
          "keyValue": 39.95
        },
        "size": [{
          "color_swatch": [{
            "keyValue": "Red",
            "@image": "red_cardigan.jpg"
          }, {
            "keyValue": "Burgundy",
            "@image": "burgundy_cardigan.jpg"
          }],
          "@description": "Medium"
        }, {
          "color_swatch": [{
            "keyValue": "Red",
            "@image": "red_cardigan.jpg"
          }, {
            "keyValue": "Burgundy",
            "@image": "burgundy_cardigan.jpg"
          }],
          "@description": "Large"
        }],
        "@gender": "Men's"
      }, {
        "item_number": {
          "keyValue": "RRX9856"
        },
        "discount_until": {
          "keyValue": new Date(1995, 11, 25)
        },
        "price": {
          "keyValue": 42.5
        },
        "size": {
          "color_swatch": {
            "keyValue": "Black",
            "@image": "black_cardigan.jpg"
          },
          "@description": "Medium"
        },
        "@gender": "Women's"
      }],
      "@description": "Cardigan Sweater"
    },
    "script": {
      "keyValue": "function matchwo(a,b) {\n  if (a < b && a < 0) { return 1; }\n  else { return 0; }\n}",
      "@type": "text/javascript"
    }
  }
}

È un approccio possibile nel caso in cui ci sia parzialmente nota la struttura del documento XML che andremo a leggere.

Algoritmo #3: una via sintetica

Ora proveremo un altro metodo di conversione. Questo algoritmo è quello che si avvicina di più alla Convenzione di Parker. Esso è molto simile al precedente, eccetto che per il fatto che i nodi che non contengono alcun nodo-figlio di tipo Element, ma solo nodi-figli di tipo Text e/o CDATASection, non sono rappresentati da oggetti, ma direttamente da booleani, numeri, stringhe o istanze del costruttore Date (si veda la Convenzione di Parker). La rappresentazione dei nodi completamente vuoti invece (cioè che non contengono né nodi di tipo Element, né nodi di tipo Text, né nodi di tipo CDATASection) avranno come valore predefinito true. Inoltre questa volta non si è usato un costruttore, ma una semplice funzione. L'argomento della funzione può essere l'intero Document, un DocumentFragment o, più semplicemente, un nodo di tipo Element di esso.

In molti casi questo rappresenta il metodo di conversione più pratico.

function buildValue(sValue) {
  if (/^\s*$/.test(sValue)) { return null; }
  if (/^(true|false)$/i.test(sValue)) { return sValue.toLowerCase() === "true"; }
  if (isFinite(sValue)) { return parseFloat(sValue); }
  if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
  return sValue;
}

function getXMLData (oXMLParent) {
  var vResult = /* put here the default value for empty nodes! */ true, nLength = 0, sCollectedTxt = "";
  if (oXMLParent.hasAttributes()) {
    vResult = {};
    for (nLength; nLength < oXMLParent.attributes.length; nLength++) {
      oItAttr = oXMLParent.attributes.item(nLength);
      vResult["@" + oItAttr.nodeName.toLowerCase()] = buildValue(oItAttr.nodeValue.replace(/^\s+|\s+$/g, ""));
    }
  }
  if (oXMLParent.hasChildNodes()) {
    for (var oItChild, sItKey, sItVal, nChildId = 0; nChildId < oXMLParent.childNodes.length; nChildId++) {
      oItChild = oXMLParent.childNodes.item(nChildId);
      if (oItChild.nodeType === 4) { sCollectedTxt += oItChild.nodeValue; } /* nodeType is "CDATASection" (4) */
      else if (oItChild.nodeType === 3) { sCollectedTxt += oItChild.nodeValue.replace(/^\s+|\s+$/g, ""); } /* nodeType is "Text" (3) */
      else if (oItChild.nodeType === 1 && !oItChild.prefix) { /* nodeType is "Element" (1) */
         if (nLength === 0) { vResult = {}; }
        sItKey = oItChild.nodeName.toLowerCase();
        sItVal = getXMLData(oItChild);
        if (vResult.hasOwnProperty(sItKey)) {
          if (vResult[sItKey].constructor !== Array) { vResult[sItKey] = [vResult[sItKey]]; }
          vResult[sItKey].push(sItVal);
        } else { vResult[sItKey] = sItVal; nLength++; }
      }
     }
  }
  if (sCollectedTxt) { nLength > 0 ? vResult.keyValue = buildValue(sCollectedTxt) : vResult = buildValue(sCollectedTxt); }
  /* if (nLength > 0) { Object.freeze(vResult); } */
  return vResult;
}

var myObject = getXMLData(doc);
// abbiamo ottenuto il nostro albero di oggetti Javascript! provare per credere: alert(JSON.stringify(myObject));
Nota: Se si vuole congelare l'intero oggetto (a causa della natura "statica" di un documento XML), decommentare la stringa: /* if (nLength > 0) { Object.freeze(vResult); } */. Il metodo Object.freeze vieta l'aggiunta di nuove proprietà e la rimozione delle proprietà esistenti, congelando la loro enumerabilità, la loro configurabilità o la loro scrivibilità. In sostanza l'oggetto è reso effettivamente immutabile.

Con questo algoritmo il nostro esempio diventerà:

{
  "catalog": {
    "product": {
      "@description": "Cardigan Sweater",
      "catalog_item": [{
        "@gender": "Men's",
        "item_number": "QWZ5671",
        "price": 39.95,
        "size": [{
          "@description": "Medium",
          "color_swatch": [{
            "@image": "red_cardigan.jpg",
            "keyValue": "Red"
          }, {
            "@image": "burgundy_cardigan.jpg",
            "keyValue": "Burgundy"
          }]
        }, {
          "@description": "Large",
          "color_swatch": [{
            "@image": "red_cardigan.jpg",
            "keyValue": "Red"
          }, {
            "@image": "burgundy_cardigan.jpg",
            "keyValue": "Burgundy"
          }]
        }]
      }, {
        "@gender": "Women's",
        "item_number": "RRX9856",
        "discount_until": new Date(1995, 11, 25),
        "price": 42.5,
        "size": {
          "@description": "Medium",
          "color_swatch": {
            "@image": "black_cardigan.jpg",
            "keyValue": "Black"
          }
        }
      }]
    },
    "script": {
      "@type": "text/javascript",
      "keyValue": "function matchwo(a,b) {\n  if (a < b && a < 0) { return 1; }\n  else { return 0; }\n}"
    }
  }
}

È un approccio raccomandato nel caso in cui ci sia nota la struttura del documento XML che andremo a leggere.

Algoritmo #4: una via davvero minimalista

La seguente rappresenta un'altra possibile via di conversione. Anch'essa è molto vicina alla Convenzione di Parker. Con questo algoritmo la rappresentazione dei nodi di tipo Element che contengono a loro volta sullo stesso piano nodi-figli di tipo Element insieme con nodi-figli di tipo Text e/o di tipo CDATASection è resa per mezzo di istanze dei costruttori Boolean, Number, String, e Date. Di conseguenza la trascrizione di ogni nodo-figlio sarà annidata in oggetti di questo tipo.

Per esempio;

<employee type="usher">John Smith</employee>
<manager>Lisa Carlucci</manager>

diventerà

var myObject = {
  "employee": new String("John Smith"),
  "manager": "Lisa Carlucci"
};

myObject.employee["@type"] = "usher";

// test

alert(myObject.manager); // "Lisa Carlucci"
alert(myObject.employee["@type"]); // "usher"
alert(myObject.employee); // "John Smith"

Come per il terzo algoritmo, i nodi che non contengono alcun nodo-figlio di tipo Element, ma solo nodi-figli di tipo Text e/o CDATASection, non sono rappresentati da oggetti, ma direttamente da booleani, numeri, stringhe (valori primitivi) o istanze del costruttore Date (si veda la Convenzione di Parker). Come per il terzo algoritmo, non si è usato un costruttore, ma una semplice funzione. L'argomento della funzione può essere l'intero Document, un DocumentFragment o, più semplicemente, un nodo di tipo Element di esso.

function buildValue (sValue) {
  if (/^\s*$/.test(sValue)) { return null; }
  if (/^(true|false)$/i.test(sValue)) { return sValue.toLowerCase() === "true"; }
  if (isFinite(sValue)) { return parseFloat(sValue); }
  if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
  return sValue;
}

function objectify (vValue) {
  if (vValue === null) {
    return new (function() {
      this.toString = function() { return "null"; }
      this.valueOf = function() { return null; }
    })();
  }
  return vValue instanceof Object ? vValue : new vValue.constructor(vValue);
}

var aTmpEls = []; // loaded element nodes cache

function getXMLData (oXMLParent) {
  var  sItKey, sItVal, vResult, nLength = 0, nLevelStart = aTmpEls.length,
       nChildren = oXMLParent.hasChildNodes() ? oXMLParent.childNodes.length : 0, sCollectedTxt = "";

  for (var oItChild, nChildId = 0; nChildId < nChildren; nChildId++) {
    oItChild = oXMLParent.childNodes.item(nChildId);
    if (oItChild.nodeType === 4) { sCollectedTxt += oItChild.nodeValue; } /* nodeType is "CDATASection" (4) */
    else if (oItChild.nodeType === 3) { sCollectedTxt += oItChild.nodeValue.replace(/^\s+|\s+$/g, ""); } /* nodeType is "Text" (3) */
    else if (oItChild.nodeType === 1 && !oItChild.prefix) { aTmpEls.push(oItChild); } /* nodeType is "Element" (1) */
  }

  var nLevelEnd = aTmpEls.length, vBuiltVal = buildValue(sCollectedTxt);

  if (oXMLParent.hasAttributes()) {
    vResult = objectify(vBuiltVal);
    for (nLength; nLength < oXMLParent.attributes.length; nLength++) {
      oItAttr = oXMLParent.attributes.item(nLength);
      vResult["@" + oItAttr.nodeName.toLowerCase()] = buildValue(oItAttr.nodeValue.replace(/^\s+|\s+$/g, ""));
    }
  } else if (nLevelEnd > nLevelStart) { vResult = objectify(vBuiltVal); }

  for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
    sItKey = aTmpEls[nElId].nodeName.toLowerCase();
    sItVal = getXMLData(aTmpEls[nElId]);
    if (vResult.hasOwnProperty(sItKey)) {
    if (vResult[sItKey].constructor !== Array) { vResult[sItKey] = [vResult[sItKey]]; }
      vResult[sItKey].push(sItVal);
    } else { vResult[sItKey] = sItVal; nLength++; }
  }

  aTmpEls.length = nLevelStart;

  if (nLength === 0) { vResult = sCollectedTxt ? vBuiltVal : /* put here the default value for empty nodes: */ true; }
  /* else { Object.freeze(vResult); } */

  return vResult;
}

var myObject = getXMLData(doc);
alert(myObject.catalog.product.catalog_item[1].size.color_swatch["@image"]); // "black_cardigan.jpg"
alert(myObject.catalog.product.catalog_item[1].size.color_swatch); // "Black" !
Nota: Se si vuole congelare l'intero oggetto (a causa della natura "statica" di un documento XML), decommentare la stringa: /* else { Object.freeze(vResult); } */ . Il metodo Object.freeze vieta l'aggiunta di nuove proprietà e la rimozione delle proprietà esistenti, congelando la loro enumerabilità, la loro configurabilità o la loro scrivibilità. In sostanza l'oggetto è reso effettivamente immutabile.

È un approccio possibile nel caso in cui ci sia nota la struttura del documento XML che andremo a leggere.

La Convenzione di Parker

Le funzioni precedentemente elencate per la conversione di un documento XML in JSON (spesso chiamate «algoritmi JXON») sono più o meno liberamente fondate sulla Convenzione di Parker. È chiamata “Convenzione di Parker”, in opposizione alla “Convenzione di BadgerFish”, dal fumetto di Cuadrado Parker & Badger. Si veda anche: Convenzione di BadgerFish.

La seguente è una traduzione dall'inglese del paper originale della Convenzione di Parker (versione 0.4), dalla pagina “TransformingRules” del sito del progetto xml2json-xslt.

Questa convenzione è stata scritta per regolamentare la conversione in JSON da parte di XSLT, di conseguenza alcune parti di essa sono futili per Javascript.

Conversione in JSON
  1. The root element will be absorbed, for there is only one:

    <root>test</root>

    becomes

    "test"
    
  2. Element names become object properties:

    <root><name>Xml</name><encoding>ASCII</encoding></root>

    becomes

    {
      "name": "Xml",
      "encoding": "ASCII"
    }
    
  3. Numbers are recognized (integers and decimals):

    <root><age>12</age><height>1.73</height></root>

    becomes

    {
      "age": 12,
      "height": 1.73
    }
    
  4. Booleans are recognized case insensitive:

    <root><checked>True</checked><answer>FALSE</answer></root>

    becomes

    {
      "checked": true,
      "answer": false
    }
    
  5. Strings are escaped:

    <root>Quote: &quot; New-line:
    </root>
    

    becomes

    "Quote: \" New-line:\n"
  6. Empty elements will become null:

    <root><nil/><empty></empty></root>

    becomes

    {
      "nil": null,
      "empty": null
    }
    
  7. If all sibling elements have the same name, they become an array

    <root><item>1</item><item>2</item><item>three</item></root>
    

    becomes

    [1, 2, "three"]
    
  8. Mixed mode text-nodes, comments and attributes get absorbed:

    <root version="1.0">testing<!--comment--><elementtest="true">1</element></root>
    

    becomes

    { "element": true }
    
  9. Namespaces get absorbed, and prefixes will just be part of the property name:

    <root xmlns:ding="http://zanstra.com/ding"><ding:dong>binnen</ding:dong></root>
    

    becomes

    { "ding:dong" : "binnen" }
    
Note: Our algorithms comply with the points 2, 3, 4 and 7. The third and the fourth algorithm comply also with the point 6 (but true instead of null). The point 5 is automatically managed by the Javascript method JSON.stringify.
Appendice Javascript

All the same as the JSON translation, but with these extra's:

  1. Property names are only escaped when necessary

    <root><while>true</while><wend>false</wend><only-if/></root>

    becomes

    {
      "while": true,
      wend: false,
      "only-if": null
    }
    
  2. Within a string, closing elements "</" are escaped as "<\/"

    <root><![CDATA[<script>alert("YES");</script>]]></root>

    becomes

    { script: "<script>alert(\"YES\")<\/script>" }
    
  3. Dates are created as new Date() objects

    <root>2006-12-25</root>

    becomes

    new Date(2006, 12 - 1, 25)
    
  4. Attributes and comments are shown as comments (for testing-purposes):

    <!--testing--><root><test version="1.0">123</test></root>
    

    becomes

    /* testing */ { test /* @version = "1.0" */ : 123}
    
  5. A bit of indentation is done, to keep things ledgible

Note: Our algorithms comply with the point 3 (but without month decrease). The points 1 and 2 are automatically managed by the Javascript method JSON.stringify.

In sintesi

Let's take the third algorithm as the most representative JXON parsing algorithm. A single structured XML Element might have eight different configurations:

  1. an empty element,
  2. an element with pure text content,
  3. an empty element with attributes,
  4. an element with text content and attributes,
  5. an element containing elements with different names,
  6. an element containing elements with identical names,
  7. an element containing elements and contiguous text,
  8. an element containing elements and non contiguous text.

The following table shows the corresponding conversion patterns between XML and JSON according to the third algorithm.

Case XML JSON Javascript access
1 <animal/> "animal": true myObject.animal
2 <animal>text</animal> "animal": "text" myObject.animal
3 <animal name="value" /> "animal": {"@name": "value"} myObject.animal["@name"]
4 <animal name="value">text</animal> "animal": { "@name": "value", "keyValue": "text" } myObject.animal["@name"], myObject.animal.keyValue
5 <animal> <dog>Charlie</dog> <cat>Deka</cat> </animal> "animal": { "dog": "Charlie", "cat": "Deka" } myObject.animal.dog, myObject.animal.cat
6 <animal> <dog>Charlie</dog> <dog>Mad Max</dog> </animal> "animal": { "dog": ["Charlie", "Mad Max"] } myObject.animal.dog[0], myObject.animal.dog[1]
7 <animal> in my house <dog>Charlie</dog> </animal> "animal": { "keyValue": "in my house", "dog": "Charlie" } myObject.animal.keyValue, myObject.animal.dog
8 <animal> in my ho <dog>Charlie</dog> use </animal> "animal": { "keyValue": "in my house", "dog": "Charlie" } myObject.animal.keyValue, myObject.animal.dog

Considerazioni sul codice

In these examples we chose to use a property named keyValue for the text content. The lack of standars for XML to JSON conversion leads developers to choose several property names for the text content of XML Element nodes which contain also other child nodes. Sometimes it is used a property called $. Other times it is used a property called #text. In the algorithms proposed here you can easily change this name, depending on your needs.

The choice of using a true value instead of a null value to represent empty nodes is due to the fact that when in an XML document there is an empty node the reason is often to express a Boolean content, as in this case:

<car>
  <type>Ferrari</type>
  <bought />
</car>

If the value were null it would be more cumbersome to launch a code like this:

if (myObject.car.Ferrari.bought) {
  // do something
}
According to our third algorithm and our fourth algorithm, just Text nodes or CDATASection nodes which contain nothing but white spaces (precisely: /^\s+$/) are parsed as null.

An important consideration is that, using the third or the fourth algorithm, an XML Document can be used to create any type of Javascript object. For example, If you want to create an object like the following:

{
  "bool": true,
  "array": ["Cinema", "Hot dogs", false],
  "object": {
    "nickname": "Jack",
    "registration_date": new Date(1995, 11, 25),
    "privileged_user": true
  },
  "num": 99,
  "text": "Hello World!"
}

you must just create an XML document with the following structure:

<bool>true</bool>
<array>Cinema</array>
<array>Hot dogs</array>
<array>false</array>
<object>
  <nickname>Jack</nickname>
  <registration_date>Dec 25, 1995</registration_date>
  <privileged_user />
</object>
<num>99</num>
<text>Hello World!</text>

This example also shows how the ideal JXON document is an XML document designed specifically to be converted in JSON format.

Costruire file a partire da alberi DOM

First, create a DOM tree as described in the Come creare un albero DOM article. If you have already have a DOM tree from using XMLHttpRequest, skip to the end of this section.

Now, let's serialize doc — the DOM tree — to a file (you can read more about using files in Mozilla):

var oFOStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
var oFile = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties).get("ProfD", Components.interfaces.nsILocalFile); // get profile folder
oFile.append("extensions"); // extensions sub-directory
oFile.append("{5872365E-67D1-4AFD-9480-FD293BEBD20D}"); // GUID of your extension
oFile.append("myXMLFile.xml"); // filename
oFOStream.init(oFile, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate
(new XMLSerializer()).serializeToStream(doc, oFOStream, ""); // rememeber, doc is the DOM tree
oFOStream.close();

Costruire file a partire da oggetti XMLHttpRequest

If you already have a DOM tree from using XMLHttpRequest, use the same code as above but replace serializer.serializeToStream(doc, foStream, "") with serializer.serializeToStream(xmlHttpRequest.responseXML.documentElement, foStream, "") where xmlHttpRequest is an instance of XMLHttpRequest.

Note that this first parses the XML retrieved from the server, then re-serializes it into a stream. Depending on your needs, you could just save the xmlHttpRequest.responseText directly.

Resources

{{ languages( { "ja": "ja/Parsing_and_serializing_XML", "en": "en/Parsing_and_serializing_XML" } ) }}

Sorgente della versione

<p>{{ T() }}</p>
<p>Mozilla gestisce ampiamente <a href="/it/XML" title="it/XML">XML</a>. Sono gestite diverse Raccomandazioni e bozze del World Wide Web Consortium (<a class="external" href="http://w3c.org/">W3C</a>) per la famiglia XML, così come altre tecnologie relative.</p>
<h4 name="So_what.3F">Che cos'è un albero DOM?</h4>
<p>Per albero DOM s'intende un'istanza di <code><a class="external" href="http://xulplanet.com/references/objref/Document.html">Document</a></code>. Si tratta quindi di un oggetto Javascript e non è da confondere con una stringa di testo contenente il codice sorgente di un documento XML ancora da parsare.</p>
<p>DOM trees can be queried using <a href="/it/Usare_XPath" title="it/Usare_XPath">XPath</a> expressions, converted to strings or written to a local or remote files using <code>XMLSerializer</code> (without having to first convert to a string), POSTed to a web server (via <code><a href="/it/XMLHttpRequest" title="it/XMLHttpRequest">XMLHttpRequest</a></code>),</p>
<p>You can use DOM trees to model data which isn't well-suited for RDF (or perhaps you just don't like RDF). Another application is that, since XUL is XML, the UI of your application can be dynamically manipulated, downloaded, uploaded, saved, loaded, converted, or transformed quite easily.</p>
<p>Mozilla offre le seguenti tecnologie native per lavorare con documenti XML:</p>
<ul> <li><a href="/it/XPath" title="it/XPath">XPath</a> per <strong>indirizzare parti diverse di un documento XM</strong>L,</li> <li><a href="/it/XMLSerializer" title="it/XMLSerializer">XMLSerializer</a> per convertire <strong>alberi DOM in stringhe o files</strong>,</li> <li><a href="/it/DOM/DOMParser" title="it/DOMParser">DOMParser</a> costruire un documento XML <strong>convertendo delle stringhe in alberi DOM</strong>,</li> <li><a href="/it/XMLHttpRequest" title="it/XMLHttpRequest">XMLHttpRequest</a> per parsare <strong>a partire da file</strong> documenti XML in albero DOM. Sebbene anche le istanze di <code>DOMParser</code> abbiano un metodo chiamato <code>parseFromStream()</code>, è più facile utilizzare <a href="/it/XMLHttpRequest" title="it/XMLHttpRequest">XMLHttpRequest</a> che lavore sia con file remoti (non confinati al solo protocollo HTTP) che con file locali,</li> <li><a href="/it/XSLT" title="it/XSLT">XSLT</a> e <a href="/it/XLink" title="it/XLink">XLink</a> per <strong>manipolare il contenuto</strong> di un documento XML.</li>
</ul>
<p>È possibile comunque creare manualmente propri algoritmi per la serializzazione o la conversione di un documento XML, come si vedrà <a href="#JXON" title="Vai alla sezione su JXON">in seguito.</a></p>
<h2>Costruire un albero DOM</h2>
<p>In questa sezione iniziale il nostro scopo sarà quello di ottenere un albero DOM.</p>
<p>Un albero DOM è un oggetto Javascript. Ci sono molti modi per costruirlo/ottenerlo, a seconda delle proprie esigenze. Di seguito verranno elencate varie strade: a partire da una stringa di codice sorgente, a partire da file o a partire da strutture di differente natura.</p>
<h3>Creare dinamicamente un albero DOM</h3>
<p>Questo paragrafo illustra come utilizzare l'API JavaScript <a class="external" href="http://www.w3.org/TR/DOM-Level-3-Core/core.html">DOM Core</a> per creare e modificare oggetti DOM. Essa è attiva in tutte le applicazioni <em>Gecko-based</em> (come Firefox, per esempio) sia in <em>privileged code</em> (estensioni) che in <em>unprivileged code</em> (pagine internet).</p>
<h4 name="Dynamically_creating_a_DOM_tree">Scrivendolo a mano</h4>
<p>L'API JavaScript <a class="external" href="http://www.w3.org/TR/DOM-Level-3-Core/core.html">W3C DOM</a> può essere invocata manualmente.</p>
<p>Si consideri il seguente documento XML:</p>
<pre class="brush: xml">&lt;?xml version="1.0"?&gt;
&lt;people&gt;
  &lt;person first-name="eric" middle-initial="H" last-name="jung"&gt;
    &lt;address street="321 south st" city="denver" state="co" country="usa"/&gt;
    &lt;address street="123 main st" city="arlington" state="ma" country="usa"/&gt;
  &lt;/person&gt;

  &lt;person first-name="jed" last-name="brown"&gt;
    &lt;address street="321 north st" city="atlanta" state="ga" country="usa"/&gt;
    &lt;address street="123 west st" city="seattle" state="wa" country="usa"/&gt;
    &lt;address street="321 south avenue" city="denver" state="co" country="usa"/&gt;
  &lt;/person&gt;
&lt;/people&gt;
</pre>
<p>L'API Javascript <a class="external" href="http://www.w3.org/TR/DOM-Level-3-Core/core.html">W3C DOM</a>, supportata da Mozilla, può essere usata per creare una rappresentazione di esso come questa, presente unicamente nella memoria dell'interprete:</p>
<pre class="brush: js">var doc = document.implementation.createDocument("", "", null);
var peopleElem = doc.createElement("people");

var personElem1 = doc.createElement("person");
personElem1.setAttribute("first-name", "eric");
personElem1.setAttribute("middle-initial", "h");
personElem1.setAttribute("last-name", "jung");

var addressElem1 = doc.createElement("address");
addressElem1.setAttribute("street", "321 south st");
addressElem1.setAttribute("city", "denver");
addressElem1.setAttribute("state", "co");
addressElem1.setAttribute("country", "usa");
personElem1.appendChild(addressElem1);

var addressElem2 = doc.createElement("address");
addressElem2.setAttribute("street", "123 main st");
addressElem2.setAttribute("city", "arlington");
addressElem2.setAttribute("state", "ma");
addressElem2.setAttribute("country", "usa");
personElem1.appendChild(addressElem2);

var personElem2 = doc.createElement("person");
personElem2.setAttribute("first-name", "jed");
personElem2.setAttribute("last-name", "brown");

var addressElem3 = doc.createElement("address");
addressElem3.setAttribute("street", "321 north st");
addressElem3.setAttribute("city", "atlanta");
addressElem3.setAttribute("state", "ga");
addressElem3.setAttribute("country", "usa");
personElem2.appendChild(addressElem3);

var addressElem4 = doc.createElement("address");
addressElem4.setAttribute("street", "123 west st");
addressElem4.setAttribute("city", "seattle");
addressElem4.setAttribute("state", "wa");
addressElem4.setAttribute("country", "usa");
personElem2.appendChild(addressElem4);

var addressElem5 = doc.createElement("address");
addressElem5.setAttribute("street", "321 south avenue");
addressElem5.setAttribute("city", "denver");
addressElem5.setAttribute("state", "co");
addressElem5.setAttribute("country", "usa");
personElem2.appendChild(addressElem5);

peopleElem.appendChild(personElem1);
peopleElem.appendChild(personElem2);
doc.appendChild(peopleElem);
</pre>
<p>Si veda anche <a href="/en/XUL_Tutorial/Document_Object_Model" title="en/XUL_Tutorial/Document_Object_Model">Il capitolo sul DOM del Tutorial XUL</a> (in inglese).</p>
<h4>Automatizzando la creazione dinamica dell'albero DOM</h4>
<p>L'invocazione dell'API Javascript <a class="external" href="http://www.w3.org/TR/DOM-Level-3-Core/core.html">W3C DOM</a>, può anche essere automatizzata.</p>
<p>Sezione da scrivere</p>
<h3>Costruire un albero DOM XML a partire da stringhe di codice sorgente</h3>
<p>Il seguente esempio mostra la costruzione di un albero DOM tramite <em>parsing</em> di un codice sorgente.</p>
<pre class="brush: js">var sMyString = "&lt;a id=\"a\"&gt;&lt;b id=\"b\"&gt;hey!&lt;\/b&gt;&lt;\/a&gt;";
var oParser = new DOMParser();
var oDOM = oParser.parseFromString(sMyString, "text\/xml");
// print the name of the root element or error message
dump(oDOM.documentElement.nodeName == "parsererror" ? "error while parsing" : oDOM.documentElement.nodeName);
</pre>
<p><a class="external" href="http://www.van-steenbeek.net/?q=explorer_domparser_parsefromstring">Tutorial su come rendere questo codice cross browser</a> (in inglese)</p>
<h3>Costruire un albero DOM a partire da un file</h3>
<p>Preambolo da scrivere.</p>
<h4>Usando <code>DOMParser</code></h4>
<p>Sezione da scrivere</p>
<h4>Usando <code>XMLHttpRequest</code></h4>
<p>Come già precedentemente accennato, sebbene ciascuna istanza di <code>DOMParser</code> possegga un metodo chiamato <code>parseFromStream()</code>, è più facile utilizzare <a href="/it/XMLHttpRequest" title="it/XMLHttpRequest">XMLHttpRequest</a> per parsare documenti XML in alberi DOM (<code>XMLHttpRequest</code> funziona bene sia in locale che in remoto). Di seguito c'è un codice di esempio che legge e parsa in un albero DOM un file XML locale:</p>
<pre class="brush: js">var oReq = new XMLHttpRequest();
oReq.open("GET", "chrome://passwdmaker/content/people.xml", false);
oReq.send(null);
// print the name of the root element or error message
var oDOM = oReq.responseXML;
dump(oDOM.documentElement.nodeName == "parsererror" ? "error while parsing" : oDOM.documentElement.nodeName);
</pre>
<p>N.B. Il metodo <code>responseXML</code> è sempre un'istanza di <code><a class="external" href="http://xulplanet.com/references/objref/Document.html">Document</a></code> – e di conseguenza un <em>oggetto</em> – a differenza del metodo <code>responseText</code>, che è sempre un <em>valore primario</em> (in questo caso una stringa).</p>
<h4>Usando l'elemento {{ HTMLElement("object") }}.</h4>
<p>Di seguito è presentata un'altra via possibile per parsare un file XML in un albero DOM: usando il tag {{ HTMLElement("object") }}. Prima di lanciare il seguente esempio è necessario creare un file XML valido chiamato <code>purchase_order.xml</code>:</p>
<pre class="brush: html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;XML Data Block Demo&lt;/title&gt;
&lt;script&gt;
function runDemo() {
  var doc = document.getElementById("purchase-order").contentDocument;
  var lineItems = doc.getElementsByTagNameNS("http://example.mozilla.org/PurchaseOrderML", "lineItem");
  var firstPrice = lineItems[0].getElementsByTagNameNS("http://example.mozilla.org/PurchaseOrderML", "price")[0].textContent;
  document.getElementById("output-box").textContent = "The purchase order contains " + lineItems.length + " line items. The price of the first line item is " + firstPrice + ".";
}
&lt;/script&gt;
&lt;/head&gt;
&lt;body onload="runDemo()";&gt;
&lt;object id="purchase-order" data="purchase_order.xml" type="text/xml" style="display: none;"&gt;&lt;/object&gt;
&lt;div id="output-box"&gt;Demo did not run&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Per ulteriori approfondimenti, si rimanda all'articolo: <a href="/it/Usare_le_XML_Data_Islands_in_Mozilla" title="it/Usare_le_XML_Data_Islands_in_Mozilla">Usare le XML Data Islands in Mozilla</a>.</p>
<h2>Decostruire un albero DOM</h2>
<p>Da adesso in poi daremo per scontato il fatto che <em>abbiamo già</em> un albero DOM nella memoria dell'interprete Javascript e che il nostro scopo è invece quello di utilizzare tale istanza di <code><a class="external" href="http://xulplanet.com/references/objref/Document.html">Document</a></code> nei modi più disparati.</p>
<h3>Convertire un documento XML in stringhe di codice sorgente</h3>
<p>L'esempio seguente mostra come ottenere dalla variabile <code>doc</code> — il nostro albero DOM — una stringa contenente l'intero suo codice sorgente:</p>
<pre class="brush: js">var oSerializer = new XMLSerializer();
var sXML = oSerializer.serializeToString(doc);
</pre>
<p>Non è possibile creare un istanza di <code>XMLSerializer</code> (ovvero lanciare: <code>new XMLSerializer()</code>) dall'interno di un componente JS XPCOM o dall'interno di un <a class="internal" href="/it/Moduli_di_codice_JavaScript" title="it/Moduli_di_codice_JavaScript">modulo</a>. Per farlo bisogna lanciare:</p>
<pre class="brush: js">var oSerializer = Components.classes["@mozilla.org/xmlextras/xmlserializer;1"].createInstance(Components.interfaces.nsIDOMSerializer);
var sXML = oSerializer.serializeToString(doc);
</pre>
<h4>Come ottenere stringhe di codice sorgente di facile lettura</h4>
<p>You can <a class="external" href="http://en.wikipedia.org/wiki/Pretty-print">pretty print</a> a DOM tree using <code>XMLSerializer</code> and <a href="/it/E4X" title="it/E4X">E4X</a>. First, create a DOM tree as described in the <a href="/it/Come_creare_un_albero_DOM" title="it/Come_creare_un_albero_DOM">Come creare un albero DOM</a> article. Alternatively, use a DOM tree obtained from <a href="/it/XMLHttpRequest" title="it/XMLHttpRequest">XMLHttpRequest</a>. We assume it's in the <code>doc</code> variable.</p>
<pre class="brush: js">var oSerializer = new XMLSerializer();
var sPrettyXML = XML(oSerializer.serializeToString(doc)).toXMLString();</pre>
<p>Indents are provided with two spaces. You can, of course, use <a href="/it/DOM/treeWalker" title="it/DOM/treeWalker">DOM:treeWalker</a> to write your own, more performant version which also has the advantage that you can customize the indent string to be whatever you like.</p>
<p><strong>Note:</strong> When using the E4X <code>toXMLString</code> method your <strong>CDATA elements will be lost</strong> and only the containing text remains. So using the above method might not be useful if you have CDATA elements in your XML.</p>
<pre class="brush: xml">&lt;content&gt;&lt;![CDATA[This is the content]]&gt;&lt;/content&gt;</pre>
<p>Will become</p>
<pre class="brush: xml">&lt;content&gt;This is the content&lt;/content&gt;</pre>
<h3 id="JXON">Convertire un foglio XML in un albero di oggetti Javascript (JXON)</h3>
<p>JXON (lossless <strong>J</strong>avascript <strong>X</strong>ML <strong>O</strong>bject <strong>N</strong>otation) è un nome generico col quale viene definita la rappresentazione di oggetti Javascript in linguaggio XML. Non esistono veri e propri standard per questa rappresentazione, ma da poco tempo a questa parte cominciano ad affacciarsi in rete alcune convenzioni.</p>
<p>JXON non è un metodo per indirizzare poche parti di un documento XML, dato che il suo punto di forza è la conversione per intero di un albero DOM. Se il nostro scopo è quello di accedere a delle informazioni limitate di un albero DOM, si raccomanda vivamente di <a href="/it/Usare_XPath" title="it/Usare_XPath">Usare XPath</a>.</p>
<p>Ci sono casi invece in cui un documento XML è costruito in maniera tale da avere come principale destinatario del proprio contenuto proprio l'interprete Javascript. In tal caso JXON si presenta come la via migliore.</p>
<p>Per questo tutto questo capitolo immaginiamo di aver parsato, come al solito nella nostra variabile <code>doc</code>, questo documento XML di esempio:</p>
<h5 id="XML_di_esempio">esempio.xml</h5>
<pre class="brush: xml">&lt;?xml version="1.0"?&gt;
&lt;!DOCTYPE catalog SYSTEM "catalog.dtd"&gt;
&lt;catalog&gt;
   &lt;product description="Cardigan Sweater"&gt;
      &lt;catalog_item gender="Men's"&gt;
         &lt;item_number&gt;QWZ5671&lt;/item_number&gt;
         &lt;price&gt;39.95&lt;/price&gt;
         &lt;size description="Medium"&gt;
            &lt;color_swatch image="red_cardigan.jpg"&gt;Red&lt;/color_swatch&gt;
            &lt;color_swatch image="burgundy_cardigan.jpg"&gt;Burgundy&lt;/color_swatch&gt;
         &lt;/size&gt;
         &lt;size description="Large"&gt;
            &lt;color_swatch image="red_cardigan.jpg"&gt;Red&lt;/color_swatch&gt;
            &lt;color_swatch image="burgundy_cardigan.jpg"&gt;Burgundy&lt;/color_swatch&gt;
         &lt;/size&gt;
      &lt;/catalog_item&gt;
      &lt;catalog_item gender="Women's"&gt;
         &lt;item_number&gt;RRX9856&lt;/item_number&gt;
         &lt;discount_until&gt;Dec 25, 1995&lt;/discount_until&gt;
         &lt;price&gt;42.50&lt;/price&gt;
         &lt;size description="Medium"&gt;
            &lt;color_swatch image="black_cardigan.jpg"&gt;Black&lt;/color_swatch&gt;
         &lt;/size&gt;
      &lt;/catalog_item&gt;
   &lt;/product&gt;
   &lt;script type="text/javascript"&gt;&lt;![CDATA[function matchwo(a,b) {
    if (a &lt; b &amp;&amp; a &lt; 0) { return 1; }
    else { return 0; }
}]]&gt;&lt;/script&gt;
&lt;/catalog&gt;
</pre>
<p>Adesso proviamo a ottenere una rappresentazione della variabile <code>doc</code> — l'albero DOM — attraverso un albero di oggetti Javascript (you can read more about <a href="/en/JavaScript/Guide/Working_with_Objects" title="Working with Objects – MDC">working with Objects</a> and <a href="/en/Introduction_to_Object-Oriented_JavaScript" title="Introduction to Object-Oriented JavaScript – MDC">how Javascript is Object-Oriented</a>). Per far ciò possiamo utilizzare diversi algoritmi di conversione.</p>
<p>Per semplicità gli algoritmi qui proposti (si veda: <a href="#Algoritmo_JXON_1" title="Vai all'algoritmo JXON #1">#1</a>, <a href="#Algoritmo_JXON_2" title="Vai all'algoritmo JXON #2">#2</a>, <a href="#Algoritmo_JXON_3" title="Vai all'algoritmo JXON #3">#3</a>, <a href="#Algoritmo_JXON_4" title="Vai all'algoritmo JXON #4">#4</a>) prenderanno in considerazione solamente i seguenti tipi di nodi e i loro attributi:</p>
<ol> <li><code>Document</code> (solo come argomento della funzione),</li> <li><code>DocumentFragment</code> (solo come argomento della funzione),</li> <li><code>Element</code>,</li> <li><code>Text</code> (mai come argomento della funzione),</li> <li><code>CDATASection</code> (mai come argomento della funzione).</li>
</ol>
<p>Si tratta di un buon compromesso per un uso Javascript, dacché la gran parte delle informazioni di un documento XML è contenuta in questo tipo di nodi. Ogni altra informazione (come processing instructions, xml schemas, commenti, etc.) andrà persa. Allo scopo di evitare conflitti, la lettura dei nomi dei nodi e dei loro attributi è <em>case insensitive</em> (resa sempre in <em>minuscolo</em>) e di conseguenza le proprietà locali dell'albero di oggetti così ottenuto aggiunte via JavaScript dovranno avere un qualche tipo di lettera maiuscola al loro interno, per evitare di sovrascrivere le proprietà ottenute dal foglio XML, come si può vedere di seguito. I seguenti algoritmi sono liberamente basati sulla <a href="#Convenzione_di_Parker" title="La Convenzione di Parker">Convenzione di Parker, versione 0.4</a>, che prevede il riconoscimento del <code>typeof</code> del contenuto di testo di ogni singolo nodo letto.</p>
<h4 id="Algoritmo_JXON_1">Algoritmo #1: una via prolissa</h4>
<p>Questo semplice costruttore ricorsivo converte un albero DOM XML in un albero di oggetti Javascript. Il contenuto di testo di ogni nodo è salvato all'interno della proprietà <code>keyValue</code>, mentre i <code>nodeAttributes</code>, se esistono, sono annidati come proprietà dell'oggetto-figlio <code>keyAttributes</code>. L'argomento del costruttore può essere l'intero <code>Document</code>, un <code>DocumentFragment</code> o, più semplicemente, un nodo di tipo <code>Element</code> di esso.</p>
<pre class="brush: js">function buildValue(sValue) {
  if (/^\s*$/.test(sValue)) { return null; }
  if (/^(true|false)$/i.test(sValue)) { return sValue.toLowerCase() === "true"; }
  if (isFinite(sValue)) { return parseFloat(sValue); }
  if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
  return sValue;
}

function XMLData (oXMLParent) {
  var nAttrLen = 0, nLength = 0, sCollectedTxt = "";
  // children
  if (oXMLParent.hasChildNodes()) {
    for (var oItChild, sItKey, sItVal, nChildId = 0; nChildId &lt; oXMLParent.childNodes.length; nChildId++) {
      oItChild = oXMLParent.childNodes.item(nChildId);
      if ((oItChild.nodeType - 1 | 1) === 3) { sCollectedTxt += oItChild.nodeType === 3 ? oItChild.nodeValue.replace(/^\s+|\s+$/g, "") : oItChild.nodeValue; } // nodeType is "Text" (3) or "CDATASection" (4)
      else if (oItChild.nodeType === 1 &amp;&amp; !oItChild.prefix) { // nodeType is "Element" (1)
        sItKey = oItChild.nodeName.toLowerCase();
        sItVal = new XMLData(oItChild);
        if (this.hasOwnProperty(sItKey)) {
          if (this[sItKey].constructor !== Array) { this[sItKey] = [this[sItKey]]; }
          this[sItKey].push(sItVal);
        } else { this[sItKey] = sItVal; nLength++; }
      }
    }
    this.keyValue = buildValue(sCollectedTxt);
  } else { this.keyValue = null; }
  // node attributes
  if (oXMLParent.hasAttributes()) {
    var oItAttr;
    this.keyAttributes = {};
    for (nAttrLen; nAttrLen &lt; oXMLParent.attributes.length; nAttrLen++) {
      oItAttr = oXMLParent.attributes.item(nAttrLen);
      this.keyAttributes[oItAttr.nodeName.toLowerCase()] = buildValue(oItAttr.nodeValue);
    }
  }
  // optional properties and methods; you could safely adjoust/remove them...
  this.keyLength = nLength;
  this.attributesLength = nAttrLen;
  // this.DOMNode = oXMLParent;
  this.valueOf = function() { return this.keyValue; };
  this.toString = function() { return String(this.keyValue); };
  this.getItem = function(nItem) {
    if (nLength === 0) { return null; }
    var iItem = 0;
    for (var sKeyName in this) { if (iItem === nItem) { return this[sKeyName]; } iItem++; }
    return null;
  };
  this.getAttribute = function(nAttrib) {
    if (nAttrLen === 0 || nAttrib + 1 &gt; nAttrLen) { return null; }
    var nItAttr = 0;
    for (var sAttrName in this.keyAttributes) { if (nItAttr === nAttrib) { return this.keyAttributes[sAttrName]; } nItAttr++; }
    return null;
  };
  this.hasChildren = function() { return this.keyLength &gt; 0; };
}

var myObject = new XMLData(doc);
// abbiamo ottenuto il nostro albero di oggetti Javascript! provare per credere: alert(JSON.stringify(myObject));
</pre>
<p>Con questo algoritmo <a href="#XML_di_esempio" title="Go to the sample XML document">il nostro esempio</a> diventerà:</p>
<pre class="brush: js">{
  "catalog": {
    "product": {
      "catalog_item": [{
        "item_number": {
          "keyValue": "QWZ5671",
          "keyLength": 0,
          "attributesLength": 0
        },
        "price": {
          "keyValue": 39.95,
          "keyLength": 0,
          "attributesLength": 0
        },
        "size": [{
          "color_swatch": [{
            "keyValue": "Red",
            "keyAttributes": {
              "image": "red_cardigan.jpg"
            },
            "keyLength": 0,
            "attributesLength": 1
          }, {
            "keyValue": "Burgundy",
            "keyAttributes": {
              "image": "burgundy_cardigan.jpg"
            },
            "keyLength": 0,
            "attributesLength": 1
          }],
          "keyValue": null,
          "keyAttributes": {
            "description": "Medium"
          },
          "keyLength": 1,
          "attributesLength": 1
        }, {
          "color_swatch": [{
            "keyValue": "Red",
            "keyAttributes": {
              "image": "red_cardigan.jpg"
            },
            "keyLength": 0,
            "attributesLength": 1
          }, {
            "keyValue": "Burgundy",
            "keyAttributes": {
              "image": "burgundy_cardigan.jpg"
            },
            "keyLength": 0,
            "attributesLength": 1
          }],
          "keyValue": null,
          "keyAttributes": {
            "description": "Large"
          },
          "keyLength": 1,
          "attributesLength": 1
        }],
        "keyValue": null,
        "keyAttributes": {
          "gender": "Men's"
        },
        "keyLength": 3,
        "attributesLength": 1
      }, {
        "item_number": {
          "keyValue": "RRX9856",
          "keyLength": 0,
          "attributesLength": 0
        },
        "discount_until": {
          "keyValue": new Date(1995, 11, 25),
          "keyLength": 0,
          "attributesLength": 0
        },
        "price": {
          "keyValue": 42.5,
          "keyLength": 0,
          "attributesLength": 0
        },
        "size": {
          "color_swatch": {
            "keyValue": "Black",
            "keyAttributes": {
              "image": "black_cardigan.jpg"
            },
            "keyLength": 0,
            "attributesLength": 1
          },
          "keyValue": null,
          "keyAttributes": {
            "description": "Medium"
          },
          "keyLength": 1,
          "attributesLength": 1
        },
        "keyValue": null,
        "keyAttributes": {
          "gender": "Women's"
        },
        "keyLength": 4,
        "attributesLength": 1
      }],
      "keyValue": null,
      "keyAttributes": {
        "description": "Cardigan Sweater"
      },
      "keyLength": 1,
      "attributesLength": 1
    },
    "script": {
      "keyValue": "function matchwo(a,b) {\n  if (a &lt; b &amp;&amp; a &lt; 0) { return 1; }\n  else { return 0; }\n}",
      "keyAttributes": {
        "type": "text/javascript"
      },
      "keyLength": 0,
      "attributesLength": 1
    },
    "keyValue": null,
    "keyLength": 2,
    "attributesLength": 0
  },
  "keyValue": null,
  "keyLength": 1,
  "attributesLength": 0
}
</pre>
<p>È un approccio raccomandato nel caso in cui ci sia completamente ignota la struttura del documento XML che andremo a leggere.</p>
<h4 id="Algoritmo_JXON_2">Algoritmo #2: una via un po' meno prolissa</h4>
<p>Quello che segue è un altro, più semplice, metodo di conversione. Dove i <code>nodeAttributes</code> sono annidati nello stesso oggetto contenente la trascrizione dei nodi figli sebbene, a differenza di quelli, questi siano contrassegnati dal prefisso “@”. Come sopra, il contenuto di testo di ciascun nodo è affidato alla proprietà <code>keyValue</code>. L'argomento del costruttore può essere l'intero <code>Document</code>, un <code>DocumentFragment</code> o, più semplicemente, un nodo di tipo <code>Element</code> di esso.</p>
<pre class="brush: js">function buildValue(sValue) {
  if (/^\s*$/.test(sValue)) { return null; }
  if (/^(true|false)$/i.test(sValue)) { return sValue.toLowerCase() === "true"; }
  if (isFinite(sValue)) { return parseFloat(sValue); }
  if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
  return sValue;
}

function XMLData (oXMLParent) {
  if (oXMLParent.hasChildNodes()) {
    var sCollectedTxt = "";
    for (var oItChild, sItKey, sItVal, nChildId = 0; nChildId &lt; oXMLParent.childNodes.length; nChildId++) {
      oItChild = oXMLParent.childNodes.item(nChildId);
      if ((oItChild.nodeType - 1 | 1) === 3) { sCollectedTxt += oItChild.nodeType === 3 ? oItChild.nodeValue.replace(/^\s+|\s+$/g, "") : oItChild.nodeValue; }
      else if (oItChild.nodeType === 1 &amp;&amp; !oItChild.prefix) {
        sItKey = oItChild.nodeName.toLowerCase();
        sItVal = new XMLData(oItChild);
        if (this.hasOwnProperty(sItKey)) {
          if (this[sItKey].constructor !== Array) { this[sItKey] = [this[sItKey]]; }
          this[sItKey].push(sItVal);
        } else { this[sItKey] = sItVal; }
      }
    }
    if (sCollectedTxt) { this.keyValue = buildValue(sCollectedTxt); }
  }
  if (oXMLParent.hasAttributes()) {
    var oItAttr;
    for (var iAttrId = 0; iAttrId &lt; oXMLParent.attributes.length; iAttrId++) {
      oItAttr = oXMLParent.attributes.item(iAttrId);
      this["@" + oItAttr.nodeName.toLowerCase()] = buildValue(oItAttr.nodeValue);
    }
  }
}

var myObject = new XMLData(doc);
// abbiamo ottenuto il nostro albero di oggetti Javascript! provare per credere: alert(JSON.stringify(myObject));
</pre>
<p>Con questo algoritmo <a href="#XML_di_esempio" title="Go to the sample XML document">il nostro esempio</a> diventerà:</p>
<pre class="brush: js">{
  "catalog": {
    "product": {
      "catalog_item": [{
        "item_number": {
          "keyValue": "QWZ5671"
        },
        "price": {
          "keyValue": 39.95
        },
        "size": [{
          "color_swatch": [{
            "keyValue": "Red",
            "@image": "red_cardigan.jpg"
          }, {
            "keyValue": "Burgundy",
            "@image": "burgundy_cardigan.jpg"
          }],
          "@description": "Medium"
        }, {
          "color_swatch": [{
            "keyValue": "Red",
            "@image": "red_cardigan.jpg"
          }, {
            "keyValue": "Burgundy",
            "@image": "burgundy_cardigan.jpg"
          }],
          "@description": "Large"
        }],
        "@gender": "Men's"
      }, {
        "item_number": {
          "keyValue": "RRX9856"
        },
        "discount_until": {
          "keyValue": new Date(1995, 11, 25)
        },
        "price": {
          "keyValue": 42.5
        },
        "size": {
          "color_swatch": {
            "keyValue": "Black",
            "@image": "black_cardigan.jpg"
          },
          "@description": "Medium"
        },
        "@gender": "Women's"
      }],
      "@description": "Cardigan Sweater"
    },
    "script": {
      "keyValue": "function matchwo(a,b) {\n  if (a &lt; b &amp;&amp; a &lt; 0) { return 1; }\n  else { return 0; }\n}",
      "@type": "text/javascript"
    }
  }
}
</pre>
<p>È un approccio possibile nel caso in cui ci sia parzialmente nota la struttura del documento XML che andremo a leggere.</p>
<h4 id="Algoritmo_JXON_3">Algoritmo #3: una via sintetica</h4>
<p>Ora proveremo un altro metodo di conversione. Questo algoritmo è quello che si avvicina di più alla <a href="#Convenzione_di_Parker" title="La Convenzione di Parker">Convenzione di Parker</a>. Esso è molto simile al precedente, eccetto che per il fatto che i nodi che non contengono alcun nodo-figlio di tipo <code>Element</code>, ma solo nodi-figli di tipo <code>Text</code> e/o <code>CDATASection</code>, non sono rappresentati da oggetti, ma direttamente da booleani, numeri, stringhe o istanze del costruttore <code>Date</code> (si veda la <a href="#Convenzione_di_Parker" title="La Convenzione di Parker">Convenzione di Parker</a>). La rappresentazione dei nodi completamente vuoti invece (cioè che non contengono né nodi di tipo <code>Element</code>, né nodi di tipo <code>Text</code>, né nodi di tipo <code>CDATASection</code>) avranno come valore predefinito <code>true</code>. Inoltre questa volta non si è usato un costruttore, ma una semplice funzione. L'argomento della funzione può essere l'intero <code>Document</code>, un <code>DocumentFragment</code> o, più semplicemente, un nodo di tipo <code>Element</code> di esso.</p>
<p>In molti casi questo rappresenta il metodo di conversione più pratico.</p>
<pre class="brush: js">function buildValue(sValue) {
  if (/^\s*$/.test(sValue)) { return null; }
  if (/^(true|false)$/i.test(sValue)) { return sValue.toLowerCase() === "true"; }
  if (isFinite(sValue)) { return parseFloat(sValue); }
  if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
  return sValue;
}

function getXMLData (oXMLParent) {
  var vResult = /* put here the default value for empty nodes! */ true, nLength = 0, sCollectedTxt = "";
  if (oXMLParent.hasAttributes()) {
    vResult = {};
    for (nLength; nLength &lt; oXMLParent.attributes.length; nLength++) {
      oItAttr = oXMLParent.attributes.item(nLength);
      vResult["@" + oItAttr.nodeName.toLowerCase()] = buildValue(oItAttr.nodeValue.replace(/^\s+|\s+$/g, ""));
    }
  }
  if (oXMLParent.hasChildNodes()) {
    for (var oItChild, sItKey, sItVal, nChildId = 0; nChildId &lt; oXMLParent.childNodes.length; nChildId++) {
      oItChild = oXMLParent.childNodes.item(nChildId);
      if (oItChild.nodeType === 4) { sCollectedTxt += oItChild.nodeValue; } /* nodeType is "CDATASection" (4) */
      else if (oItChild.nodeType === 3) { sCollectedTxt += oItChild.nodeValue.replace(/^\s+|\s+$/g, ""); } /* nodeType is "Text" (3) */
      else if (oItChild.nodeType === 1 &amp;&amp; !oItChild.prefix) { /* nodeType is "Element" (1) */
         if (nLength === 0) { vResult = {}; }
        sItKey = oItChild.nodeName.toLowerCase();
        sItVal = getXMLData(oItChild);
        if (vResult.hasOwnProperty(sItKey)) {
          if (vResult[sItKey].constructor !== Array) { vResult[sItKey] = [vResult[sItKey]]; }
          vResult[sItKey].push(sItVal);
        } else { vResult[sItKey] = sItVal; nLength++; }
      }
     }
  }
  if (sCollectedTxt) { nLength &gt; 0 ? vResult.keyValue = buildValue(sCollectedTxt) : vResult = buildValue(sCollectedTxt); }
  /* if (nLength &gt; 0) { Object.freeze(vResult); } */
  return vResult;
}

var myObject = getXMLData(doc);
// abbiamo ottenuto il nostro albero di oggetti Javascript! provare per credere: alert(JSON.stringify(myObject));
</pre>
<div class="note"><strong>Nota:</strong> Se si vuole <em>congelare</em> l'intero oggetto (a causa della natura "statica" di un documento XML), decommentare la stringa: <code>/* if (nLength &gt; 0) { Object.freeze(vResult); } */</code>. Il metodo <code><a href="/it/Javascript/Glossario/Oggetti_globali/Object/freeze" title="/it/Javascript/Glossario/Oggetti_globali/Object/freeze">Object.freeze</a></code> vieta l'aggiunta di nuove proprietà e la rimozione delle proprietà esistenti, congelando la loro enumerabilità, la loro configurabilità o la loro scrivibilità. In sostanza l'oggetto è reso effettivamente immutabile.</div>
<p>Con questo algoritmo <a href="#XML_di_esempio" title="Go to the sample XML document">il nostro esempio</a> diventerà:</p>
<pre class="brush: js">{
  "catalog": {
    "product": {
      "@description": "Cardigan Sweater",
      "catalog_item": [{
        "@gender": "Men's",
        "item_number": "QWZ5671",
        "price": 39.95,
        "size": [{
          "@description": "Medium",
          "color_swatch": [{
            "@image": "red_cardigan.jpg",
            "keyValue": "Red"
          }, {
            "@image": "burgundy_cardigan.jpg",
            "keyValue": "Burgundy"
          }]
        }, {
          "@description": "Large",
          "color_swatch": [{
            "@image": "red_cardigan.jpg",
            "keyValue": "Red"
          }, {
            "@image": "burgundy_cardigan.jpg",
            "keyValue": "Burgundy"
          }]
        }]
      }, {
        "@gender": "Women's",
        "item_number": "RRX9856",
        "discount_until": new Date(1995, 11, 25),
        "price": 42.5,
        "size": {
          "@description": "Medium",
          "color_swatch": {
            "@image": "black_cardigan.jpg",
            "keyValue": "Black"
          }
        }
      }]
    },
    "script": {
      "@type": "text/javascript",
      "keyValue": "function matchwo(a,b) {\n  if (a &lt; b &amp;&amp; a &lt; 0) { return 1; }\n  else { return 0; }\n}"
    }
  }
}
</pre>
<p>È un approccio raccomandato nel caso in cui ci sia nota la struttura del documento XML che andremo a leggere.</p>
<h4 id="Algoritmo_JXON_4">Algoritmo #4: una via davvero minimalista</h4>
<p>La seguente rappresenta un'altra possibile via di conversione. Anch'essa è molto vicina alla <a href="#Convenzione_di_Parker" title="La Convenzione di Parker">Convenzione di Parker</a>. Con questo algoritmo la rappresentazione dei nodi di tipo <code>Element</code> che contengono a loro volta sullo stesso piano nodi-figli di tipo <code>Element</code> insieme con nodi-figli di tipo <code>Text</code> e/o di tipo <code>CDATASection</code> è resa per mezzo di istanze dei costruttori <code>Boolean</code>, <code>Number</code>, <code>String</code>, e <code>Date</code>. Di conseguenza la trascrizione di ogni nodo-figlio sarà annidata in oggetti di questo tipo.</p>
<p>Per esempio;</p>
<pre class="brush: xml">&lt;employee type="usher"&gt;John Smith&lt;/employee&gt;
&lt;manager&gt;Lisa Carlucci&lt;/manager&gt;
</pre>
<p>diventerà</p>
<pre class="brush: js">var myObject = {
  "employee": new String("John Smith"),
  "manager": "Lisa Carlucci"
};

myObject.employee["@type"] = "usher";

// test

alert(myObject.manager); // "Lisa Carlucci"
alert(myObject.employee["@type"]); // "usher"
alert(myObject.employee); // "John Smith"
</pre>
<p>Come per il terzo algoritmo, i nodi che non contengono alcun nodo-figlio di tipo <code>Element</code>, ma solo nodi-figli di tipo <code>Text</code> e/o <code>CDATASection</code>, non sono rappresentati da oggetti, ma direttamente da booleani, numeri, stringhe (valori primitivi) o istanze del costruttore <code>Date</code> (si veda la <a href="#Convenzione_di_Parker" title="La Convenzione di Parker">Convenzione di Parker</a>). Come per il terzo algoritmo, non si è usato un costruttore, ma una semplice funzione. L'argomento della funzione può essere l'intero <code>Document</code>, un <code>DocumentFragment</code> o, più semplicemente, un nodo di tipo <code>Element</code> di esso.</p>
<pre class="brush: js">function buildValue (sValue) {
  if (/^\s*$/.test(sValue)) { return null; }
  if (/^(true|false)$/i.test(sValue)) { return sValue.toLowerCase() === "true"; }
  if (isFinite(sValue)) { return parseFloat(sValue); }
  if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
  return sValue;
}

function objectify (vValue) {
  if (vValue === null) {
    return new (function() {
      this.toString = function() { return "null"; }
      this.valueOf = function() { return null; }
    })();
  }
  return vValue instanceof Object ? vValue : new vValue.constructor(vValue);
}

var aTmpEls = []; // loaded element nodes cache

function getXMLData (oXMLParent) {
  var  sItKey, sItVal, vResult, nLength = 0, nLevelStart = aTmpEls.length,
       nChildren = oXMLParent.hasChildNodes() ? oXMLParent.childNodes.length : 0, sCollectedTxt = "";

  for (var oItChild, nChildId = 0; nChildId &lt; nChildren; nChildId++) {
    oItChild = oXMLParent.childNodes.item(nChildId);
    if (oItChild.nodeType === 4) { sCollectedTxt += oItChild.nodeValue; } /* nodeType is "CDATASection" (4) */
    else if (oItChild.nodeType === 3) { sCollectedTxt += oItChild.nodeValue.replace(/^\s+|\s+$/g, ""); } /* nodeType is "Text" (3) */
    else if (oItChild.nodeType === 1 &amp;&amp; !oItChild.prefix) { aTmpEls.push(oItChild); } /* nodeType is "Element" (1) */
  }

  var nLevelEnd = aTmpEls.length, vBuiltVal = buildValue(sCollectedTxt);

  if (oXMLParent.hasAttributes()) {
    vResult = objectify(vBuiltVal);
    for (nLength; nLength &lt; oXMLParent.attributes.length; nLength++) {
      oItAttr = oXMLParent.attributes.item(nLength);
      vResult["@" + oItAttr.nodeName.toLowerCase()] = buildValue(oItAttr.nodeValue.replace(/^\s+|\s+$/g, ""));
    }
  } else if (nLevelEnd &gt; nLevelStart) { vResult = objectify(vBuiltVal); }

  for (var nElId = nLevelStart; nElId &lt; nLevelEnd; nElId++) {
    sItKey = aTmpEls[nElId].nodeName.toLowerCase();
    sItVal = getXMLData(aTmpEls[nElId]);
    if (vResult.hasOwnProperty(sItKey)) {
    if (vResult[sItKey].constructor !== Array) { vResult[sItKey] = [vResult[sItKey]]; }
      vResult[sItKey].push(sItVal);
    } else { vResult[sItKey] = sItVal; nLength++; }
  }

  aTmpEls.length = nLevelStart;

  if (nLength === 0) { vResult = sCollectedTxt ? vBuiltVal : /* put here the default value for empty nodes: */ true; }
  /* else { Object.freeze(vResult); } */

  return vResult;
}

var myObject = getXMLData(doc);
alert(myObject.catalog.product.catalog_item[1].size.color_swatch["@image"]); // "black_cardigan.jpg"
alert(myObject.catalog.product.catalog_item[1].size.color_swatch); // "Black" !</pre>
<div class="note"><strong>Nota:</strong> Se si vuole <em>congelare</em> l'intero oggetto (a causa della natura "statica" di un documento XML), decommentare la stringa: <code>/* else { Object.freeze(vResult); } */</code> . Il metodo <code><a href="/it/Javascript/Glossario/Oggetti_globali/Object/freeze" title="/it/Javascript/Glossario/Oggetti_globali/Object/freeze">Object.freeze</a></code> vieta l'aggiunta di nuove proprietà e la rimozione delle proprietà esistenti, congelando la loro enumerabilità, la loro configurabilità o la loro scrivibilità. In sostanza l'oggetto è reso effettivamente immutabile.</div>
<p>È un approccio possibile nel caso in cui ci sia nota la struttura del documento XML che andremo a leggere.</p>
<h4 id="Convenzione_di_Parker">La Convenzione di Parker</h4>
<p>Le funzioni precedentemente elencate per la conversione di un documento XML in JSON (spesso chiamate «algoritmi JXON») sono più o meno liberamente fondate sulla Convenzione di Parker. È chiamata “Convenzione di Parker”, in opposizione alla “Convenzione di BadgerFish”, dal fumetto di Cuadrado <em>Parker &amp; Badger</em>. Si veda anche: <a class="external" href="http://badgerfish.ning.com/" title="BadgerFish convention">Convenzione di BadgerFish</a>.</p>
<p>La seguente è una traduzione dall'inglese del paper originale della Convenzione di Parker (versione 0.4), dalla pagina “<a class="external" href="http://code.google.com/p/xml2json-xslt/wiki/TransformingRules" title="TransformingRules – xml2json-xslt">TransformingRules</a>” del sito del progetto <a class="external" href="http://code.google.com/p/xml2json-xslt/" title="xml2json-xslt project">xml2json-xslt</a>.</p>
<p>Questa convenzione è stata scritta per regolamentare la conversione in <a href="/it/JSON" title="/it/JSON">JSON</a> da parte di <a href="/it/XSLT" title="/it/XSLT">XSLT</a>, di conseguenza alcune parti di essa sono futili per Javascript.</p>
<h5>Conversione in JSON</h5>
<ol> <li> <p>The root element will be absorbed, for there is only one:</p> <pre class="brush: xml">&lt;root&gt;test&lt;/root&gt;</pre> <p>becomes</p> <pre class="brush: js">"test"
</pre> </li> <li> <p>Element names become object properties:</p> <pre class="brush: xml">&lt;root&gt;&lt;name&gt;Xml&lt;/name&gt;&lt;encoding&gt;ASCII&lt;/encoding&gt;&lt;/root&gt;</pre> <p>becomes</p> <pre class="brush: js">{
  "name": "Xml",
  "encoding": "ASCII"
}
</pre> </li> <li> <p>Numbers are recognized (integers and decimals):</p> <pre class="brush: xml">&lt;root&gt;&lt;age&gt;12&lt;/age&gt;&lt;height&gt;1.73&lt;/height&gt;&lt;/root&gt;</pre> <p>becomes</p> <pre class="brush: js">{
  "age": 12,
  "height": 1.73
}
</pre> </li> <li> <p>Booleans are recognized case insensitive:</p> <pre class="brush: xml">&lt;root&gt;&lt;checked&gt;True&lt;/checked&gt;&lt;answer&gt;FALSE&lt;/answer&gt;&lt;/root&gt;</pre> <p>becomes</p> <pre class="brush: js">{
  "checked": true,
  "answer": false
}
</pre> </li> <li> <p>Strings are escaped:</p> <pre class="brush: xml">&lt;root&gt;Quote: &amp;quot; New-line:
&lt;/root&gt;
</pre> <p>becomes</p> <pre class="brush: js">"Quote: \" New-line:\n"</pre> </li> <li> <p>Empty elements will become null:</p> <pre class="brush: xml">&lt;root&gt;&lt;nil/&gt;&lt;empty&gt;&lt;/empty&gt;&lt;/root&gt;</pre> <p>becomes</p> <pre class="brush: js">{
  "nil": null,
  "empty": null
}
</pre> </li> <li> <p>If all sibling elements have the same name, they become an array</p> <pre class="brush: xml">&lt;root&gt;&lt;item&gt;1&lt;/item&gt;&lt;item&gt;2&lt;/item&gt;&lt;item&gt;three&lt;/item&gt;&lt;/root&gt;
</pre> <p>becomes</p> <pre class="brush: js">[1, 2, "three"]
</pre> </li> <li> <p>Mixed mode text-nodes, comments and attributes get absorbed:</p> <pre class="brush: xml">&lt;root version="1.0"&gt;testing&lt;!--comment--&gt;&lt;elementtest="true"&gt;1&lt;/element&gt;&lt;/root&gt;
</pre> <p>becomes</p> <pre class="brush: js">{ "element": true }
</pre> </li> <li> <p>Namespaces get absorbed, and prefixes will just be part of the property name:</p> <pre class="brush: xml">&lt;root xmlns:ding="http://zanstra.com/ding"&gt;&lt;ding:dong&gt;binnen&lt;/ding:dong&gt;&lt;/root&gt;
</pre> <p>becomes</p> <pre class="brush: js">{ "ding:dong" : "binnen" }
</pre> </li>
</ol>
<div class="note"><strong>Note:</strong> Our algorithms comply with the points 2, 3, 4 and 7. The third and the fourth algorithm comply also with the point 6 (but <code>true</code> instead of <code>null</code>). The point 5 is automatically managed by the Javascript method <code><a href="/it/Javascript/Glossario/Oggetti_globali/JSON/stringify" title="/it/Javascript/Glossario/Oggetti_globali/JSON/stringify">JSON.stringify</a></code>.</div>
<h5>Appendice Javascript</h5>
<p>All the same as the JSON translation, but with these extra's:</p>
<ol> <li> <p>Property names are only escaped when necessary</p> <pre class="brush: xml">&lt;root&gt;&lt;while&gt;true&lt;/while&gt;&lt;wend&gt;false&lt;/wend&gt;&lt;only-if/&gt;&lt;/root&gt;</pre> <p>becomes</p> <pre class="brush: js">{
  "while": true,
  wend: false,
  "only-if": null
}
</pre> </li> <li> <p>Within a string, closing elements "&lt;/" are escaped as "&lt;\/"</p> <pre class="brush: xml">&lt;root&gt;&lt;![CDATA[&lt;script&gt;alert("YES");&lt;/script&gt;]]&gt;&lt;/root&gt;</pre> <p>becomes</p> <pre class="brush: js">{ script: "&lt;script&gt;alert(\"YES\")&lt;\/script&gt;" }
</pre> </li> <li> <p>Dates are created as <code>new Date()</code> objects</p> <pre class="brush: xml">&lt;root&gt;2006-12-25&lt;/root&gt;</pre> <p>becomes</p> <pre class="brush: js">new Date(2006, 12 - 1, 25)
</pre> </li> <li> <p>Attributes and comments are shown as comments (for testing-purposes):</p> <pre class="brush: xml">&lt;!--testing--&gt;&lt;root&gt;&lt;test version="1.0"&gt;123&lt;/test&gt;&lt;/root&gt;
</pre> <p>becomes</p> <pre class="brush: js">/* testing */ { test /* @version = "1.0" */ : 123}
</pre> </li> <li> <p>A bit of indentation is done, to keep things ledgible</p> </li>
</ol>
<div class="note"><strong>Note:</strong> Our algorithms comply with the point 3 (but without month decrease). The points 1 and 2 are automatically managed by the Javascript method <code><a href="/it/Javascript/Glossario/Oggetti_globali/JSON/stringify" title="/it/Javascript/Glossario/Oggetti_globali/JSON/stringify">JSON.stringify</a></code>.</div>
<h4>In sintesi</h4>
<p>Let's take <a href="#Algoritmo_JXON_3" title="Vai all'algoritmo JXON #3">the third algorithm</a> as the most representative JXON parsing algorithm. A single structured XML <code>Element</code> might have eight different configurations:</p>
<ol> <li>an empty element,</li> <li>an element with pure text content,</li> <li>an empty element with attributes,</li> <li>an element with text content and attributes,</li> <li>an element containing elements with different names,</li> <li>an element containing elements with identical names,</li> <li>an element containing elements and contiguous text,</li> <li>an element containing elements and non contiguous text.</li>
</ol>
<p>The following table shows the corresponding conversion patterns between XML and JSON according to the <a href="#Algoritmo_JXON_3" title="Vai all'algoritmo JXON #3">third algorithm</a>.</p>
<table> <thead> <tr> <th style="background: #faf9e2; color: #5d5636; text-align: center;"><strong>Case</strong></th> <th style="background: #faf9e2; color: #5d5636; text-align: center;"><strong>XML</strong></th> <th style="background: #faf9e2; color: #5d5636; text-align: center;"><strong>JSON</strong></th> <th style="background: #faf9e2; color: #5d5636; text-align: center;"><strong>Javascript access</strong></th> </tr> </thead> <tbody> <tr> <td style="background: #f6f6f6;">1</td> <td style="background: #f6f6f6;"><code>&lt;animal/&gt;</code></td> <td style="background: #f6f6f6;"><code>"animal": true</code></td> <td style="background: #f6f6f6;"><code>myObject.animal</code></td> </tr> <tr> <td style="background: #e7e5dc;">2</td> <td style="background: #e7e5dc;"><code>&lt;animal&gt;text&lt;/animal&gt;</code></td> <td style="background: #e7e5dc;"><code>"animal": "text"</code></td> <td style="background: #e7e5dc;"><code>myObject.animal</code></td> </tr> <tr> <td style="background: #f6f6f6;">3</td> <td style="background: #f6f6f6;"><code>&lt;animal name="value" /&gt;</code></td> <td style="background: #f6f6f6;"><code>"animal": {"@name": "value"}</code></td> <td style="background: #f6f6f6;"><code>myObject.animal["@name"]</code></td> </tr> <tr> <td style="background: #e7e5dc;">4</td> <td style="background: #e7e5dc;"><code>&lt;animal name="value"&gt;text&lt;/animal&gt;</code></td> <td style="background: #e7e5dc;"><code>"animal": { "@name": "value", "keyValue": "text" }</code></td> <td style="background: #e7e5dc;"><code>myObject.animal["@name"]</code>, <code>myObject.animal.keyValue</code></td> </tr> <tr> <td style="background: #f6f6f6;">5</td> <td style="background: #f6f6f6;"><code>&lt;animal&gt; &lt;dog&gt;Charlie&lt;/dog&gt; &lt;cat&gt;Deka&lt;/cat&gt; &lt;/animal&gt;</code></td> <td style="background: #f6f6f6;"><code>"animal": { "dog": "Charlie", "cat": "Deka" }</code></td> <td style="background: #f6f6f6;"><code>myObject.animal.dog</code>, <code>myObject.animal.cat</code></td> </tr> <tr> <td style="background: #e7e5dc;">6</td> <td style="background: #e7e5dc;"><code>&lt;animal&gt; &lt;dog&gt;Charlie&lt;/dog&gt; &lt;dog&gt;Mad Max&lt;/dog&gt; &lt;/animal&gt;</code></td> <td style="background: #e7e5dc;"><code>"animal": { "dog": ["Charlie", "Mad Max"] }</code></td> <td style="background: #e7e5dc;"><code>myObject.animal.dog[0]</code>, <code>myObject.animal.dog[1]</code></td> </tr> <tr> <td style="background: #f6f6f6;">7</td> <td style="background: #f6f6f6;"><code>&lt;animal&gt; in my house &lt;dog&gt;Charlie&lt;/dog&gt; &lt;/animal&gt;</code></td> <td style="background: #f6f6f6;"><code>"animal": { "keyValue": "in my house", "dog": "Charlie" }</code></td> <td style="background: #f6f6f6;"><code>myObject.animal.keyValue</code>, <code>myObject.animal.dog</code></td> </tr> <tr> <td style="background: #e7e5dc;">8</td> <td style="background: #e7e5dc;"><code>&lt;animal&gt; in my ho &lt;dog&gt;Charlie&lt;/dog&gt; use &lt;/animal&gt;</code></td> <td style="background: #e7e5dc;"><code>"animal": { "keyValue": "in my house", "dog": "Charlie" }</code></td> <td style="background: #e7e5dc;"><code>myObject.animal.keyValue</code>, <code>myObject.animal.dog</code></td> </tr> </tbody>
</table>
<h4>Considerazioni sul codice</h4>
<p>In these examples we chose to use a property named <code>keyValue</code> for the text content. The lack of standars for XML to JSON conversion leads developers to choose several property names for the text content of XML <code>Element</code> nodes which contain also other child nodes. Sometimes it is used a property called <code>$</code>. Other times it is used a property called <code>#text</code>. In the algorithms proposed here you can easily change this name, depending on your needs.</p>
<p>The choice of using a <code>true</code> value instead of a <code>null</code> value to represent empty nodes is due to the fact that when in an XML document there is an empty node the reason is often to express a <code>Boolean</code> content, as in this case:</p>
<pre class="brush: xml">&lt;car&gt;
  &lt;type&gt;Ferrari&lt;/type&gt;
  &lt;bought /&gt;
&lt;/car&gt;
</pre>
<p>If the value were <code>null</code> it would be more cumbersome to launch a code like this:</p>
<pre class="brush: js">if (myObject.car.Ferrari.bought) {
  // do something
}
</pre>
<div class="note">According to our <a href="#Algoritmo_JXON_3" title="Vai all'algoritmo JXON #3">third algorithm</a> and our <a href="#Algoritmo_JXON_4" title="Vai all'algoritmo JXON #4">fourth algorithm</a>, just <code>Text</code> nodes or <code>CDATASection</code> nodes which contain nothing but white spaces (precisely: <code>/^\s+$/</code>) are parsed as <code>null</code>.</div>
<p>An important consideration is that, using the third or the fourth algorithm, an XML Document can be used to create any type of Javascript object. For example, If you want to create an object like the following:</p>
<pre class="brush: js">{
  "bool": true,
  "array": ["Cinema", "Hot dogs", false],
  "object": {
    "nickname": "Jack",
    "registration_date": new Date(1995, 11, 25),
    "privileged_user": true
  },
  "num": 99,
  "text": "Hello World!"
}
</pre>
<p>you must just create an XML document with the following structure:</p>
<pre class="brush: xml">&lt;bool&gt;true&lt;/bool&gt;
&lt;array&gt;Cinema&lt;/array&gt;
&lt;array&gt;Hot dogs&lt;/array&gt;
&lt;array&gt;false&lt;/array&gt;
&lt;object&gt;
  &lt;nickname&gt;Jack&lt;/nickname&gt;
  &lt;registration_date&gt;Dec 25, 1995&lt;/registration_date&gt;
  &lt;privileged_user /&gt;
&lt;/object&gt;
&lt;num&gt;99&lt;/num&gt;
&lt;text&gt;Hello World!&lt;/text&gt;
</pre>
<p>This example also shows how the ideal JXON document is an XML document designed specifically to be converted in JSON format.</p>
<h3>Costruire file a partire da alberi DOM</h3>
<p>First, create a DOM tree as described in the <a href="/it/Come_creare_un_albero_DOM" title="it/Come_creare_un_albero_DOM">Come creare un albero DOM</a> article. If you have already have a DOM tree from using <a href="/it/XMLHttpRequest" title="it/XMLHttpRequest">XMLHttpRequest</a>, skip to the end of this section.</p>
<p>Now, let's serialize <code>doc</code> — the DOM tree — to a file (you can read more <a href="/en/Code_snippets/File_I//O" title="en/Code_snippets/File_I//O">about using files in Mozilla</a>):</p>
<pre class="brush: js">var oFOStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
var oFile = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties).get("ProfD", Components.interfaces.nsILocalFile); // get profile folder
oFile.append("extensions"); // extensions sub-directory
oFile.append("{5872365E-67D1-4AFD-9480-FD293BEBD20D}"); // GUID of your extension
oFile.append("myXMLFile.xml"); // filename
oFOStream.init(oFile, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate
(new XMLSerializer()).serializeToStream(doc, oFOStream, ""); // rememeber, doc is the DOM tree
oFOStream.close();
</pre>
<h3>Costruire file a partire da oggetti XMLHttpRequest</h3>
<p>If you already have a DOM tree from using <a href="/it/XMLHttpRequest" title="it/XMLHttpRequest">XMLHttpRequest</a>, use the same code as above but replace <code>serializer.serializeToStream(doc, foStream, "")</code> with <code>serializer.serializeToStream(xmlHttpRequest.responseXML.documentElement, foStream, "")</code> where <code>xmlHttpRequest</code> is an instance of <code>XMLHttpRequest</code>.</p>
<p>Note that this first parses the XML retrieved from the server, then re-serializes it into a stream. Depending on your needs, you could just save the <code>xmlHttpRequest.responseText</code> directly.</p>
<h3>Resources</h3>
<ul> <li><a class="external" href="http://xulplanet.com/tutorials/mozsdk/xmlparse.php">Parsing and Serializing XML su XUL Planet</a></li>
</ul>
<p>{{ languages( { "ja": "ja/Parsing_and_serializing_XML", "en": "en/Parsing_and_serializing_XML" } ) }}</p>
Ripristina questa versione