tags:

views:

422

answers:

1

I have the folowing XML file generated by my iLO HP server, Do you have any examples of how can i parse it ? See the example XML file below. I would like to extract fan speeds and temperatures from it.

<?xml version="1.0"?>
<GET_EMBEDDED_HEALTH_DATA>
<FANS>
   <FAN>
      <LABEL VALUE = "Fan 1"/>
      <ZONE VALUE = "System"/>
      <STATUS VALUE = "Ok"/>
      <SPEED VALUE = "81" UNIT="Percentage"/>
   </FAN>
   <FAN>
      <LABEL VALUE = "Fan 2"/>
      <ZONE VALUE = "System"/>
      <STATUS VALUE = "Not Installed"/>
      <SPEED VALUE = "n/a" UNIT="n/a"/>
   </FAN>
   <FAN>
      <LABEL VALUE = "Fan 3"/>
      <ZONE VALUE = "System"/>
      <STATUS VALUE = "Ok"/>
      <SPEED VALUE = "81" UNIT="Percentage"/>
   </FAN>
   <FAN>
      <LABEL VALUE = "Fan 4"/>
      <ZONE VALUE = "System"/>
      <STATUS VALUE = "Not Installed"/>
      <SPEED VALUE = "n/a" UNIT="n/a"/>
   </FAN>
   <FAN>
      <LABEL VALUE = "Fan 5"/>
      <ZONE VALUE = "CPU 1"/>
      <STATUS VALUE = "Ok"/>
      <SPEED VALUE = "81" UNIT="Percentage"/>
   </FAN>
   <FAN>
      <LABEL VALUE = "Fan 6"/>
      <ZONE VALUE = "CPU 2"/>
      <STATUS VALUE = "Not Installed"/>
      <SPEED VALUE = "n/a" UNIT="n/a"/>
   </FAN>
</FANS>
<TEMPERATURE>
   <TEMP>
      <LABEL VALUE = "Temp 1"/>
      <LOCATION VALUE = "Ambient"/>
      <STATUS VALUE = "Ok"/>
      <CURRENTREADING VALUE = "32" UNIT="Celsius"/>
      <CAUTION VALUE = "40" UNIT="Celsius"/>
      <CRITICAL VALUE = "45" UNIT="Celsius"/>
   </TEMP>
   <TEMP>
      <LABEL VALUE = "Temp 2"/>
      <LOCATION VALUE = "Memory"/>
      <STATUS VALUE = "Ok"/>
      <CURRENTREADING VALUE = "48" UNIT="Celsius"/>
      <CAUTION VALUE = "110" UNIT="Celsius"/>
      <CRITICAL VALUE = "120" UNIT="Celsius"/>
   </TEMP>
   <TEMP>
      <LABEL VALUE = "Temp 3"/>
      <LOCATION VALUE = "CPU 1"/>
      <STATUS VALUE = "Ok"/>
      <CURRENTREADING VALUE = "30" UNIT="Celsius"/>
      <CAUTION VALUE = "100" UNIT="Celsius"/>
      <CRITICAL VALUE = "100" UNIT="Celsius"/>
   </TEMP>
   <TEMP>
      <LABEL VALUE = "Temp 4"/>
      <LOCATION VALUE = "CPU 1"/>
      <STATUS VALUE = "Ok"/>
      <CURRENTREADING VALUE = "30" UNIT="Celsius"/>
      <CAUTION VALUE = "100" UNIT="Celsius"/>
      <CRITICAL VALUE = "100" UNIT="Celsius"/>
   </TEMP>
   <TEMP>
      <LABEL VALUE = "Temp 5"/>
      <LOCATION VALUE = "I/O Board"/>
      <STATUS VALUE = "Ok"/>
      <CURRENTREADING VALUE = "46" UNIT="Celsius"/>
      <CAUTION VALUE = "63" UNIT="Celsius"/>
      <CRITICAL VALUE = "68" UNIT="Celsius"/>
   </TEMP>
   <TEMP>
      <LABEL VALUE = "Temp 6"/>
      <LOCATION VALUE = "CPU 2"/>
      <STATUS VALUE = "n/a"/>
      <CURRENTREADING VALUE = "n/a" UNIT="n/a"/>
      <CAUTION VALUE = "100" UNIT="Celsius"/>
      <CRITICAL VALUE = "100" UNIT="Celsius"/>
   </TEMP>
   <TEMP>
      <LABEL VALUE = "Temp 7"/>
      <LOCATION VALUE = "CPU 2"/>
      <STATUS VALUE = "n/a"/>
      <CURRENTREADING VALUE = "n/a" UNIT="n/a"/>
      <CAUTION VALUE = "100" UNIT="Celsius"/>
      <CRITICAL VALUE = "100" UNIT="Celsius"/>
   </TEMP>
</TEMPERATURE>
+2  A: 

It depends, and as usual there is lots of ways to do it. Primarily it depends on the size of the (actual) file. If it's big, I would recommend using a module like XML::Twig to cut it into smaller pieces before parsing. It it is small, like your example file, almost anything should do. For instance XML::LibXML::XPathContext could do it like this (note: you'll do wisely to add some error checking code to the parsing and possibly validate the xml beforehand):

#!/us/bin/perl                                                                                          

use warnings;                                                                                            
use strict;                                                                                              

use XML::LibXML;                                                                                         
use XML::LibXML::XPathContext;                                                                           

my $parser = XML::LibXML->new();                                                                         

my $doc = $parser->parse_file('test.xml');                                                               

my @nodes = $doc->findnodes('//FAN/SPEED');                                                              

foreach my $node(@nodes){                                                                                
  printf("fan: %s %s\n", $node->getAttribute('VALUE'), $node->getAttribute('UNIT'));                     
}

which gives this output:

fan: 81 Percentage
fan: n/a n/a
fan: 81 Percentage
fan: n/a n/a
fan: 81 Percentage
fan: n/a n/a

You'll probably need a quick intro to XPath

Knut Haugen
any idea if i can use Simple XML with this ?
Mike
yea... i can't seem to be able to install XPath on my debian box, even with "apt-get install libxml-libxml-perl"
Mike
@Mike: unless you are on etch or older, that should do it. How does it fail for you?
ysth
@ysth: I'm using Lenny. I did the apt-get install but i am still receiving the folowing when i try to run the code : Can't locate XML/LibxML/XPathContext.pm in @INC (@INC contains: /etc/perl /usr/local/lib/perl/5.10.0 /usr/local/share/perl/5.10.0 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.10 /usr/share/perl/5.10 /usr/local/lib/site_perl .) at perl2.pl line 6.BEGIN failed--compilation aborted at perl2.pl line 6.
Mike
You could of course use XML::Simple for this task, but I tend to steer away from XML::Simple because I've had experiences where it gets in my way rather than doing the thing I want. But it's been a while and it might have changed now. As usual YMMV.
Knut Haugen