How to get only required xpath elements? - php

I have an xml file that I want to store a node's rank attribute in a variable.
I tried:
echo $var = $xmlobj->xpath("//Listing[#rank]");
to no avail, it just prints ArrayArray.
How can this be done?
if($xmlobj = simplexml_load_string(file_get_contents($xml_feed)))
{
foreach($xmlobj as $listing)
{
// echo 'Session ID: ' . $sessionId = $listing->sessionId . '<br />';
// echo 'Result Set: ' . $ResultSet = $listing->ResultSet . '<br />';
print_r($xmlobj->xpath("//Listing[#rank]"));
// $result = $xmlobj->xpath("/page/");
// print_r($result);
}
}
Henrik's suggestion:
foreach($xmlobj as $listing)
{
$var = $xmlobj->xpath("//Listing[#rank]");
foreach ($var as $xmlElement)
{
echo (string)$xmlElement;
}
}
Here you go
<page>
<ResultSet id="adListings" numResults="3">
<Listing rank="1" title="Reliable Local Moving Company" description="TEST." siteHost="www.example.com">
</Listing>

Edit after playing around with the posted example xml:
My initial answer was somewhat off track - casting to string would give you the inner text of the selected elements, if they have one (not the case here)
"//Listing[#rank]" selects all 'Listing' Elements that have a 'rank' attribute. If you want to select the attributes themselves, use "//Listing/#rank"
To output an attribute, use the SimpleXMLElement with array syntax: $xmlElement['rank']
So in your case:
foreach($xmlobj as $listing)
{
$var = $xmlobj->xpath("//Listing/#rank");
foreach ($var as $xmlElement)
{
echo $xmlElement['rank'];
}
}
or
foreach($xmlobj as $listing)
{
$var = $xmlobj->xpath("//Listing[#rank]");
foreach ($var as $xmlElement)
{
echo $xmlElement['rank'];
echo $xmlElement['title']; // Added to demonstrate difference
}
}
should work.
In the first case, the $xmlElement would only contain the 'rank' attribute while in the second, it would contain the complete 'Listing' element (hence allowing the title output).

Related

how to create child nodes with php xpath query

Code is something like this:
$b = $xpath->query('//td[#class="abc"]');
foreach ($b as $b2) { /*contents*/ }
Inside td, this contents will be there:
<h2>Link Title
<span class="spanclass">Spinning</span></h3>
<div class="xyz">ABC XYZ abc xyz</div>
<span class="phr">Style</span>red
if i print/echo, "print_r ($b2->nodeValue);", content will be like this:
Link Title
Spinning
ABC XYZ abc xyz
Style red
Now tried, this code inside each $b2:
foreach ($xpath->query('.//a[#href]', $b2) as $child) {
print_r($child->nodeValue);
}
Answer is coming:
Link Title
I need this information from there:
$title = 'Link Title';
$titlelink = 'http://www.example.com';
$spanclassinfo = 'Spinning';
$stylerandom = 'red';
Any help?
Thanks in advance.
You should check if it has attributes with something like this.
Get all attributes in each element
foreach ($b as $b2) {
if ($b2->hasAttributes()) {
foreach ($p->attributes as $attr) {
$name = $attr->nodeName;
$value = $attr->nodeValue;
echo 'Attribute ' . $name . ' - ' . $value . '<br />';
}
}
}
Get specific attributes from an element
foreach ($b as $b2) {
if ($b2->hasAttributes()) {
$titlelink = $b2->attributes->getNamedItem('href')->value;
}
}
You'll need to add in some checks to make sure that the attribute you're trying to select actually exists. That way you're not trying to grab the href attribute on a span tag.

How to print jSON values with loop

I am using the following code to print the output of the jSON response but when I try to print
echo $obj->HotelListResponse->customerSessionId; // This is working.
echo $obj->HotelListResponse->HotelList->HotelSummary->name; // This is not working.
When the response contains only one node then its printing perfectly but when there are multiple nodes with same name then its not printing. I tried using foreach just like the below. I also tried using while loop but still I am unable to print the list of hotel names.
My jSON decoded output is like http://pastebin.com/Fr21DkEk
Total code:
$url = "https://api.eancdn.com/ean-services/rs/hotel/v3/list?cid=55505&minorRev=99&apiKey=cbrzfta369qwyrm9t5b8y8kf&locale=en_AU&currencyCode=AUD&xml=<HotelListRequest><city>Brisbane</city><stateProvinceCode>QLD</stateProvinceCode><countryCode>AU</countryCode><arrivalDate>10/16/2014</arrivalDate><departureDate>10/18/2014</departureDate><RoomGroup><Room><numberOfAdults>2</numberOfAdults></Room></RoomGroup><numberOfResults>25</numberOfResults></HotelListRequest>";
$json = file_get_contents($url);
$obj = json_decode($json);
foreach($obj as $val) {
echo $val->HotelListResponse->HotelList->HotelSummary->name;
}
Try this
foreach($obj->HotelListResponse->HotelList->HotelSummary as $val) {
echo $val->name . '<br/>';
}
HotelSummary is an array:
echo $val->HotelListResponse->HotelList->HotelSummary[0]->name;
If you want all of the hotel summaries:
foreach($obj as $val) {
foreach($val->HotelListResponse->HotelList->HotelSummary as $sum) {
echo $sum->name;
}
}
Yes you can directly access them inside the foreach. Like this:
foreach($obj->HotelListResponse->HotelList->HotelSummary as $val) {
// ^^
// since you're interested on just names, you can point it directly on that object, then each of that batch is in `$val`
echo $val->name . '<br/>';
}
// or start from the parent
foreach($obj as $values) {
$customerSessionId = $values->customerSessionId;
echo $customerSessionId . '<hr/>';
$hotelList = $values->HotelList;
foreach($hotelList->HotelSummary as $hotelsummary) {
echo $hotelsummary->name . '<br/>';
}
}

