View Full Version : XML To Array script issue

04-19-2006, 07:56 PM
Hello All,
I've been working on the same script for two weeks nearly every day. I have it working almost exactly as I need it to, but there are three issues that I can't seem to figure out.
I think it's a "can't see the forest for the trees" issue, because I've been looking at it for so long. I'm hoping a pair of fresh eyes will see a glaring error or two in what I'm doing.
What I want to do is parse an XML file and put the keys and values into a hash.
I originally started working on this using the method I have now, then I abandoned that thinking there was a better way and used XPath. Xpath works perfect in Mozilla, but I couldn't get IE to work at all, even using xpath_dom.js by Dimitri Glazkov. So I went back to my original plan.
The three problems are #1 erronious replication of hash keys with no data. This can be seen at work at http://d13699489.d91.digitalelite.biz/xmltoarray_cross.php. (this is most problematic in xml_Array['data']['records']['record']['children']['son']['favorite_sport'] vs. xml_Array['data']['records']['record']['children']['son']['favorite_sport2'] because of the errroneous ->['favorite_sport1']. The other places that it happens I could live with, but prefer not to.
#2 using a different XML file, but the same script, it drops or doesn't set slices in the hash. See http://d13699489.d91.digitalelite.biz/xmltoarray_cross2.php (every 'record' should have the same keys, but only the first one is complete).
#3 while minor compared to the other two, the first node of the root node in both XML files are //data/time-date/published/ but the script ignores "published" and puts the data xml_Array['data']['time-date'] in instead.
The output should look like http://d13699489.d91.digitalelite.biz/xml_list2_mozilla_works.php (this is the XPath version, Mozilla Only :mad: )
Any help would be appreciated.

The code involved is:

function xmlToArray(tree) {
structure.pop(); //remove extra elements
for(var i=0; i<tree.childNodes.length; i++){
var tmp_array = new Array();
for(k in structure){
tmp_array.push(structure[k]); //put this on the end of the array.
var array_element = eval("xml_Array['"+tmp_array.join("']['")+"']");
if(!array_element){ //if the element does not exist create it.
if(tree.childNodes.length > 1){//if the current node has children
var def_element = eval("xml_Array['"+tmp_array.join("']['")+"'] = new Array()")//create array element.
}else{ //set the value
eval("xml_Array['"+tmp_array.join("']['")+"'] = '"+xmlSafe(tree.childNodes[i].nodeValue)+"'");
break; //we found what we wanted, NEXT!
if(k + 1 > depth){//make sure that we're at the current level.
tmp_array2 = structure;
var count = 0;
while(eval("typeof xml_Array['"+tmp_array2.join("']['")+"'] != 'undefined'")){//other node using this name, need to increment and create a new name.
var name_test = tmp_array2.pop();//now we have to work backwards.
name_test = name_test.replace(/\d+/g,''); //remove any number from the test name.
}else{ //not a tag, data
return tree.nodeValue;
xmlToArray(tree) is initially passed xmlDoc.documentElement

Full code is in the source of the above URLs.

04-19-2006, 09:12 PM
in the above post, I said I could live with the erroneous key duplication. Well as it turns out, I can't. I didn't realize it before, but this behaves differently in different browsers.
In IE it looks like this //root/records/record/name/<data>
In mozilla it looks like this: //data/records/record/<empty>
which as you can see would cause problems as my method to access the information has to be different for each browser.

04-21-2006, 09:07 PM
Since I really hate reading threads where a question is asked and you assume the person found an answer, but it was not posted, I have the answer, it works, at least in FireFox 1.5 and IE 6.

In the near future, you'll be able to see this in action at http://mechlogs.com and http://lancasteronline.com

Here's a working XMLtoArray page, complete:

<script type="text/javascript"><!--
* This script is copyright Karl Kittler (karl.kittler AT gmail.com)
* This program is free software; you may redistribute and/or modify
* it under the terms of the GNU General Public License version 2 or
* the GNU Lesser General Public License version 2.1 as published by
* the Free Software Foundation.
* should you feel so inclined, donations may be made via PayPal at
* at the same address.
* the above statement was included because so few people read this.
* this text must remain in any and all future revisions.
function loadXML(file){//load xml file
if (window.ActiveXObject){// code for IE
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
}else if (document.implementation && document.implementation.createDocument){// code for Mozilla, etc.
xmlDoc= document.implementation.createDocument("","",null);
alert('Your browser cannot handle this script');

function xmlToArray(tree) { //this returns the very outer part, but nothing inside it.
for(var i=0; i<tree.childNodes.length; i++){
tmp = xmlToArray(tree.childNodes[i]);
if(eval("typeof return_array == 'undefined'")) var return_array = new Array();
var count = '';
while(eval("typeof return_array['" + tree.childNodes[i].tagName + count + "'] != 'undefined'")){//other node using this name, need to increment and create a new name.
if(count == '')count = 0;
return_array[tree.childNodes[i].tagName+count] = tmp;
return_array = tmp;
return return_array;

}else{ //not a tag, data
return xmlSafe(tree.nodeValue);

function xmlSafe(string){
if(string == '' || string == null) return '';
search_array = Array();
//first, convert all existing HTMLEntities preceeding ampersand to something, so we don't screw them up.
string = string.replace( /&([a-zA-Z]{3,6})/g, "AMPERSAMD$1");
search_array['&'] = '&amp;';
search_array['"'] = '&quot;';
search_array["'"] = '&apos;';
search_array['<'] = '&lt;';
search_array['>'] = '&gt;';
//remove retuns and new lines
search_array['[\r\n]'] = '';
//now, put all the ampersands back in the encoded chars
search_array['AMPERSAMD'] = '&';
for(f in search_array){
var re = new RegExp (f, 'gi') ;
string = string.replace( re, search_array[f]);
/*string = string.replace(/&/g,'&amp;');
string = string.replace(/"/g,'&quot;');
string = string.replace(/'/g,'&apos;');
string = string.replace(/</g,'&lt;');
string = string.replace(/>/g,'&gt;');
return string;

function arrayToList(obj,name,recursing){ //this works fine, don't mess with it.
//If it doesn't work, it's your data, not me.
tmp = '';
if(!name) name='';
if(recursing) tmp = '<ul><li>(array)['+name+'=>';
if(obj.constructor == Array){
for(var k in obj){
tmp += arrayToList(obj[k],k.toString(),1);

tmp += '"'+obj+'"';
if(recursing) tmp += ']</li></ul>';
return tmp;

function hokey_pokey(){ //that's what it's all about
//all processing after loading the xml doc must be referenced here
var content='';
var output = new Array();
xml_Array = xmlToArray(xmlDoc.documentElement);
content += arrayToList(xml_Array);

<body onload="loadXML('name_address.xml')">
XML Data:<br>
<span id="content"></span>
This using the following file 'name_address.xml':

<?xml version="1.0" encoding="UTF-8"?>
<!-- Last update of file Fri, 21 Apr 2006 15:15:36 EDT -->
<time-date><published>Fri, 21 Apr 2006 15:15:36 EDT</published></time-date>
<record><name>TJ</name><address>My Home</address><city>My town</city><occupation>My Girl</occupation><nickname>Depends on the day</nickname><children><son><name>Matt</name><age>15</age><favorite_sport>football</favorite_sport><favorite_sport>baseball</favorite_sport></son><son><name>Austin</name><age>11</age></son><daughter><age>6</age><name>Mallory</name></daughter></children></record>

<record><name>Some Guy</name><address>123 Some Street</address><city>Some City</city><occupation>Farker</occupation><nickname>Some Guy</nickname></record>
<record><name>Bart</name><address>742 Evergreen Terrace</address><city>Springfield</city><occupation>Student</occupation><nickname>El Barto</nickname></record>
<record><name>My Car</name><address>My Driveway</address><city>My Town</city><occupation>Car</occupation><nickname>Maverik</nickname></record>

The root node does not appear in the array as the array is root node.

04-21-2006, 09:55 PM
Darn, I was writing on an answer, you know :)