getExtendedData() the easy way

64 views
Skip to first unread message

jmatthews

unread,
Nov 6, 2009, 8:36:57 PM11/6/09
to KML Developer Support - Google Earth Plug-in
I've seen where people wanted a function to be able to get their
Extended Data (<ExtendedData>).

I ran across this earlier thread. It did not work for me because I
had empty <value> tags in my kml file. Further, I noticed the routine
was not quite compact enough because it required the programmer to run
a loop after every call to the function.

A better way to access the data would be through a single function
call.

I therefore wrote the following routine and documented the heck out of
it due to GE's peculiar ways of handling kml data after importing it
through kmlFetch().

I imagine there is an even more efficient way to write this, where a
programmer could pass an array of various values to retrieve
simultaneously. It would probably run faster, as well, which could be
important when calling this function inside a loop.

At any rate, I hope this is helpful to someone and/or provides the
impetus for a better re-write. (Sorry if formatting is bad. This is
not a very good editor).


function getExtendedData(kmlString,varName)
{

// Return value of <Data> element assigned in a kml file under
// the <ExtendedData> tags.

// Note: This is tested for use when <ExtendedData> is loaded from
a kml file.
// It is NOT tested for when <ExtendedData> is set programatically.

// kmlString is GE's function. ( e.g. placemark.getKml() )
// varName is the name attribute of the <Data> tag that is the
subject of inquiry.

// Usage: To find value of lastName in ExtendedData where kml file
contains:
// <ExtendedData>
// <Data name="firstName">
// <value>John</value>
// </Data>
// <Data name="lastName">
// <value>Smith</value>
// </Data>
// </ExtendedData>

// Example use: last=getExtendedData(placemark.getKml
(),'lastName');

try
{
//ie
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async="false";
xmlDoc.loadXML(kmlString);
}
catch(e)
{
try //ff, moz, op, etc.
{
parser=new DOMParser();
xmlDoc=parser.parseFromString(kmlString,"text/xml");
}
catch(e)
{
alert(e.message);
return;
}
}

data=xmlDoc.getElementsByTagName("Data");

for(var i=0; i<data.length; i++)
{
var name = data[i].getAttribute('name');

if (name.toUpperCase()==varName.toUpperCase())
{
// Then, the matching <Data (name)> was found.
// But it might not have a value assigned, so we defualt
// the return at "".
retValue="";

// Per the way GE loads kml and set up a dom,
// a <Data> set will always have either 1 or 3 children.

// Of particular noteworthiness is that if the kml file
contains
// <value> tags, but no text between those tags, GE does
not
// load the value tags in kmlFetch(). Therefore, the
programmer will wind up
// getting errors if it is just assumed that all tags in a
kml
// file are loaded.

// If 1 child, it is always named #text.
// There will only be 1 when the kml file does NOT
// assign a value to the <Data (name)>, EVEN WHEN
// the <value> tags are present in the file but have no text
between them.

// If 3 children, they are always #text, value, #text.
// Not sure why, but that is the way it is.
// There will only be 3 children when <value> tags are
present
// in the kml file AND there is text in the kml file between
those <value> tags.

if (data[i].childNodes.length==3)
{
// Then, childNodes[1] is the value node.
retValue=data[i].childNodes[1].textContent;

}

// No need to continue going through rest of <Data> tags.
// The match has been found and processed.
break;
}
else
{
// I like setting the following default return because the
only way this occurs is
// if programmer makes an error and references a <Data (name)>
which does not
// exist.
// Returning an empty string is a bit cryptic. Likely, when
the program
// does not perform as expected, programmer will be wondering
what, among many
// possibilities, is wrong. This return will make it obvious
when programmer
// tests the return value in the calling procedure. An alert
can cause
// inconvenience in cases where this function is called within
a loop.

retValue='ExtendedData variable "'+varName+'" not found.';
}

}

return retValue;
}


fraser (Earth API Guru)

unread,
Nov 7, 2009, 12:44:43 PM11/7/09
to KML Developer Support - Google Earth Plug-in
Hi,

That looks great, maybe you could post it as a further work around to
issue 16?
http://code.google.com/p/earth-api-samples/issues/detail?id=16

Thanks,

Fraser.

jmatthews

unread,
Nov 7, 2009, 2:52:46 PM11/7/09
to KML Developer Support - Google Earth Plug-in
Thanks, fraser. A good chunk of that was actually borrowed from your
example on another thread. But for your example, this would have
taken me much longer to conceptualize and implement.

