Manipulating XML using JavaScript

No PHP, ASP or JSP codes, just JavaScript.

Manipulating XML files or data using JavaScript to create lists, tables, menus, manipulate feeds (rss or atom), etc.

Important: Browser just allow access to files in your own domain (security reasons). Dont try to load XML files of another domains, this is not possible.

1. Make a XML test file

<?xml version="1.0" ?>
<person>
   <ident id="1">
    <name>John</name>
    <email>John@mail.com</email>
   </ident>
   <ident id="2">
    <name family="ze" data="2">Maria</name>
    <email>maria@mail.com</email>
   </ident>
</person>

Save as names.xml

2. Loading XML

The browsers load XML files using diferent ways (like in Ajax). Internet Explorer (IE) use ActiveX. Firefox and Opera use XMLHttpRequest (and another ways).

The code to return a XML object to these browsers is:

function xmlMicoxLoader(url){
  //by Micox: micoxjcg@yahoo.com.br.
  //http://elmicoxcodes.blogspot.com
    if(window.XMLHttpRequest){
        var Loader = new XMLHttpRequest();
        //assyncronous mode to load before the 'return' line
        Loader.open("GET", url ,false); 
        Loader.send(null);
        return Loader.responseXML;
    }else if(window.ActiveXObject){
        var Loader = new ActiveXObject("Msxml2.DOMDocument.3.0");
        //assyncronous mode to load before the 'return' line
        Loader.async = false;
        Loader.load(url);
        return Loader;
    }
}

Using assyncronous mode to load before the 'return' line.

More informations about responseXML (in portuguese): a propriedade responseXML.

3. Manipulating XML - Example

XML can be manipulated like a tree using DOM functions and properties: childNodes, nodeType, nodeValue, firstChild, etc. To see more functions read MDC DOM docs.

In example code bellow, i read all childs of XML returned by xmlMicoxLoader. Get values using "nodeValue", names using "nodeName" and attributes using array "attributes[]".

Very important: IE ignores white spaces in XML file, but to Opera and Firefox, these white spaces are valid childNodes (#text nodes). To filter these elements we using a nodetype test (real XML elements have nodeType=1, #texts have nodeType=3).

This example code print a XML tree. Read and understends:

function xmlMicoxTree(xmlNode,ident){
  //by Micox: micoxjcg@yahoo.com.br
    var treeTxt=""; //var to content temp
    for(var i=0;i<xmlNode.childNodes.length;i++){//each child node
  if(xmlNode.childNodes[i].nodeType == 1){//no white spaces
   //node name
   treeTxt = treeTxt + ident + xmlNode.childNodes[i].nodeName + ": "
   if(xmlNode.childNodes[i].childNodes.length==0){
    //no children. Get nodeValue
    treeTxt = treeTxt + xmlNode.childNodes[i].nodeValue 
    for(var z=0;z<xmlNode.childNodes[i].attributes.length;z++){
     var atrib = xmlNode.childNodes[i].attributes[z];
     treeTxt = treeTxt + " (" + atrib.nodeName + " = " + atrib.nodeValue + ")";
    }
    treeTxt = treeTxt + "<br />\n";
   }else if(xmlNode.childNodes[i].childNodes.length>0){
    //children. get first child
    treeTxt = treeTxt + xmlNode.childNodes[i].firstChild.nodeValue;
    for(var z=0;z<xmlNode.childNodes[i].attributes.length;z++){
     var atrib = xmlNode.childNodes[i].attributes[z];
     treeTxt = treeTxt + " (" + atrib.nodeName + " = " + atrib.nodeValue + ")";
    }
    //recursive to child of children
    treeTxt = treeTxt + "<br />\n" + xmlMicoxTree(xmlNode.childNodes[i],ident + "> > ");
   }
      }
    }
    return treeTxt;
}

Call the functions:

xml = xmlMicoxLoader("names.xml"); //load xml
document.write(xmlMicoxTree(xml,"")); //print the tree 

4) Loading RSS

In the next post, a real example: loading a RSS XML feed just using JavaSript

---
Another way to load XML using JavaScript in IBM website.

