简体   繁体   中英

Using xpath the right way, with foreach function?

I have trouble to parse from xml (external url) file to php. Idea what I am trying to accomplish is that my.php script loads url and takes specific data from it -> parse them as variables and then use those variables to post them to my database (MySQL).

My problem (might be mistaken, because new with handling XML-data and pretty new with PHP) is with "foreach" loop. When I open my script it returns following data for me:

1
Array
Array
Array
2
Array
Array
Array
3

In final version of course (when I get this working), there isn't a point for me to print/echo those values, because those variables will be posted to my database. So that in mind I am doing this right now understand about the code and where the problem might rest.

$url = 'http://opendata.fmi.fi/wfs?service=WFS&version=2.0.0&request=getFeature&storedquery_id=fmi::observations::weather::daily::simple&place=tammela&starttime='.$first_image_date.'T00:00:00Z&endtime='.$last_image_date.'T01:00:00Z&parameters=tmin,tday,tmax&';

Original xml url = http://opendata.fmi.fi/wfs?service=WFS&version=2.0.0&request=getFeature&storedquery_id=fmi::observations::weather::daily::simple&place=tammela&starttime=2020-05-24T00:00:00Z&endtime=2020-05-31T01:00:00Z&parameters=tmin,tday,tmax&

The following variable is where I take the XML-data from. Only thing which changes (whenever php is going to be used) are $first_image_date and $last_image_date . So basic idea is that I have images on my server and right now I have 9 different of images (all of them are.jpg format) and.php code takes dates from those images and matches with XML-data.

If new images get uploaded/transfered to my server, it means same time that $url variable will fetch data with updated date linked to the url.

<?php

$folder_location = "AarniAnsa/*/*/";
$jpg = glob("" . $folder_location . "*.jpg");

$first_image = reset($jpg);
$last_image = end($jpg);

ob_start();
print end(explode('@',$first_image,-2));
$first_image_date = ob_get_contents();
ob_end_clean();

ob_start();
print end(explode('@',$last_image,-2));
$last_image_date = ob_get_contents();
ob_end_clean();

define('DB_SERVER', '***');
define('DB_USERNAME', '***');
define('DB_PASSWORD', '***');
define('DB_NAME', '***');

$link = mysqli_connect(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);

if($link === false) {
  die("ERROR: Could not connect. " . mysqli_connect_error());
}

// Alla oleva linkki antaa pelkästään meille tmin (Alin lämpötila), tday (Keskilämpötila) sekä tmax (Ylin lämpötila) arvot. Muita muuttujia emme tarvitse.
$url = 'http://opendata.fmi.fi/wfs?service=WFS&version=2.0.0&request=getFeature&storedquery_id=fmi::observations::weather::daily::simple&place=tammela&starttime='.$first_image_date.'T00:00:00Z&endtime='.$last_image_date.'T01:00:00Z&parameters=tmin,tday,tmax&';
$xml = simplexml_load_file($url);
$xmlID = 0;

$xml->registerXPathNamespace('wfs', 'http://www.opengis.net/wfs/2.0');
$xml->registerXPathNamespace('BsWfs', 'http://xml.fmi.fi/schema/wfs/2.0');

foreach ($xml->xpath('//wfs:member/BsWfs:BsWfsElement') as $xmlData) {
  $xmlID++;
  echo $xmlID;
  echo "<br>";
  $xmlDate = $xmlData->xpath('BsWfs:Time');
  echo $xmlDate;
  echo "<br>";
  $xmlName = $xmlData->xpath('BsWfs:ParameterName');
  echo $xmlName;
  echo "<br>";
  $xmlValue = $xmlData->xpath('BsWfs:ParameterValue');
  echo $xmlValue;
  echo "<br>";


  $query = "INSERT INTO Kaavio(ID,Päivämäärä,Parametri,Arvo) VALUES ('" . $xmlID . "','" . $xmlDate . "','" . $xmlName . "','" . $xmlValue . "')";

  $result = mysqli_query($link, $query);
}

 ?>

Now I am using "xpath", is because to my understanding (what I have learned so far) is that if I use SimpleXML option, it doesn't like data which has "prefixes". And this XML-data containes on every element some of the "prefix" tags. Thats why I was using "registerXPathNamespace" function, but hasn't solved my problem yet.

If you are wondering why I am using following code, is because all of my images format goes like this: @AnsaID-20@2020-05-31@19:55:36@.jpg:)

ob_start();
print end(explode('@',$first_image,-2));
$first_image_date = ob_get_contents();
ob_end_clean();

Thanks for the help in advance! <3

Edit1 (for XML-data, even though there was link for it):

