Apologies if this is simple to some, but it's been doing my head in.

I've got my client application receiving the XML from the server but I'm having a hell of a time parsing it.

The XML is :

<?xml version="1.0" encoding="UTF-8"?>
<page>
	<id>1</id>
	<code>HOME</code>
	<template>1</template>
	<menulevel>0</menulevel>
	<menuname></menuname>
	<menutooltip></menutooltip>
	<elements>
		<element id="content1">
			<id>1</id>
			<page>1</page>
			<container>content1</container>
			<type>javascript</type>
			<value></value>

			<data><![CDATA[showmainmenu()]]></data>
		</element>
		<element id="content2">
			<id>2</id>
			<page>1</page>
			<container>content2</container>
			<type>text</type>

			<value></value>
			<data><![CDATA[<span style="font-family:helvetica,arial,sans-serif; font-size:10px; text-align:center;">Information goes here.</span>]]></data>
		</element>
		<element id="title">
			<id>3</id>
			<page>1</page>
			<container>title</container>

			<type>text</type>
			<value></value>
			<data><![CDATA[Economic Dashboard & Summary]]></data>
		</element>
	</elements>
	<generated>Wed, 12 May 2010 14:08:30 +0200</generated>
</page>

What I want to do is to be able, with Javascript, to quickly pick out various bits of data from this information, such as the <data> tag of the <element> that has attribute "title".

So far as I can tell, there's no way of getting an element by its attribute name without traversing the entire DOM tree. Is that right? Seems like a monumental pain in the ass if it's the case, so I'm hoping I'm wrong.

Since I couldn't find a way to do it, I've resorted to the following, but still have issues with my solution :

data=http.responseXML.documentElement
elements=data.getElementsByTagName('element');
var num_elements = elements.length
for (i = 0; i > num_elements ; i++) {
  if (elements[i].attributes.getNamedItem('id').value=="title") {
    alert(elements[i].getElementsByTagName('data')[0].value
  }
}

but that just returns "undefined".

I'd rather not have to traverse the DOM tree with a loop just to find the right node though - there must be a way to reference a node some other way? I can't do it by index number because they won't always be in the same order...

Any insight into either problem would be helpful, thank you in advance.

N.

Recommended Answers

All 6 Replies

I dont think there is any way to get an element by its attribute.

As for the second problem try following in Line no. 6

alert(elements[i].getElementsByTagName('data')[0].childNodes[0].nodeValue);
elements=data.getElementsByTagName('element');
for (i = 0; i < elements.length ; i++)

The comparison in the for statement was miscoded.

Take a look at .selectSingleNode() and related methods (IE only).

Take a look at .selectSingleNode() and related methods (IE only).

For the others, this

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html>
  <head>
    <meta name="generator" content=
    "HTML Tidy for Windows (vers 25 March 2009), see www.w3.org">
    <title></title>
  </head>
  <body>
    <script type="text/javascript">
	var xmlstring ='<?xml version="1.0" encoding="UTF-8"?><page> <id>1</id> <code>HOME</code> <template>1</template> <menulevel>0</menulevel> <menuname></menuname> <menutooltip></menutooltip> <elements>  <element id="content1">   <id>1</id>   <page>1</page>   <container>content1</container>   <type>javascript</type>   <value></value>    <data><![CDATA[showmainmenu()]]></data>  </element>  <element id="content2">   <id>2</id>   <page>1</page>   <container>content2</container>   <type>text</type>    <value></value>   <data><![CDATA[<span style="font-family:helvetica,arial,sans-serif; font-size:10px; text-align:center;">Information goes here.</span>]]></data>  </element>  <element id="title">   <id>3</id>   <page>1</page>   <container>title</container>    <type>text</type>   <value></value>   <data><![CDATA[Economic Dashboard & Summary]]></data>  </element> </elements> <generated>Wed, 12 May 2010 14:08:30 +0200</generated></page>'

	var xmlobject = (new DOMParser()).parseFromString(xmlstring, "text/xml");

	var root = xmlobject.getElementsByTagName('page')[0];
	
	elems = root.getElementsByTagName('element');
	for (var i = 0; i < elems.length; i++) {
	    if (elems[i].getAttribute('id') == 'title') {
	        cns = elems[i].getElementsByTagName('data')
	        for (var j = 0; j < cns.length; j++) {
	            alert(cns[j].firstChild.nodeValue)
	        }
	    }
	}

    </script>
  </body>
</html>

will do what you want.

A more elegant cross-browser version should be possible.

Note: the iteration on j would not be needed if there can only be one 'data' within an <element id='title'>.

elems = root.getElementsByTagName('element');
	for (var i = 0; i < elems.length; i++) {
	    if (elems[i].getAttribute('id') == 'title') {
	        cns = elems[i].getElementsByTagName('data')
	        for (var j = 0; j < cns.length; j++) {
	            alert(cns[j].firstChild.nodeValue)
	        }
	    }
	}

Of course taking a different view

dats = root.getElementsByTagName('data');
	for (var i = 0; i < dats.length; i++) {
	   with (dats[i].parentNode) {
	      if (tagName=='element' && getAttribute('id')=='title') alert(dats[i].firstChild.nodeValue)
	   }
	}

makes the code look simpler but could - depending on the content of the xml document - increase processing time.

Of course both demos above assume [as is true in the sample xml document provided] that the 'data' nodes of interest all have at least one child and that each firstChild is of type #text; in a realistic situation it may be necessary to handle other possibilities.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.