Jump to content

XML Parsing Assistance


michael.davis

Recommended Posts

Good Monday Everyone!

 

I am working on some code to pull in an XML formatted page from the internet and break it out into variables.

 

I am not sure what I am missing here, but it will not parse the data.  I am sure something simple.

 

Here is the web link:

 

http://www.amecim.com/metronashvillewater/metronashvilleraingaugeservice.asmx/getAllGauges15m

 

Listed below is the code:

 

<?php
//
// 15 Minute Gauge Data
//

$xml = new SimpleXMLElement('http://www.amecim.com/metronashvillewater/metronashvilleraingaugeservice.asmx/getAllGauges15m', 0, true);

foreach ($xml->clsRainGaugeReading as $row) {
printf("Sample Date: %s\n", $row->SampleDate);
  echo "<br>";
    printf("Sample Time: %s\n", $row->SampleTime);
      echo "<br>";
    printf("Gauge Name: %u\n", $row->GaugeName);
      echo "<br>";
  printf("Sample Value: %u\n", $row->SampleValue);
      echo "<br>";
        echo "<br>";
}
?>

 

Thanks in advance for any help.

 

Mike

 

 

Link to comment
Share on other sites

Your method is fine, you've just mis-understood your structure.

 

Use this to view your structure.

 

<?php
//
// 15 Minute Gauge Data
//

$xml = new SimpleXMLElement('http://www.amecim.com/metronashvillewater/metronashvilleraingaugeservice.asmx/getAllGauges15m', 0, true);

echo '<pre>';
print_r($xml);
echp '</pre>'

?>

Link to comment
Share on other sites

Hey mate

 

Sorry I only suggested that because it's generally what I use.

 

This will work to get the child elements for each clsRainGaugeReading element. I am sure there are lots of cleaner ways to get them but it might put you on the right track :)

 

<?php


//$xml = new SimpleXML


$xml = SimpleXML_load_file('http://www.amecim.com/metronashvillewater/metronashvilleraingaugeservice.asmx/getAllGauges15m', 'SimpleXMLIterator');

$firstChildrenArray = array(); // going to hold parent elements
$secondChildArray = array(); // going to hold child elements of each clsRainGaugeReading

foreach($xml->children() as $child)
  {
  	$firstChildrenArray[] = $child->getName();
   }  
  
  foreach($firstChildrenArray as $v){
  
$secondChildArray[] =$xml->{$v}->clsRainGaugeReading->children();

  }
  echo "<pre>";
print_r($firstChildrenArray);
print_r($secondChildArray);


?>

Link to comment
Share on other sites

Well as i said, there may well be a better way to do it.

 

Not quite sure I follow your question. What do yo want to do?

 

 

So to break it out into two different arrays will work best?  Make sense.

 

Ok...brain dump here.  I believe my brain is fried now.  To list the matching first array item with the first array data fields, I need to add?

 

Thanks for your help!

Mike

Link to comment
Share on other sites

Oh wait I think i get you :)

 

try this:

 

<?php


//$xml = new SimpleXML


$xml = SimpleXML_load_file('http://www.amecim.com/metronashvillewater/metronashvilleraingaugeservice.asmx/getAllGauges15m', 'SimpleXMLIterator');

$firstChildrenArray = array(); // going to hold parent elements
$secondChildArray = array(); // going to hold child elements of each clsRainGaugeReading

foreach($xml->children() as $child)
  {
  	$firstChildrenArray[] = $child->getName();
   }  
  
  foreach($firstChildrenArray as $v){
  
$secondChildArray[$v] =$xml->{$v}->clsRainGaugeReading->children();

  }
  echo "<pre>";
print_r($firstChildrenArray);
print_r($secondChildArray);



 

That will give you an associative array that matches the parent element to the children.

 

You might want some logic in the foreach to handle null values too. For instance, "Brentwood" has no child elements so throws a warning.

 

 

So to break it out into two different arrays will work best?  Make sense.

 

Ok...brain dump here.  I believe my brain is fried now.  To list the matching first array item with the first array data fields, I need to add?

 

Thanks for your help!

Mike

Link to comment
Share on other sites

Thanks for your help Drongo_III!

 

What I am trying to do is pull in the data and format it in a line format to be ingested into our database.

 

What I would like to do is put the site and related data into one line at a time.

 

Fore example:

SITE      DATE        TIME  VALUE

BntCrk : 82712 DH1640/0

 

Does that make sense?

 

Thanks!

Mike

 

 

Link to comment
Share on other sites

Hey mate

 

If that's your purpose then I've tweaked the code slightly so you end up with a conventional array and not an array of xmlobjects (that in my my opinion are harder to access).

 

<?php


//$xml = new SimpleXML


$xml = SimpleXML_load_file('http://www.amecim.com/metronashvillewater/metronashvilleraingaugeservice.asmx/getAllGauges15m');

