/*******************************************************************************
  Classe per l'oggetto XML - DOM Cross-Browser
  
  Testato su:
    - Firefox 3.0
    - Internet Explorer 7
  
  Ciascun documento XML deve avere un unico nodo radice o non viene riconosciuto
  come documento valido
  
*******************************************************************************/

XMLDom = function()
{ 
  // Definizione di proprietà
  this.state    = true;
  this.error    = false;
  this.message  = "";
  this.xmlDoc   = null;
  this.xsltDoc  = null;
 
  // Definizione del metodo costruttore
  this.XMLDom = function()
  {
    this.xmlDoc   =  this.initDom();
    this.xsltDoc  =  this.initDom();
  }
  
  // Definizione di metodi
  
  this.initDom = function()
  {
    var xmlDomObj;
    // Istanzio il parser XML
    try 
    {
      // Istanzio l'activex per Internet Explorer
      xmlDomObj = new ActiveXObject("Microsoft.XMLDOM");
    }
    catch(e)
    {
      try 
      {
        // Istanzio il parser Per gli altri Browser
        xmlDomObj = document.implementation.createDocument("","",null);
      }
      catch(e)
      {
        // Catturo l'errore e lo memorizzo
        this.message = e.message;
        this.state = false;
        return null;
      }
    }
    // Normalizzo il comportamento di ie e FF. Spazi e a capo vengono trattati come nodi.
    xmlDomObj.preserveWhiteSpace = true;
    return xmlDomObj;
  }
  
  // Carica un documento XML esterno in un documento specificato
  this.loadXDoc = function(doc, docName)
  {
    if (this.state)
    {
      try 
      {
        doc.async =false;
        doc.load(docName);
        return (doc);
      }
      catch(e)
      {
        this.error    = true;
        this.message  = e.message;
      }
    }
    return (null);
  }
  
  // Carica un file xml esterno nell'oggetto
  this.loadXMLDoc = function(docName)
  {
    this.xmlDoc = this.loadXDoc(this.xmlDoc, docName);
    return this.xmlDoc;
  }
  
  // Carica un file xslt esterno nell'oggetto
  this.loadXSLTDoc = function(docName)
  {
    this.xsltDoc = this.loadXDoc(this.xsltDoc, docName);
    return this.xsltDoc
  }
  
  // Carica una stringa XML
  this.loadXString = function(doc, txt) 
  {
    if (this.state)
    {
      try
      {
        // Uso l'activeX per Internet Explorer
        doc.async="false";
        doc.loadXML(txt);
        return(doc); 
      }
      catch(e)
      {
        try
        {
          // Uso il parser per gli altri browser
          parser = new DOMParser();
          doc = parser.parseFromString(txt,"text/xml");
          return(doc);
        }
        catch(e)
        {
          this.error    = true;
          this.message  = e.message;
        }
      }
    }
    return(null);
  }
  
  // Carica una stringa XML
  this.loadXMLString = function(txt)
  {
    this.xmlDoc = this.loadXString(this.xmlDoc, txt);
    return this.xmlDoc;
  }
  
  // Carica un stringa XSLT
  this.loadXSLTString = function(txt)
  {
    this.xsltDoc = this.loadXString(this.xsltDoc, txt);
    return this.xsltDoc;
  }
  
  // Funzione ricorsiva per la visita in profondità
  this.traverseDomTree_recurse = function(curr_element, operation) 
  {

    // Controllo che il nodo abbia figli
    if(curr_element.childNodes.length > 0) 
    {
      operation(curr_element);
      // Per ogni figlio del nodo corrente
      for(var i=0; curr_element.childNodes.item(i); i++) 
      {
        // Chiamo ricorsivamente la funzione
        this.traverseDomTree_recurse(curr_element.childNodes.item(i),operation);
      }
    }
    
  }
  
  // Funzione di interfaccia per la visita
  this.traverseDomTree = function(operation) 
  {
    if ( this.state )
    {
      var nodo = this.xmlDoc.documentElement;
      this.traverseDomTree_recurse(nodo, operation);
    }
  }

  // Visita l'albero stampando il nome dei nodi e il valore. Questa funzione 
  // sebbene poco utile in generale mostra come recuperare nome e valore di un nodo
  // superando il problema degli spazi e degli a capo.
  this.printDomTree = function() 
  {
    if ( this.state )
    {
      var nodo = this.xmlDoc.documentElement;
      
      this.traverseDomTree_recurse(nodo , function(node)
                                          {
                                            // Recupero il nome del nodo
                                            str = node.nodeName;
                                            // Recupero il valore del nodo
                                            val = node.childNodes[0].nodeValue;
                                            document.write("<b>"+str+"</b>: "+val+"<br />");
                                          } );
    }
  }
  
  // Metodo per la trasformazione XSLT
  this.xsltTransform = function(target)
  {
    if ( (this.xmlDoc != null) && (this.xsltDoc != null) )
    {
      try
      {
        var transform = this.xmlDoc.transformNode(this.xsltDoc);
        target.innerHTML = transform;
      }
      catch(e)
      {
        try
        {
          var xsltProcessor = new XSLTProcessor();
          xsltProcessor.importStylesheet(this.xsltDoc);
          var resultDocument = xsltProcessor.transformToFragment(this.xmlDoc,document);
          target.appendChild(resultDocument);
        }
        catch(e)
        {
          // Dovremmo mettere gli errori nelle giuste variabili
          return false;
        }
      }
    }
    else
    {
      // Anche qui
      return false;
    }
    
    return true;
  }
  
  // Definizione di metodi get/set property
  this.getState = function()
  {
    return this.state;
  }
  
  this.getXMLDoc = function()
  {
    return this.xmlDoc;
  }
  
  // Richiamo del costruttore  
  this.XMLDom();
  
}