<wfs:FeatureCollection xmlns:wfs="http://www.opengis.net/wfs/2.0" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:BsWfs="http://xml.fmi.fi/schema/wfs/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" timeStamp="2020-06-24T20:12:30Z" numberReturned="24" numberMatched="24" xsi:schemaLocation="http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd http://xml.fmi.fi/schema/wfs/2.0 http://xml.fmi.fi/schema/wfs/2.0/fmi_wfs_simplefeature.xsd">
<wfs:member>
<BsWfs:BsWfsElement gml:id="BsWfsElement.1.1.1">
<BsWfs:Location>
<gml:Point gml:id="BsWfsElementP.1.1.1" srsDimension="2" srsName="http://www.opengis.net/def/crs/EPSG/0/4258">
<gml:pos>60.81401 23.49761 </gml:pos>
</gml:Point>
</BsWfs:Location>
<BsWfs:Time>2020-05-24T00:00:00Z</BsWfs:Time>
<BsWfs:ParameterName>tmin</BsWfs:ParameterName>
<BsWfs:ParameterValue>8.2</BsWfs:ParameterValue>
</BsWfs:BsWfsElement>
</wfs:member>
<wfs:member>
<BsWfs:BsWfsElement gml:id="BsWfsElement.1.1.2">
<BsWfs:Location>
<gml:Point gml:id="BsWfsElementP.1.1.2" srsDimension="2" srsName="http://www.opengis.net/def/crs/EPSG/0/4258">
<gml:pos>60.81401 23.49761 </gml:pos>
</gml:Point>
</BsWfs:Location>
<BsWfs:Time>2020-05-24T00:00:00Z</BsWfs:Time>
<BsWfs:ParameterName>tday</BsWfs:ParameterName>
<BsWfs:ParameterValue>11.1</BsWfs:ParameterValue>
</BsWfs:BsWfsElement>
</wfs:member>
<wfs:member>
<BsWfs:BsWfsElement gml:id="BsWfsElement.1.1.3">
<BsWfs:Location>
<gml:Point gml:id="BsWfsElementP.1.1.3" srsDimension="2" srsName="http://www.opengis.net/def/crs/EPSG/0/4258">
<gml:pos>60.81401 23.49761 </gml:pos>
</gml:Point>
</BsWfs:Location>
<BsWfs:Time>2020-05-24T00:00:00Z</BsWfs:Time>
<BsWfs:ParameterName>tmax</BsWfs:ParameterName>
<BsWfs:ParameterValue>14.3</BsWfs:ParameterValue>
</BsWfs:BsWfsElement>
</wfs:member>

Edit2 (adding now "partially working" code, but with a MySQL problem)

<?php

$folder_location = "AarniAnsa/*/*/";
$jpg = glob("" . $folder_location . "*.jpg");

$first_image = reset($jpg);
$last_image = end($jpg);

ob_start();
print end(explode('@',$first_image,-2));
$first_image_date = ob_get_contents();
ob_end_clean();

ob_start();
print end(explode('@',$last_image,-2));
$last_image_date = ob_get_contents();
ob_end_clean();

define('DB_SERVER', '***');
define('DB_USERNAME', '***');
define('DB_PASSWORD', '***');
define('DB_NAME', '***');

$link = mysqli_connect(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);

if($link === false) {
  die("ERROR: Could not connect. " . mysqli_connect_error());
}

// Alla oleva linkki antaa pelkästään meille tmin (Alin lämpötila), tday (Keskilämpötila) sekä tmax (Ylin lämpötila) arvot. Muita muuttujia emme tarvitse.
$url = 'http://opendata.fmi.fi/wfs?service=WFS&version=2.0.0&request=getFeature&storedquery_id=fmi::observations::weather::daily::simple&place=tammela&starttime='.$first_image_date.'T00:00:00Z&endtime='.$last_image_date.'T01:00:00Z&parameters=tmin,tday,tmax&';
$xml = simplexml_load_file($url);
$xmlID = 0;

$xml->registerXPathNamespace('wfs', 'http://www.opengis.net/wfs/2.0');
$xml->registerXPathNamespace('BsWfs', 'http://xml.fmi.fi/schema/wfs/2.0');

foreach ($xml->xpath('//wfs:member/BsWfs:BsWfsElement') as $xmlData) {
  $xmlID++;
  echo $xmlID;
  echo "<br>";
  $xmlDate = (string)$xmlData->xpath('BsWfs:Time')[0];
  echo $xmlDate;
  echo "<br>";
  $xmlName = (string)$xmlData->xpath('BsWfs:ParameterName')[0];
  echo $xmlName;
  echo "<br>";
  $xmlValue = (string)$xmlData->xpath('BsWfs:ParameterValue')[0];
  echo $xmlValue;
  echo "<br>";

  $sql = "INSERT INTO Kaavio(Päivämäärä, Parametri, Arvo) VALUES('$xmlDate', '$xmlName', '$xmlValue')";
  mysqli_query($link, $sql) or die(mysqli_error($link));

}

 ?>

Following code is making this error and I have checked that database settings are right 100% so problem can't be with that and also I have tried to replace php variables with normal text (such as 'testi' or 'aarni') and that didn't worked either.