It is tough posting code on here because formatting is largely lost.
It really makes it a chore for me.

What I think this site could use is a feature used by other sites.
They allow placing code snippets between [Code] tags in the editor, so
that tabs remain intact.

What I think would really be useful is a page where people can post
their home made utilities by subject matter and description.

Maybe one of these days....

>

jmatthews

unread,
Nov 10, 2009, 3:35:30 PM11/10/09
to KML Developer Support - Google Earth Plug-in
NOTE!!!!

I have found that FF and Chrome process kml in the DOM one way, while
IE processes it another way. Therefore, I had to re-write the
getExtendedData() function for cross-browser compatibility. It is
documented inside the code below.

Here it is. As usual, if you need it, you'll have to copy and format
the indents on your own. This editor makes indenting very difficult.
// Note: The above works that way for FF and Chrome, but not IE.
// In IE, there will be either 0 or 1 children.

browser=navigator.appName;
if (browser.search(/Internet Explorer/i)==(-1))
{
if (data[i].childNodes.length==3)
{
// Then, childNodes[1] is the value node.
retValue=data[i].childNodes[1].textContent;
}
}
else
{
// IE.
if (data[i].childNodes.length==1)
{
// Then, childNodes[0] is the value node.
// IE does not like textContent. It likes childNodes
[0].nodeValue.
retValue=data[i].childNodes[0].childNodes[0].nodeValue;
}
}

// No need to continue going through rest of <Data> tags.
// The match has been found and processed.
break;
}
else
{
// I like setting the following default return because the only
way this occurs is if programmer
// makes an error and references a <Data (name)> which does not
exist.
// Returning an empty string is a bit cryptic. Likely, when the
program
// does not perform as expected, programmer will be wondering
what, among many
// possibilities, is wrong. This return will make it obvious
when programmer
// tests the return value in the calling procedure. An alert can
cause
// inconvenience in cases where this function is called within a
loop.

retValue='ExtendedData variable "'+varName+'" not found.';
}

}

return retValue;
}







Markw65

unread,
Nov 10, 2009, 4:25:53 PM11/10/09
to KML Developer Support - Google Earth Plug-in
I think you're making /way/ too many assumptions about the format of
the data.

The reason you're getting three text nodes is (most likely) because
you have
<value>
text
</value>

Some (compliant, so not IE) xml processors will put the line-end, and
space at the beginning of the next line as the first #text child, the
value as the next, and the line-end and whitespace at the end as the
third child.

While <value>text</value> will typically result in a single #text
node.

But then <value>te
xt</value> could well result in two #text children (or it might not).

But the fact is, that the #text nodes can be split anywhere...

So the correct way to deal with this is to concatenate all the
children, and then deal with white space in whatever manner is
appropriate for your data (if you're writing a general purpose
routine, you probably want to give the caller some options here - such
as "keep it", "trim leading and trailing", etc.

Mark

jmatthews

unread,
Nov 10, 2009, 5:51:16 PM11/10/09
to KML Developer Support - Google Earth Plug-in
Perhaps I am making too much of it, but I find that the routine is the
MINIMUM to access the proper node between the various browsers.

If you can improve it, please do. Maybe you have an idea to improve
its speed as well.
> >                                 //  in the kml file AND there is text in the kml file between- Hide quoted text -
>
> - Show quoted text -

Markw65

unread,
Nov 10, 2009, 7:07:24 PM11/10/09
to KML Developer Support - Google Earth Plug-in


On Nov 10, 2:51 pm, jmatthews wrote:
> Perhaps I am making too much of it, but I find that the routine is the
> MINIMUM to access the proper node between the various browsers.

Except that it only works (in FF/Chrome) if you format your xml as:

<value>
text
</value>

If you give it <value>text</value> it will only get /one/ child node
(not three), and you'll discard the text!

Here's my suggestion (again):

Concatenate all the #text nodes, and then do whatever cleanup you
think is appropriate. It seems that you want to discard any preceeding
or following white space, so something like value = value.replace(/^\s*
(.*?)\s*$/,"$1") should do the trick.

If you do that, the same code works for all the browsers, and
regardless of the formatting of the xml file.

Simpler, and more portable...

Mark
Reply all
Reply to author
Forward
0 new messages