$firstChildrenArray = array(); // going to hold parent elements
$secondChildArray = array(); // going to hold child elements of each clsRainGaugeReading

foreach($xml->children() as $child)
  {
  	$firstChildrenArray[] = $child->getName();
   }  
   
  // cycle through parent elements array so we deal with each in turn
  foreach($firstChildrenArray as $v){

// now for every parent element get the object vars for each child element
foreach($xml->{$v}->clsRainGaugeReading  as $vv){
	$secondChildArray[] =  get_object_vars($vv); // add object var value to array

}

  }
  
  echo "<pre>";  // get rid of this line
  print_r($secondChildArray); // just to demonstrate end result
  
  echo "" . $secondChildArray[3]['SampleDate']  ;
?>

 

 

So as you can see in the very last echo line you can then access each entry as a multi-dimensional array, which you can then simply use in your insert statement for your database.

Link to comment
Share on other sites

http://www.amecim.com/metronashvillewater/metronashvilleraingaugeservice.asmx/getAllGaugesAllIntervals

 

The file above has 15 min, 30 minute, 1 hour, 2 hour, 4 hour, 6 hour and 24 values in this file.  The USGS prefers we source this to gather all intervals and data associated with that interval that we require.  This is really nice as it will be a one sources, yet the php code that we are working on slightly changes.  Could use some help.

 

Thanks!

Mike

Link to comment
Share on other sites

Ok I just edited the code and can get the 24 hour data.

 

<?php


//$xml = new SimpleXML


$xml = SimpleXML_load_file('http://www.amecim.com/metronashvillewater/metronashvilleraingaugeservice.asmx/getAllGaugesAllIntervals');

$firstChildrenArray = array(); // going to hold parent elements
$secondChildArray = array(); // going to hold child elements of each clsRainGaugeReading

foreach($xml->children() as $child)
  {
  	$firstChildrenArray[] = $child->getName();
   }  
   
  
  foreach($firstChildrenArray as $v){

foreach($xml->{$v}->TwentyfourHour  as $vv){
	$secondChildArray[] =  get_object_vars($vv);

}

  }
  
  echo "<pre>";  // get rid of this line
  print_r($secondChildArray); // just to demonstrate end result
  
  echo "" . $secondChildArray[3]['GaugeName']  ;
?>

Link to comment
Share on other sites

There is absolutely no need to create that array of "first children" names, only to use it to get the readings that you want.  There is also no need to loop over the readings once to get them into an array, then loop over them again in array form to do whatever you want with them.  It's all looking like doing unnecessary work.

 

$data_url = 'http://www.amecim.com/metronashvillewater/metronashvilleraingaugeservice.asmx/getAllGaugesAllIntervals';
$package  = new SimpleXMLElement($data_url, NULL, TRUE);

foreach($package->children() as $gauge) {
    $sample = $gauge->TwentyfourHour;
    // Access the data using the tag name
    // e.g. $sample->GaugeName
}

 

If you haven't already, have a good (re-)read through the SimpleXML Basic Usage manual page which has lots of examples and instructions.

 

The key take-home point, I think, is that you need to remember how the SimpleXML object structure relates to the XML structure.  For example, the first SimpleXMLElement object ($package) contains the <clsRainGaugeIntervalSetPackage> element.  Then we loop over its children(), which are the <BntCrk>, <Brentwood>, <GibsonCrk> ... elements.  For each of those children, we grab the <TwentyfourHour> element and then you are left to get the child elements for whichever bits of information you want (see the comment).

Link to comment
Share on other sites

Well that does look cleaner :/ I did say there was probably a better way...

 

And if you didn't like my last offering then you'll positively hate what I did to get the results for each timeslot.  I will go brush up on my simplexml i think...  :-\

 

 

Yeah three levels of foreach was probably never going to be a winner...

Link to comment
Share on other sites

Ok, to atone for providing such a long winded example, and as I've learned something from Salathe's super dooper example, here is a slimmed down version micahel that will produce a multidimensional array of all the time intervals:

 

<?php

$data_url = 'http://www.amecim.com/metronashvillewater/metronashvilleraingaugeservice.asmx/getAllGaugesAllIntervals';
$package  = new SimpleXMLElement($data_url, NULL, TRUE);

$topLevel = array();

foreach($package->children() as $k=>$gauge) {


$topLevel[$k] = array(

		'FifteenMinute'		=>get_object_vars($gauge->FifteenMinute), 
		'ThirtyMinute'		=>get_object_vars($gauge->ThirtyMinute), 
		'OneHour'				=>get_object_vars($gauge->OneHour), 
		'TwoHour'				=>get_object_vars($gauge->TwoHour), 
		'FourHour'			=>get_object_vars($gauge->FourHour), 
		'SixHour'				=>get_object_vars($gauge->SixHour), 
		'TwelveHour'			=>get_object_vars($gauge->TwelveHour), 
		'TwentyfourHour'	=>get_object_vars($gauge->TwentyfourHour)

	);

}


