How do I get attributes with XML::XPath?

Viewed 64

I have a short perl (cgi) program which parses and displays some weather data.

I was getting data from an XML source with nested values, each with unique tags.

Now I get some data with multiple entries, distinguished by a unique “type” field, and then a (different) value for each.

Previous data:

<weather ver="2.0">
  <head>
    <locale>en_US</locale>
  </head>
  <loc id="52557">
    </loc>
  <cc>
    <tmp>16</tmp>
    <flik>16</flik>
    <t>Mostly Cloudy</t>
    <bar>
      <r>1022.35</r>
      <d>steady</d>
    </bar>
    <wind>
      <s>14</s>
      <gust>N/A</gust>
      <d>120</d>
      <t>ESE</t>
    </wind>
    <hmid>77</hmid>
  </cc>
</weather>

So I could access like this: (relevant fragments..)

use XML::XPath;
use XML::XPath::Parser;

sub getData($) {
    my $url   = http://wxdata.weather.com/wxdata/weather/local/52557?cc=*&unit=$unit;
    return get($url);

#  returned values are XML::XPath::Nodeset  (not numbers, or strings!!)
my $xml = getData($zip);
 $xp = XML::XPath->new($xml);
sub getVal($) { ##      ("tag")
    my $tag = shift;
    return $xp->findvalue($tag)->value();

sub postData($) {
    my $wind  = getVal('//cc/wind/s');
      if($wind=="calm") { $wind=0; }
    my $gust  = getVal('//cc/wind/gust');
    my $dir   = getVal('//cc/wind/d');
    my $real  = getVal('//cc/tmp');
    my $felt  = getVal('//cc/flik');
    my $pres  = getVal('//cc/bar/r');
etc.
       print "Wind:: ", $wind, " (", $dir, "), Gust:: ", $gust, "\n";
      }

Now the fields are like this, note how temperature and wind-speed have the same tag, but are differentiated by a "type" data field.:

<dwml version="1.0" xsi:noNamespaceSchemaLocation="http://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">
  <head>
    ...
  </head>

  <data type="current observations">
    <parameters applicable-location="point1">
      <temperature type="apparent" units="Fahrenheit" time-layout="k-p1h-n1-1">
        <value>91</value>
      </temperature>
      <temperature type="dew point" units="Fahrenheit" time-layout="k-p1h-n1-1">
        <value>77</value>
      </temperature>
      <humidity type="relative" time-layout="k-p1h-n1-1">
        <value>63</value>
      </humidity>
      <direction type="wind" units="degrees true" time-layout="k-p1h-n1-1">
        <value>310</value>
      </direction>
      <wind-speed type="gust" units="knots" time-layout="k-p1h-n1-1">
        <value>NA</value>
      </wind-speed>
      <wind-speed type="sustained" units="knots" time-layout="k-p1h-n1-1">
        <value>3</value>
      </wind-speed>
      <pressure type="barometer" units="inches of mercury" time-layout="k-p1h-n1-1">
        <value>30.08</value>
      </pressure>
    </parameters>
  </data>
</dwml>

I can still access any unique labels, e.g.

   my $dir   = getVal('//parameters/direction/value')

but don’t know how to access values with same tag but different “type” fields.

my $gust  = getVal('//parameters/wind-speed/gust/value');    ??
my $real  = getVal('//parameters/temperature/value');   ??
1 Answers

Use a predicate, checking the type attribute e.g. XPath //parameters/wind-speed[@type='gust'] or //parameters/wind-speed[@type="gust"].

Related