Pagination Filtered XML file

I want to paginate the following filtered results from xml file:
<?php
//load up the XML file as the variable $xml (which is now an array)
$xml = simplexml_load_file('inventory.xml');
//create the function xmlfilter, and tell it which arguments it will be handling
function xmlfilter ($xml, $color, $weight, $maxprice)
{
$res = array();
foreach ($xml->widget as $w)
{
//initially keep all elements in the array by setting keep to 1
$keep = 1;
//now start checking to see if these variables have been set
if ($color!='')
{
//if color has been set, and the element's color does not match, don't keep this element
if ((string)$w->color != $color) $keep = 0;
}
//if the max weight has been set, ensure the elements weight is less, or don't keep this element
if ($weight)
{
if ((int)$w->weight > $weight) $keep = 0;
}
//same goes for max price
if ($maxprice)
{
if ((int)$w->price > $maxprice) $keep = 0;
}
if ($keep) $res[] = $w;
}
return $res;
}
//check to see if the form was submitted (the url will have '?sub=Submit' at the end)
if (isset($_GET['sub']))
{
//$color will equal whatever value was chosen in the form (url will show '?color=Blue')
$color = isset($_GET['color'])? $_GET['color'] : '';
//same goes for these fellas
$weight = $_GET['weight'];
$price = $_GET['price'];
//now pass all the variables through the filter and create a new array called $filtered
$filtered = xmlfilter($xml ,$color, $weight, $price);
//finally, echo out each element from $filtered, along with its properties in neat little spans
foreach ($filtered as $widget) {
echo "<div class='widget'>";
echo "<span class='name'>" . $widget->name . "</span>";
echo "<span class='color'>" . $widget->color . "</span>";
echo "<span class='weight'>" . $widget->weight . "</span>";
echo "<span class='price'>" . $widget->price . "</span>";
echo "</div>";
}
}
Where $xml->widget represents the following xml:
<hotels xmlns="">
<hotels>
<hotel>
<noofrooms>10</noofrooms>
<website></website>
<imageref>oias-sunset-2.jpg|villas-agios-nikolaos-1.jpg|villas-agios-nikolaos-24​.jpg|villas-agios-nikolaos-41.jpg</imageref>
<descr>blah blah blah</descr>
<hotelid>119</hotelid>
</hotel>
</hotels>
</hotels>
Any good ideas?
Honestly if you're already using XML and want to do Pagination then use XSL. It'll allow for formatting of the results and for pagination with ease. PHP has a built in XSL transformer iirc
See http://www.codeproject.com/Articles/11277/Pagination-using-XSL for a decent example.

PHP: $_POST array to XML file and display results

I'm creating a "Madlibs" page where visitors can create funny story things online. The original files are in XML format with the blanks enclosed in XML tags
(Such as blablabla <PluralNoun></PluralNoun> blablabla <Verb></Verb> ).
The form data is created using XSL and the results are saved using a $_POST array. How do I post the $_POST array between the matching XML tags and then display the result to the page? I'm sure it uses a "foreach" statement, but I'm just not familiar enough with PHP to figure out what functions to use. Any help would be great.
Thanks,
E
I'm not sure if I understood your problem quite well, but I think this might help:
// mocking some $_POST variables
$_POST['Verb'] = 'spam';
$_POST['PluralNoun'] = 'eggs';
// original template with blanks (should be loaded from a valid XML file)
$xml = 'blablabla <PluralNoun></PluralNoun> blablabla <Verb></Verb>';
$valid_xml = '<?xml version="1.0"?><xml>' . $xml . '</xml>';
$doc = DOMDocument::loadXML($valid_xml, LIBXML_NOERROR);
if ($doc !== FALSE) {
$text = ''; // used to accumulate output while walking XML tree
foreach ($doc->documentElement->childNodes as $child) {
if ($child->nodeType == XML_TEXT_NODE) { // keep text nodes
$text .= $child->wholeText;
} else if (array_key_exists($child->tagName, $_POST)) {
// replace nodes whose tag matches a POST variable
$text .= $_POST[$child->tagName];
} else { // keep other nodes
$text .= $doc->saveXML($child);
}
}
echo $text . "\n";
} else {
echo "Failed to parse XML\n";
}
Here is PHP foreach syntax. Hope it helps
$arr = array('fruit1' => 'apple', 'fruit2' => 'orange');
foreach ($arr as $key => $val) {
echo "$key = $val\n";
}
and here is the code to loop thru your $_POST variables:
foreach ($_POST as $key => $val) {
echo "$key = $val\n";
// then you can fill each POST var to your XML
// maybe you want to use PHP str_replace function too
}