// topLevel should be an array of all your interval values
echo "<pre>";
print_r($topLevel);


?>

 

Hope that helps and sorry my first attempt to help was a bit...well...crap :)

Link to comment
Share on other sites

I guess you missed my entire point, there is no need to "convert" SimpleXMLElement objects into arrays (with get_object_vars(), casting, etc.) in order to use them. Learning how to work with SimpleXML will be much more beneficial than always working against it.  It is really only a baby step of difference between using nested arrays and using SimpleXMLElement objects.

Link to comment
Share on other sites

Well I am keen to be enlightened.

 

How would you suggest doing it?

 

For instance if I remove the get_object_vars from one of the nested arrays in the foreach I get an array as follows (this is just a snippet because the array is huge)

 

Array
(
    [bntCrk] => Array
        (
            [FifteenMinute] => SimpleXMLElement Object
                (
                    [sampleDate] => 8-28-2012
                    [sampleTime] => 17:0:17
                    [GaugeName] => BntCrk
                    [sampleValue] => 0
                )

            [ThirtyMinute] => Array
                (
                    [sampleDateStart] => 8-28-2012
                    [sampleDateEnd] => 8-28-2012
                    [sampleTimeStart] => 16:45:17
                    [sampleTimeEnd] => 17:0:17
                    [GaugeName] => BntCrk
                    [sampleValueAccumulation] => 0
                )

 

So the first nested array (FifteenMinute) is now an xml object. The second (ThirtyMinute) is a standard array because I've used get_object _vars to retrieve the values.

 

You've suggested using get_object_vars in this scenario is incorrect but it's now simple to access the values, e.g.:

 

echo $topLevel['BntCrk']['ThirtyMinute']['SampleDateStart'];

 

So it would be quite easy to use this in an insert statement.

 

But you've suggested this is wrong and it doesn't seem to be possible to do the following on the xml object nested array (probably because I can't seem to find out how you use the array when it's an xml object, so this is the bit i'm not getting):

 

echo $topLevel['BntCrk']['FifteenMinute']['SampleDateStart'];

 

So how do you access those values the proper way? Lets assume I want to insert that value into a database, or even simply echo it out.

 

I am keen to learn

Link to comment
Share on other sites

I see what you're saying there but lets say you want to get the children elements of FifteenMinutes, but each parent (e.g. FiftenMinutes, ThirtyMinutes etc.) has varying numbers of child elements.

 

In that instance you can't precisely name the child elements as with:

 

$start = (string) $gauge->FifteenMinute->SampleDateStart;

 

So if you wanted to fill a miltidimensional array with the child elements of each time interval how would you cast the values then?

Link to comment
Share on other sites

Well the desire is to iterate over the entire xml document and for each place name pull out the child elements of the intervals in a form that can be:

 

a) directly echoed to the page

b) stored in a database

 

The issue is if you have a variable number of child elements under each time interval you can't access the values directly (because you may not know what they are).

 

So what is the best method of extracting the values from the time interval child elements in a form that can be used as outlined above?

 

Sorry I don't mean to sound deliberately obtuse (or to be awkward), its just that using get_object_vars appears to do the above but you suggest it's incorrect. So I genuinely want to understand how it's possible to achieve the above without using get_object_vars or type casting if you don't know the end precise end element name.

Link to comment
Share on other sites

Well the desire is to iterate over the entire xml document and for each place name pull out the child elements of the intervals in a form that can be:

 

a) directly echoed to the page

b) stored in a database

 

The issue is if you have a variable number of child elements under each time interval you can't access the values directly (because you may not know what they are).

 

So what is the best method of extracting the values from the time interval child elements in a form that can be used as outlined above?

 

Sorry I don't mean to sound deliberately obtuse (or to be awkward), its just that using get_object_vars appears to do the above but you suggest it's incorrect. So I genuinely want to understand how it's possible to achieve the above without using get_object_vars or type casting if you don't know the end precise end element name.

 

SimpleXML provides iteration through the class. There's no reason to convert it to an array only to iterate through it.

 

Unknown values can be looped through.

 

<?php

$xml = new SimpleXMLElement('http://www.amecim.com/metronashvillewater/metronashvilleraingaugeservice.asmx/getAllGauges15m', 0, true);

header('content-type: text/plain');

foreach( $xml as $location => $data ) {
echo "$location\n";
foreach( $data->clsRainGaugeReading as $subdata ) {
	foreach( $subdata as $key => $value ) {
		echo "\t$key -> $value\n";
	}
}
}

?>

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.