parsing XML
|
|
Thread rating:  |
miquael - 18 Mar 2008 23:06 GMT Why won't this work? I just want to create one Node for each <placemark> tag in the xml.
the xmlData trace gets:
<kml xmlns="http://earth.google.com/kml/2.2"> <Placemark id="0" type="1"> <name>Zero - zero</name> <description>This is at zero latitude and zero longitude</description> <Point> <coordinates>0,0,0</coordinates> </Point> </Placemark> <Placemark id="1" type="2"> <name>Simple placemark</name> <description>Attached to the ground. Intelligently places itself at the height of the underlying terrain.</description> <Point> <coordinates>-122.0822035425683,37.42228990140251,0</coordinates> </Point> </Placemark> <Placemark id="2" type="3"> <name>New York City</name> <description>This is a rockin' town</description> <Point> <coordinates>42.3583,-75.85,0</coordinates> </Point> </Placemark> </kml>
Yet, I cannot even get the second "success!" trace.
public function processMarkerData (xmlData:XML):void {
// loop through all markers in the XML // and generate a node for each one trace ("xmlData: " + xmlData);
for each (var xmlPlacemark:XML in xmlData.placemark) { trace ("success!"); // create node var node:Node = new Node( xmlPlacemark, { nodeID: nodeID, app: this }); // add node to nodeArray and display container nodes.push(node); container.addChild(node); // increment id nodeID++; } } }
miquael - 19 Mar 2008 02:35 GMT Raymond Basque - 19 Mar 2008 11:16 GMT xmlData.placemark should be xmlData.Placemark
Raymond Basque - 19 Mar 2008 11:39 GMT Just noticed you're using a namespace. This will work whether or not there is a default namespace declared in the xml.
public function processMarkerData (xmlData:XML):void { // retrieve the default namespace var ns:Namespace = xmlData.namespace();
// loop through all markers in the XML // and generate a node for each one trace ("xmlData: " + xmlData);
for each (var xmlPlacemark:XML in xmlData.ns::Placemark) {
trace ("success!");
// create node var node:Node = new Node( xmlPlacemark, { nodeID: nodeID, app: this });
// add node to nodeArray and display container nodes.push(node); container.addChild(node);
// increment id nodeID++; } }
miquael - 20 Mar 2008 02:36 GMT Great, thanks. Yes, that works: i am now getting the XML passed into the loop.
So, next issue is this: I'm passing xmlPlacemark to another function that then extracts the data from the XML structure. I am partially successfull with extrafcting a few attributes, but am not able to extract element values. I've tried everything I could find in the CS3 help files. Seem like it should be pretty straight forward, but this does not work:
private function initContent(xmlPlacemark:XML):void { trace ("xmlPlacemark: " + xmlPlacemark); // returns just the portion of xml needed here
// extract data from XML id = xmlPlacemark.attribute("id"); // works type = xmlPlacemark.attribute("type"); // works title = xmlPlacemark.name; // returns nothing! contentPath = xmlPlacemark.description;// returns nothing! geoPosition = xmlPlacemark.Point.coordinates; // returns nothing! trace ("*** id: " + id); trace ("*** type: " + type); trace ("*** title: " + title); trace ("*** contentPath: " + contentPath); trace ("*** geoPosition: " + geoPosition); // more calculations ... }
miquael - 20 Mar 2008 02:37 GMT Here is the XML again:
<?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://earth.google.com/kml/2.2"> <Placemark id="0" type ="1"> <name>Zero - zero</name> <description>This is at zero latitude and zero longitude</description> <Point> <coordinates>0,0,0</coordinates> </Point> </Placemark> <Placemark id="1" type ="2"> <name>Simple placemark</name> <description>Attached to the ground. Intelligently places itself at the height of the underlying terrain.</description> <Point> <coordinates>-122.0822035425683,37.42228990140251,0</coordinates> </Point> </Placemark> <Placemark id="2" type ="3"> <name>New York City</name> <description>This is a rockin' town</description> <Point> <coordinates>42.3583,-75.85,0</coordinates> </Point> </Placemark> </kml>
miquael - 20 Mar 2008 02:43 GMT The trace ("xmlPlacemark: " + xmlPlacemark) returns just portions of the total XML (as it should):
<Placemark id="2" type="3" xmlns="http://earth.google.com/kml/2.2"> <name>New York City</name> <description>This is a rockin' town</description> <Point> <coordinates>42.3583,-75.85,0</coordinates> </Point> </Placemark>
miquael - 20 Mar 2008 02:44 GMT Interesting that the namespace is in there again ...
miquael - 20 Mar 2008 02:48 GMT I've also tried this with no success:
title = xmlPlacemark.descendants("name"); geoPosition = xmlPlacemark.Point.(elements("coordinates"));
miquael - 20 Mar 2008 02:53 GMT And neither of these works:
title = xmlPlacemark..name; title = xmlPlacemark.elements("name");
miquael - 20 Mar 2008 03:02 GMT These both return "null". Why?
title = xmlPlacemark..name[0]; title = xmlPlacemark.name[0];
Raymond Basque - 20 Mar 2008 13:11 GMT Dealing with xml namespaces can be a little tricky. But this document uses only one default namespace ( xmlns="http://earth.google.com/kml/2.2" ), and it's applied to the root node. In this case, all child nodes and their attributes belong to that namespace, which makes it fairly easy to work with.
private function initContent(xmlPlacemark:XML):void { trace ("xmlPlacemark: " + xmlPlacemark); // declare a default namespace -- inherited from // parent node if none declared
var ns:Namespace = xmlPlacemark.namespace(); default xml namespace = ns;
// extract data from XML // assumes all target members are string types: id = xmlPlacemark.@id.toString(); type = xmlPlacemark.@type.toString(); title = xmlPlacemark.name.toString(); contentPath = xmlPlacemark.description.toString(); geoPosition = xmlPlacemark.Point.coordinates.toString(); trace ("*** id: " + id); trace ("*** type: " + type); trace ("*** title: " + title); trace ("*** contentPath: " + contentPath); trace ("*** geoPosition: " + geoPosition); // more calculations ... }
miquael - 20 Mar 2008 22:02 GMT Great, yes, that helps! I am getting good results now. Thanks!
However, a new problem now arises: although the values are now being extracted from the XML, when the next function is called, I get a very strange error.
Here is the new function as I have it now (which gets values for all the trace vars):
private function initContent1(xmlPlacemark:XML, data:Object):void { trace ("xmlPlacemark: " + xmlPlacemark); // declare a default namespace -- inherited from // parent node if none declared var ns:Namespace = xmlPlacemark.namespace(); default xml namespace = ns; // extract data from XML // (assumes all target members are string types) // from attributes id = xmlPlacemark.@id.toString(); type = xmlPlacemark.@type.toString(); // from elements title = xmlPlacemark.name.toString(); contentPath = xmlPlacemark.description.toString(); geoPosition = xmlPlacemark.Point.coordinates.toString(); // parse latitude and longitude from geoPosition var geoPos:Array = new Array(); geoPos = geoPosition.split(",", 3); // * latitude = geoPos[0]; longitude = geoPos[1]; elevation = geoPos[2]; trace ("*** id: " + id); trace ("*** type: " + type); trace ("*** title: " + title); trace ("*** contentPath: " + contentPath); trace ("*** geoPosition: " + geoPosition); trace ("*** latitude: " + latitude); trace ("*** longitude: " + longitude); trace ("*** elevation: " + elevation); // extract data from data object nodeID = data.nodeID; app = data.app; }
miquael - 20 Mar 2008 22:09 GMT Here is the resulting output and error. Although there are 3 <Placemark> nodes in the XML, only the first is processed before the error emerges. I've never seen an error like this before, followed by "VerifyError: Error #1025: An invalid register 3 was accessed." What's this about?
xmlPlacemark: <Placemark id="0" type="1" xmlns="http://earth.google.com/kml/2.2"> <name>Zero point: 0, 0, 0</name> <description>sample.html</description> <Point> <coordinates>0,0,0</coordinates> </Point> </Placemark> *** id: 0 *** type: 1 *** title: Zero point: 0, 0, 0 *** contentPath: sample.html *** geoPosition: 0,0,0 *** latitude: 0 *** longitude: 0 *** elevation: 0 verify UI::Node/UI:Node::setType() stack: scope: [global Object$ flash.events::EventDispatcher$ flash.display::DisplayObject$ flash.display::InteractiveObject$ flash.display::DisplayObjectContainer$ flash.display::Sprite$ flash.display::MovieClip$ UI::Node$] locals: UI::Node * 0:getlocal0 stack: UI::Node scope: [global Object$ flash.events::EventDispatcher$ flash.display::DisplayObject$ flash.display::InteractiveObject$ flash.display::DisplayObjectContainer$ flash.display::Sprite$ flash.display::MovieClip$ UI::Node$] locals: UI::Node * 1:pushscope stack: scope: [global Object$ flash.events::EventDispatcher$ flash.display::DisplayObject$ flash.display::InteractiveObject$ flash.display::DisplayObjectContainer$ flash.display::Sprite$ flash.display::MovieClip$ UI::Node$] UI::Node locals: UI::Node * 2:getlocal3 VerifyError: Error #1025: An invalid register 3 was accessed. at UI::Node/UI:Node::setType() at UI::Node$iinit() at MeadanGlobe/processMarkerData() at Function/http://adobe.com/AS3/2006/builtin::call() at support::DataLoader/support:DataLoader::loadDataComplete() at flash.events::EventDispatcher/flash.events:EventDispatcher::dispatchEventFunctio n() at flash.events::EventDispatcher/dispatchEvent() at flash.net::URLLoader/flash.net:URLLoader::onComplete()
miquael - 20 Mar 2008 22:15 GMT Now if I revert to the previous function that uses the previous XML schema, then this error does not emerge. I mean, I have now "initContent1(xmlPlacemark, data);" and "initContent2(xmlPlacemark, data);" to easily switch between functions for testing (I call either one or the other). If I use the original function (initContent2), everything works--but only if I comment out the entire new function (initContent1). Here is the original function again. Not much is different:
private function initContent2(xmlPlacemark:XML, data:Object):void { trace ("xmlPlacemark: " + xmlPlacemark); var attributes:XMLList = xmlPlacemark.attributes(); id = attributes[0]; title = attributes[1]; type = attributes[2]; contentPath = attributes[3]; geoPosition = xmlPlacemark.georss; // parse latitude and longitude from georss var latlong:Array = new Array(); latlong = geoPosition.split(" ", 2); latitude = latlong[0]; longitude = latlong[1]; trace ("*** id: " + id); trace ("*** type: " + type); trace ("*** title: " + title); trace ("*** contentPath: " + contentPath); trace ("*** geoPosition: " + geoPosition); trace ("*** latitude: " + latitude); trace ("*** longitude: " + longitude); // extract data from data object nodeID = data.nodeID; app = data.app; }
miquael - 20 Mar 2008 22:19 GMT And here is the setType() function, on which it appear the error is happening. Again, this error only happens here whenever initContent1 is left in the code (not commented out), independent of weather it is actually being called or not! What's going on here?!
Here is setType():
private function setType():void { switch (type) { case "1": colorCode = 0xE06117; // red break; case "2": colorCode = 0x6DC1EF; // blue break; case "3": colorCode = 0x7FDD34; // green break; case "4": colorCode = 0xD0C32E; // yellow break; default: colorCode = 0xFFFFFF; // white break; } if (!meadanColors) {colorCode = 0xFFFFFF} colorTransform(colorCode); }
miquael - 20 Mar 2008 22:21 GMT FYI, the entire code base for this project is an open-source project that is available here:
http://code.google.com/p/meadanglobe
miquael - 20 Mar 2008 22:29 GMT I was not able to find much info on "Error #1025: An invalid register 3 was accessed". What's this about?
Raymond Basque - 21 Mar 2008 15:16 GMT Holy crap! Took a little bit of investigating, but it seems that if you hold a reference to a namespace within a method and set the default xml namespace to that namespace, BANG! Most likely the namespace goes out of scope. There are 2 ways to fix the problem.
1. In each method, set the default xml namespace to null when no longer needed:
private function initContent1(xmlPlacemark:XML, data:Object):void {
trace ("xmlPlacemark: " + xmlPlacemark);
// declare a default namespace var ns:Namespace = xmlPlacemark.namespace(); default xml namespace = ns; // ... other stuff default xml namespace = null; }
2. Store the namespace in a private field:
// private variable to hold a copy of the namespace belonging // to the xmlPlacemark node passed to the ctor // We need to do this to get around a nasty problem // where if we set the default xml namespace to a local reference // and then forget to set it to null, we get // "VerifyError: Error #1025: An invalid register 3 was accessed." // OUCH!! private var ns:Namespace = null;
// NODE CONSTRUCTOR //////////////////////////////////// public function Node(xmlPlacemark:XML, data:Object):void { // store the namespace for future reference ns = xmlPlacemark.namespace(); initContent1(xmlPlacemark, data); //initContent2(xmlPlacemark, data);
setType(); setPosition(); initTextDisplay(); // addEventListener(Event.ENTER_FRAME, update); addEventListener(MouseEvent.CLICK, clickHandler); addEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler); addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler); }
private function initContent1(xmlPlacemark:XML, data:Object):void {
trace ("xmlPlacemark: " + xmlPlacemark);
// declare a default namespace -- was stored in private var default xml namespace = ns; // ... other stuff } private function initContent2(xmlPlacemark:XML, data:Object):void {
trace ("xmlPlacemark: " + xmlPlacemark);
// declare a default namespace -- was stored in private var default xml namespace = ns; // ... other stuff }
Raymond Basque - 21 Mar 2008 16:55 GMT ... Most likely "because" the namespace goes out of scope. ..
miquael - 21 Mar 2008 21:38 GMT That's it! Good find. I went with solution #1
Thanks so much for your help!
Raymond Basque - 21 Mar 2008 23:11 GMT
|
|
|