1
2020-05-24T00:00:00Z
tmin
8.2
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '�ivämäärä, Parametri, Arvo) VALUES('2020-05-24T00:00:00Z', 'tmin...' at line 1

Edit3 (fixed all the problems I had previously and adding the whole code here, so in future if someone has similar problem they can just copy/paste it)

<?php

$folder_location = "AarniAnsa/*/*/";
$jpg = glob("" . $folder_location . "*.jpg");

$first_image = reset($jpg);
$last_image = end($jpg);

ob_start();
print end(explode('@',$first_image,-2));
$first_image_date = ob_get_contents();
ob_end_clean();

ob_start();
print end(explode('@',$last_image,-2));
$last_image_date = ob_get_contents();
ob_end_clean();

define('DB_SERVER', '***');
define('DB_USERNAME', '***');
define('DB_PASSWORD', '***');
define('DB_NAME', '***');

$link = mysqli_connect(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);

if($link === false) {
  die("ERROR: Could not connect. " . mysqli_connect_error());
}

// Alla oleva linkki antaa pelkästään meille tmin (Alin lämpötila), tday (Keskilämpötila) sekä tmax (Ylin lämpötila) arvot. Muita muuttujia emme tarvitse.
$url = 'http://opendata.fmi.fi/wfs?service=WFS&version=2.0.0&request=getFeature&storedquery_id=fmi::observations::weather::daily::simple&place=tammela&starttime='.$first_image_date.'T00:00:00Z&endtime='.$last_image_date.'T01:00:00Z&parameters=tmin,tday,tmax&';
$xml = simplexml_load_file($url);

$xml->registerXPathNamespace('wfs', 'http://www.opengis.net/wfs/2.0');
$xml->registerXPathNamespace('BsWfs', 'http://xml.fmi.fi/schema/wfs/2.0');

foreach ($xml->xpath('//wfs:member/BsWfs:BsWfsElement') as $xmlData) {
  $xmlDate = (string)$xmlData->xpath('BsWfs:Time')[0];
  $xmlDate = substr($xmlDate,0,10);
  echo $xmlDate;
  echo "<br>";
  $xmlName = (string)$xmlData->xpath('BsWfs:ParameterName')[0];
  echo $xmlName;
  echo "<br>";
  $xmlValue = (string)$xmlData->xpath('BsWfs:ParameterValue')[0];
  echo $xmlValue;
  echo "<br>";

  $sql = "INSERT INTO `Kaavio` (`date`, `parameter`, `value`) VALUES('$xmlDate', '$xmlName', '$xmlValue')";
  $result = mysqli_query($link, $sql);
}

 ?>

This is now, how my array is looking/showing when I open my.php script:

2020-05-24
tmin
8.2
2020-05-24
tday
11.1
2020-05-24
tmax
14.3
2020-05-25
tmin
8.0
2020-05-25
tday
13.0
2020-05-25
tmax
18.2
2020-05-26
tmin
4.6
2020-05-26
tday
14.9

And this is how my phpMyAdmin looks (using MariaDB):

XML Data parsed to my database:)

You will need to register the namespace on any element you call the xpath() method on. In you case you should to register the http://xml.fmi.fi/schema/wfs/2.0 on the $xmlData variable inside the loop.

Additionally SimpleXMLElement::xpath() return an array of SimpleXMLElement instance. To fetch a single value reference the first element and cast it:

$xmlDate = (string)$xmlData->xpath('BsWfs:Time')[0];

Only DOMxpath::evaluate() is able to return scalar values directly. The type cast is part of the expression. Here is an example:

$document = new DOMDocument();
$document->loadXML(getXMLString());
$xpath = new DOMXpath($document);
$xpath->registerNamespace('wfs', 'http://www.opengis.net/wfs/2.0');
$xpath->registerNamespace('BsWfs', 'http://xml.fmi.fi/schema/wfs/2.0');

foreach ($xpath->evaluate('//wfs:member/BsWfs:BsWfsElement') as $index => $element) {
    var_dump(
        [
             'id' => $index + 1,
             'date' => $xpath->evaluate('string(BsWfs:Time)', $element),
             'name' => $xpath->evaluate('string(BsWfs:ParameterName)', $element),
             'value' => $xpath->evaluate('number(BsWfs:ParameterValue)', $element)
        ]
    );
}

Output:

array(4) {
  ["id"]=>
  int(1)
  ["date"]=>
  string(20) "2020-05-24T00:00:00Z"
  ["name"]=>
  string(4) "tmin"
  ["value"]=>
  float(8.2)
}
array(4) {
  ["id"]=>
  int(2)
  ["date"]=>
  string(20) "2020-05-24T00:00:00Z"
  ["name"]=>
  string(4) "tday"
  ["value"]=>
  float(11.1)
}
array(4) {
  ["id"]=>
  int(3)
  ["date"]=>
  string(20) "2020-05-24T00:00:00Z"
  ["name"]=>
  string(4) "tmax"
  ["value"]=>
  float(14.3)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM