Parsing XML Files

I have not found any examples of parsing an xml document and the documentation is unclear to me regarding the development status of XML parsing in P5 JS. See loadXML, parseXML -- What is Status? Workarounds?. For folks already familiar with parsing xml with other versions of Processing, all that's really necessary for P5 JS would be a working example code.

The following code does not work, but is a start. Currently, it loads (or appears to load) an xml file with the command, loadXML(url). However, getChildren, getChildCount, and similar commands do not seem to work. I don't know if its necessary, but the html file precedes this development code.

If anyone has ideas or suggestions for how to test parsing xml documents, please help me create a working example.

HTML

<head>
  <script language="javascript" src="p5.js"></script>
  <script language="javascript" src="p5.dom.js"></script>
</head>
<body>
<div id="ncdgbW"><script language="javascript" src="NCDGB_Weather.js"></script></div>
</body>

CODE

    var url_mesonet_xml = "http://www.wrh.noaa.gov/mesowest/mwXJList.php?extents=39.839552,-124.571045,41.505911,-122.428711&zoom=9&mapsize=780px,800px&density=1&format=xml";
var local_xml = "mwxml.xml";
var StationIDs = ["D0866"];

var MesoData;

var StatusText;

// colors
var ColorList = ["216,17,91","10,255,163","10,237,255","43,110,161","130,176,208","184,78,38","246,210,186","0,107,59","116,39,43","19,56,162","149,138,176","71,0,97","116,0,23"];
var  TextColor;
var  flcolor;
var  bgColor;
var  svgfill;
var  svgstroke;
var  SlideColor;

var LastUpdate;
var UpdateInterval;

var CaseControl;

var Canvas;
var BackGrndImg;

function setup() {
  BackGrndImg = createImg("https://scontent-b-dfw.xx.fbcdn.net/hphotos-xfp1/v/t1.0-9/p552x414/10603438_782958711724495_2214620743295991804_n.png?oh=04e33b806eae5c4a0b4c64a97dbb60d7&oe=548E1695");
  Canvas = createCanvas(600, 600);
  BackGrndImg.position(0,0);
  BackGrndImg.size(600,AUTO);
  Canvas.position(0,0);
  //loadXML("http://www.wrh.noaa.gov/mesowest/mwXJList.php?extents=39.839552,-124.571045,41.505911,-122.428711&zoom=9&mapsize=780px,800px&density=1&format=xml");
  CaseControl=0;
  UpdateInterval = 600000;
  LastUpdate = millis() + UpdateInterval;

  StatusText = "Standing By";

  //XMLElement xml;
  // Mesodata =  loadXML("mwxml.xml");
  // numSites = Mesodata.getChildCount();
  // for ( i = 0; i < numSites; i++) {
  // kid = Mesodata.getChild(i);
  // id = kid.getInt("id"); 
  // url = kid.getString("name"); 
  // site = kid.getContent();
  // println(id + " : " + url + " : " + site);    
  //}
}

function draw() {
  background(255,0);
  switch(CaseControl) {
  default:
      UpdateInterval = 600000;
      break;
  case 1:
          UpdateInterval = 600000;
      break;
  }

  if (CaseControl == 0) {
     //stroke(246,210,255,98);
     //strokeWeight(.12);
     noStroke();
     fill(216,17,91,255);
     noFill();
     textSize(24);
     text(StatusText,370,440,570,580); 
     //println("should be case 1");
  }
  //BackGrndImg.show(); 

  // background(bgColor.split(","));
  // push();
  // tint(SlideColor.split(","),40);
  // imageMode(CENTER);

  if (millis()-LastUpdate >= UpdateInterval) {
   println("updating");
   LastUpdate = millis();
}

}



function keyTyped() {
    if (key === 'm') {
    //MesoData = loadXML("http://www.wrh.noaa.gov/mesowest/mwXJList.php?extents=39.839552,-124.571045,41.505911,-122.428711&zoom=9&mapsize=780px,800px&density=1&format=xml",CaseControl = 1);  
    MesoData = loadXML("mwxml.xml",ParseMeso);  
    //CaseControl = 1;
    } else
    if (key === 's') {
    println("case:" + CaseControl); 
    }else 
    if (key === 't') {
      ParseMeso();  
    }
}

function mousePressed() {
  // if (Hlink != "") {window.open(Hlink);}
}

function ParseMeso() {

    // var children[] = MesoData.getChildren("station");
    //parseXML(StatusText);  uncaught exception: not yet implemented
    StatusText = MesoData.toString(); 
    println(StatusText);
}

Here is a sample of the particular structure of the xml source I am working with:

<?xml version="1.0" encoding="ISO-8859-1"?>
<mesonet>
<station id="D0866" name="DW0866 Eureka" elev="79" lat="40.73133" lon="-124.205" distance="" provider="APRSWXNET/CWOP"><link>http://www.wrh.noaa.gov/mesowest/getobext.php?sid=D0866</link>;
<ob time='11 Sep 2:54 am PDT'>
<variable var='T' description='Temp' unit='F' value='51'/>
<variable var='RH' description='Relh' unit='%' value='38'/>
<variable var='ALTSE' description='Altimeter' unit='inches' value='29.84'/>
<variable var='P' description='Station Pressure' unit='inches' value='29.849'/>
<variable var='STAQUAL' description='Station Quality' unit='' value='Caution'/>
</ob></station>
</mesonet>

Answers

  • "t loads (or appears to load)"
    How do you check this?
    You should println() the content to see if there is data.

  • I am not sure how to print the content.

    With something like 'var MesoData;' instead of 'XML MesoData;' because the later statement is syntactically incorrect with P5 JS, or something, the following breaks at line 2, showing an error message that parseXML is not implemented.

    MesoData = loadXML("mwxml.xml");   // no error, but, did it really get data?
    //parseXML(StatusText);  uncaught exception: not yet implemented
    StatusText = MesoData.toString(); 
    println(StatusText);
    

    Results with " ". I am not sure if toString would be the best method to show the raw contents of 'MesoData', perhaps a list to string would be more appropriate ... my results are not dispositive of anything.

    structures like this, ' var children[] = MesoData.getChildren("station");' which work in javascript, might not work in P5 JS simply because it's syntactically incorrect, or, might not work because the features, for lack of better word, are not implemented.

  • edited September 2014

    I am trying to avoid trial and error to see if features are enabled, for myself and others. I modified my original post at line 91 to perform a callback to the function ParseMeso() when the target of loadXML is loaded. The callback function does not run, leading me to conclude that loadXML is either not working or there is a problem with my coding.

    One thing that looks out of place is that usually you declare or otherwise specify an object to be an xml object, e.g. 'XML MesoData;' ... in my code I just declare it as a var because nothing else I've tried produces an executable code.

    I'm going to see if loadStrings works, although I prefer to work directly with the xml data and it might make more sense to parse the xml data with a separate processing.js sketch running as a cron job into a file that P5 can load with loadStrings, or better, loadTable.

    On my 'to do' list is to look into the try() statement for P5. Usually, when you load data from external sources, you want to avoid uncaught exceptions when the file/data is not there .... I don't know if callbacks completely obviate the need for try and catch statements.

    If loadXML's totally not working at this point, would it be appropriate take a hiatus and keep this issue UNANSWERED for the time being?

  • edited September 2014

    For most cases, where we'd normally load resources within setup(), transferring them to preload() is the most sensible & easiest choice to do!
    Alas, for your case, 1 load isn't enough. You need 1 reload to happen for each keyTyped() event!
    However, you made some mistakes and redundancies in your current implementation! ~:>


    Let's start from the redundancy case: mesoData = loadXML('mwxml.xml', parseMeso);
    Since the callback argument (parseMeso) is yet to happen in the future, assigning to a variable so soon is premature and will only get ya a null after all! :-& That'd be valid inside preload() though.
    For now, let's clean up that unneeded assignment: if (key == 'm') loadXML('mwxml.xml', parseMeso);


    function parseMeso() {
      statusText = mesoData.toString();
      print(statusText);
    }
    

    Your callback above doesn't make any sense due to these 2 facts:

    1. loadXML() doesn't know & thus won't magically assign its result to mesoData!
    2. loadXML() passes an argument to the callback instead!

    In short, your custom specified callback gotta read its passed argument and manually assign it to the "global" variable you wish to:

    function parseMeso(loaded) {
      mesoData = loaded;
      print(mesoData);
    }
    

    This recent thread touched this callback subject too:
    forum.processing.org/two/discussion/6942/loadstrings-question


  • edited September 2014

    In my code I just declare it as a var because nothing else I've tried produces an executable code.

    In JS, only the data got a type. Variables on the other hand can store any of them! So they're simply var! >:)

    In addition to var, now there's also const, which means the same as Java's final. \m/
    And another 1's coming up called let, which would finally render true local scoped variables! O:-)

Sign In or Register to comment.