Need some help with XML parsing

The XML feed is located at: http://xml.betclick.com/odds_fr.xml
I need a php loop to echo the name of the match, the hour, and the bets options and the odds links.
The function will select and display ONLY the matchs of the day with streaming="1" and the bets type "Ftb_Mr3".
I'm new to xpath and simplexml.
Thanks in advance.
So far I have:
<?php
$xml_str = file_get_contents("http://xml.betclick.com/odds_fr.xml");
$xml = simplexml_load_string($xml_str);
// need xpath magic
$xml->xpath();
// display
?>
Xpath is pretty simple once you get the hang of it
you basically want to get every match tag with a certain attribute
//match[#streaming=1]
will work pefectly, it gets every match tag from underneath the parent tag with the attribute streaming equal to 1
And i just realised you also want matches with a bets type of "Ftb_Mr3"
//match[#streaming=1]/bets/bet[#code="Ftb_Mr3"]
This will return the bet node though, we want the match, which we know is the grandparent
//match[#streaming=1]/bets/bet[#code="Ftb_Mr3"]/../..
the two dots work like they do in file paths, and gets the match.
now to work this into your sample just change the final bit to
// need xpath magic
$nodes = $xml->xpath('//match[#streaming=1]/bets/bet[#code="Ftb_Mr3"]/../..');
foreach($nodes as $node) {
echo $node['name'].'<br/>';
}
to print all the match names.
I don't know how to work xpath really, but if you want to 'loop it', this should get you started:
<?php
$xml = simplexml_load_file("odds_fr.xml");
foreach ($xml->children() as $child)
{
foreach ($child->children() as $child2)
{
foreach ($child2->children() as $child3)
{
foreach($child3->attributes() as $a => $b)
{
echo $a,'="',$b,"\"</br>";
}
}
}
}
?>
That gets you to the 'match' tag which has the 'streaming' attribute. I don't really know what 'matches of the day' are, either, but...
It's basically right out of the w3c reference:
http://www.w3schools.com/PHP/php_ref_simplexml.asp
I am using this on a project. Scraping Beclic odds with:
<?php
$match_csv = fopen('matches.csv', 'w');
$bet_csv = fopen('bets.csv', 'w');
$xml = simplexml_load_file('http://xml.cdn.betclic.com/odds_en.xml');
$bookmaker = 'Betclick';
foreach ($xml as $sport) {
$sport_name = $sport->attributes()->name;
foreach ($sport as $event) {
$event_name = $event->attributes()->name;
foreach ($event as $match) {
$match_name = $match->attributes()->name;
$match_id = $match->attributes()->id;
$match_start_date_str = str_replace('T', ' ', $match->attributes()->start_date);
$match_start_date = strtotime($match_start_date_str);
if (!empty($match->attributes()->live_id)) {
$match_is_live = 1;
} else {
$match_is_live = 0;
}
if ($match->attributes()->streaming == 1) {
$match_is_running = 1;
} else {
$match_is_running = 0;
}
$match_row = $match_id . ',' . $bookmaker . ',' . $sport_name . ',' . $event_name . ',' . $match_name . ',' . $match_start_date . ',' . $match_is_live . ',' . $match_is_running;
fputcsv($match_csv, explode(',', $match_row));
foreach ($match as $bets) {
foreach ($bets as $bet) {
$bet_name = $bet->attributes()->name;
foreach ($bet as $choice) {
// team numbers are surrounded by %, we strip them
$choice_name = str_replace('%', '', $choice->attributes()->name);
// get the float value of odss
$odd = (float)$choice->attributes()->odd;
// concat the row to be put to csv file
$bet_row = $match_id . ',' . $bet_name . ',' . $choice_name . ',' . $odd;
fputcsv($bet_csv, explode(',', $bet_row));
}
}
}
}
}
}
fclose($match_csv);
fclose($bet_csv);
?>
Then loading the csv files into mysql. Running it once a minute, works great so far.

Categories