Portuguese original version.

Include Function in JavaScript

Here, a include function to JavaScript like PHP.

Good for conditional includes.

Using:

if(have_money==true)  {
 include("girs.js");
} else if(i_am_very_rich==true) {
 include("more_more_girls.js");
}else if(i_am_inteligent==true){
 include("no_girls_back_to_work.js");
}

Add this function to your code:

function include(arquivo){
//By Fabrício Magri e Micox
//http://elmicox.blogspot.com/2006/12/include-em-javascript.html
 var novo = document.createElement('script');
 novo.setAttribute('type', 'text/javascript');
 novo.setAttribute('src', arquivo);
 document.getElementsByTagName('head')[0].appendChild(novo);
 //apos a linha acima o navegador inicia o carregamento do arquivo
 //portanto aguarde um pouco até o navegador baixá-lo. :)
}

Tested sucessful in Internet Explorer 6.0, Firefox 2.0 and Opera 8.5.

Edit 02/08/07: A include_once function can be viewed here.

Bugs and comments? Just comment :) Bye.

Portuguese original version and comments.

InnerHTML and Select option in IE

Hello. This is my second post.

The non-DOM property innerHTML can't add options to a tag select in Internet Explorer.

Example not working:

document.getElementById("my_select").innerHTML = "<option value='1'>not</option> <option value='2'>work</option>"; 

The correct way to insert options in a select is using appendChild or addOption functions. But that's tiring if we are working with Ajax.

Use innerHTML is not the standard but it is very useful.

The function above, will help you to insert options like using innerHTML, in IE, Firefox or Opera.

Updated: now supports option-selected

Using my function:

var inner = "<option value='1'>Now</option> <option value='2'>work</option>"; 
select_innerHTML(document.getElementById("my_select"),inner);

The function. Add to your lib.

function select_innerHTML(objeto,innerHTML){
/******
* select_innerHTML - corrige o bug do InnerHTML em selects no IE
* Veja o problema em: http://support.microsoft.com/default.aspx?scid=kb;en-us;276228
* Versão: 2.1 - 04/09/2007
* Autor: Micox - Náiron José C. Guimarães - micoxjcg@yahoo.com.br
* @objeto(tipo HTMLobject): o select a ser alterado
* @innerHTML(tipo string): o novo valor do innerHTML
*******/
    objeto.innerHTML = ""
    var selTemp = document.createElement("micoxselect")
    var opt;
    selTemp.id="micoxselect1"
    document.body.appendChild(selTemp)
    selTemp = document.getElementById("micoxselect1")
    selTemp.style.display="none"
    if(innerHTML.toLowerCase().indexOf("<option")<0){//se não é option eu converto
        innerHTML = "<option>" + innerHTML + "</option>"
    }
    innerHTML = innerHTML.toLowerCase().replace(/<option/g,"<span").replace(/<\/option/g,"</span")
    selTemp.innerHTML = innerHTML
      
    
    for(var i=0;i<selTemp.childNodes.length;i++){
  var spantemp = selTemp.childNodes[i];
  
        if(spantemp.tagName){     
            opt = document.createElement("OPTION")
    
   if(document.all){ //IE
    objeto.add(opt)
   }else{
    objeto.appendChild(opt)
   }       
    
   //getting attributes
   for(var j=0; j<spantemp.attributes.length ; j++){
    var attrName = spantemp.attributes[j].nodeName;
    var attrVal = spantemp.attributes[j].nodeValue;
    if(attrVal){
     try{
      opt.setAttribute(attrName,attrVal);
      opt.setAttributeNode(spantemp.attributes[j].cloneNode(true));
     }catch(e){}
    }
   }
   //getting styles
   if(spantemp.style){
    for(var y in spantemp.style){
     try{opt.style[y] = spantemp.style[y];}catch(e){}
    }
   }
   //value and text
   opt.value = spantemp.getAttribute("value")
   opt.text = spantemp.innerHTML
   //IE
   opt.selected = spantemp.getAttribute('selected');
   opt.className = spantemp.className;
  } 
 }    
 document.body.removeChild(selTemp)
 selTemp = null
}

Another solution to innerHTML/Select/IE problem, here

Portuguese original version.

Word wrap in Firefox

Updated version of word-wrap to Firefox and Opera here!!! Above, a old version with bugs.

Hello. My first topic.
This blog will show just codes.

I have a blog in portuguese language and decide post my codes in english to all the word heheh.
My english is not good, so, sorry and go to codes. Just codes.

The Firefox dont wrap big words like Internet Explorer in width of a parent element.
Example:

This code

<style>
#url {
width: 400px;
}
</style>
<div id="url">
    <p>URL:</p>
    <p>http://www.google.com.br/search?hl=pt-BR&q=blableblibloblu&btnG=Pesquisa+Google&meta= </p>
</div>

In IE will render like

URL
http://www.google.com.br/search?hl=pt-
BR&q=plugsites&btnG=Pesquisa+Google&meta=

And the Firefox will render like

URL
http://www.google.com.br/search?hl=pt-BR&q...Pesquisa+Google&meta=

This is a problem. The declarations to word wrap just will come in CSS3.

But try use this code:

<style>
#url { border:1px solid black; width:50px; }
p {border:1px solid blue; }
</style>
<script>
function wordWrap(){
/******
* wordWrap to firefox for big words
* Creative Commons license * Version: 1.0 - 26/04/2006
* Autor: Micox - Náiron J.C.G - micoxjcg@yahoo.com.br - http://elmicoxcodes.blogspot.com
* Uso: call the function on onload of body element.
* put the class "word-wrap" on elements to wordwrap
*******/
    var larg_total,larg_carac,quant_quebra,pos_quebra;
    var elementos,quem, caracs, texto, display_orig;
    
    elementos = document.getElementsByTagName("p")
    
    for(var i=0; i<elementos.length;i++){
        if(elementos[i].className=="word-wrap"){
            quem = elementos[i];
            
            quem.innerHTML = String(quem.innerHTML).replace(/ /g,"Ø")
            texto = String(quem.innerHTML)
            
            quem.innerHTML = " "
            
            display_orig = quem.style.display;
            quem.style.display="block";
            larg_oficial = quem.offsetWidth;
            //alert("oficial: " + larg_oficial)
            //alert("display " + quem.style.display)
            if(!document.all) quem.style.display="table";
            //alert("display " + quem.style.display)
            quem.innerHTML = texto;
            larg_total = quem.offsetWidth;
            //alert("total: " + larg_total)
            
            pos_quebra = 0;
            caracs = texto.length;
            texto = texto.replace(/Ø/g," ")
            larg_carac = larg_total / caracs
            if(larg_total>larg_oficial){
                quant_quebra = parseInt(larg_oficial/larg_carac)
                quant_quebra = quant_quebra - (parseInt(quant_quebra/6)) //quanto menor o num, maior a garantia;
                quem.innerHTML = ""
                while(pos_quebra<=caracs){
                    quem.innerHTML = quem.innerHTML + texto.substring(pos_quebra,pos_quebra + quant_quebra) + " "
                    pos_quebra = pos_quebra + quant_quebra;
                }
            }else{
                quem.innerHTML = texto;
            }//end if do larg_total>larg_oficial
            quem.style.display = display_orig;
        }//end if do word wrap
    }//end for loop dos elementos
}
</script>
<body onload="wordWrap()">
<div id="url">
    <p>URL:</p>
    <p class="word-wrap">lala </p>
    <p class="word-wrap">EstaEUmaLinhaQueDeveraSerQuebradaPoisÉGrandeDemais</p>
    <p  class="word-wrap">EstaEOutraLinha,QueDeveraSerQuebrada.PoisÉGrandeDemais.MasComPontuacao</p>
    <p  class="word-wrap">abc defgh 890123456789012 ijklmnopqrstu 9012345678901 vivaO micox </p>
    <p  class="word-wrap">Vou colocar aqui uma frase comum pragente ver comé que ela se comporta</p>
</div>
</body>

Just add word-wrap classname in elements to wrap

Bye. To the next

Portuguese original version.