I changed the code to be more prototype-esque, and created a class called XMLDoc. I may add more functionality to it later, hence the more generic name, but you do something like this to convert XML to a hash: XMLDoc = Class.create(); Object.extend(XMLDoc.prototype, { initialize: function (xmlDoc) { this.element = xmlDoc; }, asHash: function () { if (! this._xmlHash) { this._xmlHash = this._nodeToHash(this.element); } return this._xmlHash; }, _nodeToHash: function (node) { Element.cleanWhitespace(node); if ((node.attributes && node.attributes.length > 0) || (node.hasChildNodes() && node.childNodes[0].nodeType =1)) { var localHash = {}; if (node.attributes && node.attributes.length >= 1) { $A(node.attributes).each(function (attr) { localHash[attr.nodeName] = [attr.nodeValue]; }); } $A(node.childNodes).each(function (node) { this._subNodeToHash(localHash, node); }.bindAsEventListener(this)); $H(localHash).each( function (pair) { if (localHash[pair[0]].length == 1) { localHash[pair[0]] localHash[pair[0]][0]; } }); return localHash; } else { return this._nodeAsText(node); } }, _subNodeToHash: function (hash, node) { if (node.nodeType == 2) { hash[node.localName] = this._nodeAsText(node); } else { var key = node.tagName; if (hash[key]) { hash[key].push(this._nodeToHash(node)); } else { hash[key] = [ this._nodeToHash(node) ]; } } }, _nodeAsText: function (node) { return node.textContent || node.innerText || node.text || ''''; } } ); Usage: var doc = new XMLDoc(request.responseXML.documentElement); var hash = doc.asHash(); So, this xml: <document> <item id="1" type="blah" /> <item> <id>2</id> <type>blah</type> </item> </document> Becomes: { item: [ { id: 1, type: ''blah'' }, { id: 2, type: ''blah'' } ] } Dunno if anyone even cares, but hey, free code :) Greg
Very nice! Thank you. I''m sure I will be using this. But what about elements with attributes, nested elements AND/OR text values? What does: <element attribute="blah">text</element> Look like? And what does a nested structure like this look like as a hash: <elements groupName="blah"> <element id="1" type="blah1">text1</element> <element id="2" type="blah2">text2</element> </elements> I would expect something similar to... { elements: [ { groupName: "blah", element: [ { id: "1", type: "blah1", TEXT: "text1" // ??? }, { id: "2", type: "blah2", TEXT: "text2" // ??? } ] } ] } ...but you''ll have to have some way to handle cases where an attribute of "TEXT" is supplied, etc... ...you might have to append your hash object names with something to indicate if the name/value pair represents an attribute, element, or text node. Like: { elements_EL: [ { groupName_ATTR: "blah", element_EL: [ { id_ATTR: "1", type_ATTR: "blah1", text: "text1" }, { id_ATTR: "2", type_ATTR: "blah2", text: "text2" } ] } ] } Then you always know "text" represents the text value, because if an element (or attribute) of "text" was supplied, it would be appended with an identifier.. Or maybe taking it that far is beyond the scope of what you need it for? Lol, it seems if you take this far enough you might as well just stick with XML... The information transmitted in this electronic mail is intended only for the person or entity to which it is addressed and may contain confidential, proprietary, and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from all computers.
> But what about elements with attributes, nested elements AND/OR text > values?It''s recursive.> > What does: > > <element attribute="blah">text</element> > > Look like?I don''t think that is handled in the current code. If you have attributes, you''d need to have nested tags (or nothing). I could add a conditional that if you have attributes and no child tags, the text goes into a key called ''text''. But, I hadn''t really considered it before :)> > And what does a nested structure like this look like as a hash: > > <elements groupName="blah"> > <element id="1" type="blah1">text1</element> > <element id="2" type="blah2">text2</element> > </elements> > > I would expect something similar to...Close. Since there is only 1 ''elements'' tag, it is not an array. Also, having a mixture of text and attributes isn''t yet handled. I''ll just rewrite your example to be what it would be currently:> > { > elements: > { > groupName: "blah", > element: [ ''text1'', ''text2'' ] > } > }But, if those elements didn''t have ''text1'' or ''text2'', then the hash structure from the attributes would''ve been created. But, now that I think about it more, having an array all the time makes more sense. I did it the current way so that tags that only had text in them would not be arrays, but I should change it so that if there are nested tags, it stays an array.> > ...but you''ll have to have some way to handle cases where an attribute > of "TEXT" is supplied, etc... > > ...you might have to append your hash object names with something to > indicate if the name/value pair represents an attribute, element, or > text node. >No, I don''t think I''d want to do that. If I cared about whether they were attributes or elements, I''d just use regular XML functions to get to what I needed. This is meant basically to just convert to a usable, hierarchical data structure.> Lol, it seems if you take this far enough you might as well just stick > with XML...Yeah, I agree. I''ll probably add the part to put the ''text'' in they key ''text'' if there are attributes already defined, but beyond that I don''t want to extend the scope. As always, great input. Thanks. Greg
No problem, always try to play Devil''s advocate... Your tool is very nice, I can think of a few applications already. Thanks for the work. The information transmitted in this electronic mail is intended only for the person or entity to which it is addressed and may contain confidential, proprietary, and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from all computers.
Updated code: XMLDoc = Class.create(); Object.extend(XMLDoc.prototype, { initialize: function (xmlDoc) { this.element = xmlDoc; }, asHash: function () { if (! this._xmlHash) { this._xmlHash = this._nodeToHash(this.element); } return this._xmlHash; }, _nodeToHash: function (node) { Element.cleanWhitespace(node); if ((node.attributes && node.attributes.length > 0) || (node.hasChildNodes() && node.childNodes[0].nodeType =1)) { var localHash = {}; if (node.attributes && node.attributes.length >= 1) { $A(node.attributes).each(function (attr) { localHash[attr.nodeName] = [attr.nodeValue]; }); } if (node.hasChildNodes() && node.childNodes[0].nodeType == 1) { $A(node.childNodes).each(function (node) { this._subNodeToHash(localHash, node); }.bindAsEventListener(this)); } else if (node.hasChildNodes()) { localHash[''text''] = [this._nodeAsText(node)]; } $H(localHash).each( function (pair) { if (pair[1].length == 1 && typeof pair[1][0] == ''string'') { localHash[pair[0]] = pair[1][0]; } }); return localHash; } else { return this._nodeAsText(node); } }, _subNodeToHash: function (hash, node) { var key = node.tagName; if (hash[key]) { hash[key].push(this._nodeToHash(node)); } else { hash[key] = [ this._nodeToHash(node) ]; } }, _nodeAsText: function (node) { return node.textContent || node.innerText || node.text || ''''; } } ); I think this addresses the ''text'' thing as well as keeping things in an array if there are sub-elements. So, now your example should be pretty much spot-on (except lowercase text vs. TEXT). Greg> -----Original Message----- > From: rails-spinoffs-bounces-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org[mailto:rails-spinoffs-> bounces-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org] On Behalf Of Ryan Gahl > Sent: Friday, March 17, 2006 3:01 PM > To: rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > Subject: RE: [Rails-spinoffs] Updated the xml code to be more object- > oriented > > No problem, always try to play Devil''s advocate... > > Your tool is very nice, I can think of a few applications already. > Thanks for the work. > > The information transmitted in this electronic mail is intended onlyfor> the > person or entity to which it is addressed and may containconfidential,> proprietary, and/or privileged material. Any review, retransmission, > dissemination or other use of, or taking of any action in relianceupon,> this information by persons or entities other than the intendedrecipient> is prohibited. If you received this in error, please contact thesender> and > delete the material from all computers. > > _______________________________________________ > Rails-spinoffs mailing list > Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs
Hi Gregory What you think about this /* -------------------------------------- */ XMLDoc = Class.create(); Object.extend(XMLDoc.prototype, { initialize: function (XMLFile, options) { this.xmlFile = XMLFile; this.options = options; this.element = false; this.getXml(); }, XMLHash: function () { return this.XMLParsed; }, asHash: function () { if (! this._xmlHash) { this._xmlHash = this._nodeToHash(this.element); } return this._xmlHash; }, getXml: function () { if(this.options.onLoading) { this.options.onLoading(); } new Ajax.Request(this.xmlFile, {method:''get'', onComplete: this.parseXML.bind(this)}); }, parseXML: function (req) { this.element = req.responseXML; var XMLParsed = this.asHash(); if(this.options.onComplete) { this.options.onComplete(XMLParsed); } }, _nodeToHash: function (node) { Element.cleanWhitespace(node); if ((node.attributes && node.attributes.length > 0) || (node.hasChildNodes() && node.childNodes[0].nodeType == 1)) { var localHash = {}; if (node.attributes && node.attributes.length >= 1) { $A(node.attributes).each(function (attr) { localHash[attr.nodeName] = [attr.nodeValue]; }); } if (node.hasChildNodes() && node.childNodes[0].nodeType =1) { $A(node.childNodes).each(function (node) { this._subNodeToHash(localHash, node); }.bindAsEventListener(this)); } else if (node.hasChildNodes()) { localHash[''text''] = [this._nodeAsText(node)]; } $H(localHash).each( function (pair) { if (pair[1].length == 1 && typeof pair[1][0] =''string'') { localHash[pair[0]] = pair[1][0]; } }); return localHash; } else { return this._nodeAsText(node); } }, _subNodeToHash: function (hash, node) { var key = node.tagName; if (hash[key]) { hash[key].push(this._nodeToHash(node)); } else { hash[key] = [ this._nodeToHash(node) ]; } }, _nodeAsText: function (node) { return node.textContent || node.innerText || node.text || ''''; } } ); /* -------------------------------------- */ Usage: /* ************** */ function showRssLength(xml) { /* this is an example */ alert(xml.rss[0][''channel''][0][''item''].length); } new XMLDoc(''rssFile.xml'',{onComplete:showRssLength}); /* ************** */ On Fri, 2006-03-17 at 22:35, Gregory Hill wrote:> Updated code: > XMLDoc = Class.create(); > Object.extend(XMLDoc.prototype, { > initialize: function (xmlDoc) { > this.element = xmlDoc; > }, > asHash: function () { > if (! this._xmlHash) { > this._xmlHash = this._nodeToHash(this.element); > } > return this._xmlHash; > }, > _nodeToHash: function (node) { > Element.cleanWhitespace(node); > if ((node.attributes && node.attributes.length > 0) > || (node.hasChildNodes() && node.childNodes[0].nodeType => 1)) { > var localHash = {}; > if (node.attributes && node.attributes.length >= 1) { > $A(node.attributes).each(function (attr) { > localHash[attr.nodeName] = [attr.nodeValue]; }); > } > if (node.hasChildNodes() && node.childNodes[0].nodeType == 1) { > $A(node.childNodes).each(function (node) { > this._subNodeToHash(localHash, node); }.bindAsEventListener(this)); > } > else if (node.hasChildNodes()) { > localHash[''text''] = [this._nodeAsText(node)]; > } > $H(localHash).each( function (pair) { if (pair[1].length == 1 && > typeof pair[1][0] == ''string'') { localHash[pair[0]] = pair[1][0]; } }); > return localHash; > } > else { > return this._nodeAsText(node); > } > }, > _subNodeToHash: function (hash, node) { > var key = node.tagName; > if (hash[key]) { > hash[key].push(this._nodeToHash(node)); > } > else { > hash[key] = [ this._nodeToHash(node) ]; > } > }, > _nodeAsText: function (node) { > return node.textContent || node.innerText || node.text || ''''; > } > } ); > > I think this addresses the ''text'' thing as well as keeping things in an > array if there are sub-elements. So, now your example should be pretty > much spot-on (except lowercase text vs. TEXT). > > Greg > > > -----Original Message----- > > From: rails-spinoffs-bounces-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > [mailto:rails-spinoffs- > > bounces-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org] On Behalf Of Ryan Gahl > > Sent: Friday, March 17, 2006 3:01 PM > > To: rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > > Subject: RE: [Rails-spinoffs] Updated the xml code to be more object- > > oriented > > > > No problem, always try to play Devil''s advocate... > > > > Your tool is very nice, I can think of a few applications already. > > Thanks for the work. > > > > The information transmitted in this electronic mail is intended only > for > > the > > person or entity to which it is addressed and may contain > confidential, > > proprietary, and/or privileged material. Any review, retransmission, > > dissemination or other use of, or taking of any action in reliance > upon, > > this information by persons or entities other than the intended > recipient > > is prohibited. If you received this in error, please contact the > sender > > and > > delete the material from all computers. > > > > _______________________________________________ > > Rails-spinoffs mailing list > > Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > > http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs > _______________________________________________ > Rails-spinoffs mailing list > Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs-- /** * Claudio Gamboa * @email: gamboa-uCwpClY+SkUVhHzd4jOs4w@public.gmane.org * @IM-Sapo: claudiogamboa-N47toQN4rTE@public.gmane.org */