Simplexml : xpath with three conditions - php

I have a xml file like this :
<rss version="2.0" xmlns:atom="https://www.w3.org/2005/Atom">
<channel>
<item>
<city>London</city>
<description>Trip</description>
<link>page.php</link>
<img>img.jpg</img>
</item>
<item>
<city>London</city>
<description>Trip</description>
<link>page.php</link>
<img>img.jpg</img>
</item>
<item>
<city>Paris</city>
<description>Trip</description>
<link>page.php</link>
<img>img.jpg</img>
</item>
.
.
</channel>
</rss>
If I want to select TRIP in LONDON, I do that :
<?php
$xml = simplexml_load_file('file.xml');
$items = $xml->xpath('//item[city[contains(.,"London")] and description[contains(.,"Trip")]]');
foreach($items as $item){
echo ' txt ';
}
?>
If I want to select ONLY the first TRIP in LONDON, I do that :
<?php
$xml = simplexml_load_file('file.xml');
$items = $xml->xpath('//item[city[contains(.,"London")] and description[contains(.,"Trip")]]')[0];
foreach($items as $item){
echo ' txt ';
}
?>
I try also 1 instead of 0, and this
[position()=0]
it does not work.
What's wrong ?
I keep looking.
I have made several tests only with the position filter, for example :
<?php
$xml = simplexml_load_file('site-alpha.xml');
$items = $xml->xpath('//(/item)[1]');
foreach($xml->channel->item as $item){
echo '<div>....</div>';
}
?>
And it doesn't work.
I think I have a problem with this part, but I don't see where.

<?php
// Load the XML file
$xml = simplexml_load_file('your_xml_file.xml');
// Iterate through each "item" element
foreach ($xml->item as $item) {
// Output the description and city
echo $item->description . ' in ' . $item->city . '<br>';
}
?>

Unlike php, xpath indexing start from "1".
So either of these should get you only the first trip:
#indexing is indicated inside the xpath expression so it starts with 1:
$items = $xml->xpath('//item[city[contains(.,"London")] and description[contains(.,"Trip")]][1]');
or
#indexing is indicated outside the xpath expression so it's handled by php and starts with 0:
$items = $xml->xpath('//item[city[contains(.,"London")] and description[contains(.,"Trip")]]')[0];

Related

How to get a specific child from an XML file and show its children on a div with PHP

So, I have an XML file that looks like this (The names are fictional):
<myxmlfile>
<infos>
<item>
<itemChild1>foo1</itemChild1>
<itemChild2>foo2</itemChild2>
</item>
<item>
<itemChild1>foo1</itemChild1>
<itemChild2>foo2</itemChild2>
</item>
<item>
<itemChild1>foo1</itemChild1>
<itemChild2>foo2</itemChild2>
</item>
<item>...</item>
<item>...</item>
<item>...</item>
<item>...</item>
<item>...</item>
<item>...</item>
<infos>
</myxmlfile>
My goal is to take for example ONLY the third <item>, and show on my browser its children. How can I achieve that?
So far I have this:
PHP
<?php
$divId = 0;
$url ='myxml.xml';
$xml = simplexml_load_file($url) or die ("Can't connect to URL");
?>
The simplest way to access the node values of your XML would be to use the object operator plus your node name e.g. $xml->myxmlfile
$xml_data = '
<myxmlfile>
<infos>
<item>foo1</item>
<item>foo2</item>
<item>foo3</item>
<item>foo4</item>
<item>foo5</item>
</infos>
</myxmlfile>
';
$xml = new SimpleXMLElement($xml_data);
foreach($xml->infos->item as $k=>$v) {
echo $v . '<br>';
}
Output:
foo1
foo2
foo3
foo4
foo5
See: http://php.net/manual/en/book.simplexml.php
I'd suggest you to use DOM extension with XPath queries. Your question doesn't exactly state what you're trying to achieve, so here's a couple of examples:
$doc = new DOMDocument();
$doc->loadXML($xml);
$xpath = new DOMXPath($doc);
// query 3rd item and get the first match
$item = $xpath->query("/myxmlfile/infos/item[3]")->item(0);
// dump item as an XML
echo $doc->saveXML($item) . "\n";
// iterate all children of the item and work with nodes directly
foreach ($xpath->query("./*", $item) as $node) {
printf("%s has a value of %s\n", $node->nodeName, $node->nodeValue);
}
// iterate all children and dump nodes as an HTML
foreach ($xpath->query("./*", $item) as $node) {
echo $doc->saveHTML($node) . "\n";
}
This prints the following:
<item>
<itemChild1>foo1</itemChild1>
<itemChild2>foo2</itemChild2>
</item>
itemChild1 has a value of foo1
itemChild2 has a value of foo2
<itemChild1>foo1</itemChild1>
<itemChild2>foo2</itemChild2>

Getting a specific part from XML

I am trying to get the PAY where it has the ID 3 Where it says the label phone
but i really dont know how, i tried everything.
Thanks for helping!
Here is the XML code:
$books = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<data>
<login>1</login>
<arrStatsData>
<item>
<Id>500</Id>
<Label>website_name</Label>
<Data>
<item>
<Id>4</Id>
<Label>transactions</Label>
<Data>
<sum>2029.34</sum>
<cst>47.67575</cst>
<num>86</num>
<avg>23.6</avg>
<pay>1981.66</pay>
</Data>
</item>
<item>
<Id>3</Id>
<Label>Phone</Label>
<Data>
<sum>205</sum>
<cst>17.353</cst>
<num>205</num>
<avg>1</avg>
<pay>187.647</pay>
</Data>
</item>
......
PHP Code:
$xml = simplexml_load_string($arrResult); //load xml from above
foreach($xml->arrStatsData->item->Data as $item)
{
foreach($item->item as $DATA)
{
echo $DATA->Id.'<br>';
}
My result now is:
1981.66
187.647
-0.4448
Since you know some information that's tell the node apart from the rest you can use XPath to get the value directly instead of iterating through all of them:
<?php
$sxe = new SimpleXMLElement($books);
$pay = $sxe->xpath('//item[./Id=3]/Data/pay');
echo (string) $pay[0];
Ouput:
187.647
Your PHP code would be like this:
$xml = simplexml_load_string($books);
foreach($xml->arrStatsData->item->Data as $item)
{
//echo '$item;';
foreach($item->item as $DATA)
{
if($DATA->Id == '3'){
echo $DATA->Data->pay."<br/>";
}
}
}
It retrieve the pay value when the ID is equals to 3.
Rolando Isidoro was faster to recommend xpath, my solution is slightly different, that's why I post it, too:
$pay = (string)$xml->xpath("//item[Id = '3']/Data/pay")[0];
echo $pay;
see it working: http://codepad.viper-7.com/qzPlmp

XPATH Get Multiple Values within same Element in an RSS Feed

I have an rss feed that is formatted something like this:
<item>
<posturl>mysite.com/abc.html</posturl>
<imagepath>123.jpg</imagepath>
</item>
<item>
<posturl>mysite.com/def.html</posturl>
<imagepath>456.jpg</imagepath>
</item>
<item>
<posturl>mysite.com/ghi.html</posturl>
<imagepath>789.jpg</imagepath>
</item>
I have a script where I want to extract both the values above. I can extract one of the values and build html code using code like:
<?php
$xml = simplexml_load_file('http://myrssfeed.com');
$imgs = $xml->xpath('//imagepath');
echo '<ul>';
foreach($imgs as $output1) {
echo '<li><img src="' . $output1 . '" ></li>';
}
echo '</ul>';
?>
This works like a charm thanks to all the help from people here. But I need to expand that second echo line to read something like:
echo '<li><img src="' . $output1 . '" ></li>';
I need help on how to extract $output2 = posturl within the same item as $output1.
Basically I need to display the images as links... both imagepath and posturl are elements within item.
Many thanks.
You could select the <item> elements instead of <posturl> and <imagepath>. Like this:
$xml = simplexml_load_file('http://myrssfeed.com');
echo '<ul>';
foreach($xml->xpath('//item') as $item) {
printf('<li><img src="%s" /></li>',
$item->posturl, $item->imagepath);
}
echo '</ul>';

PHP SimpleXML XPath get next parent node

I've never asked a question here before so please forgive my question if its formatted badly or not specific enough. I am just a dabbler and know very little about PHP and XPath.
I have an XML file like this:
<catalogue>
<item>
<reference>A1</reference>
<title>My title1</title>
</item>
<item>
<reference>A2</reference>
<title>My title2</title>
</item>
</catalogue>
I am pulling this file using SimpleXML:
$file = "products.xml";
$xml = simplexml_load_file($file) or die ("Unable to load XML file!");
Then I am using the reference from a URL parameter to get extra details about the 'item' using PHP:
foreach ($xml->item as $item) {
if ($item->reference == $_GET['reference']) {
echo '<p>' . $item->title . '</p>';
}
So from a URL like www.mysite.com/file.php?reference=A1
I would get this HTML:
<p>My title1</p>
I realise I might not be doing this right and any pointers to improving this are welcome.
My question is, I want to find the next and previous 'item' details. If I know from the URL that reference=A1, how do I find the reference, title etc of the next 'item'? If I only have 'A1' and I know that's a reference node, how do I get HTML like this:
<p>Next item is My title2</p>
I have read about following-sibling but I don't know how to use it. I can only find the following-sibling of the reference node, which isn't what I need.
Any help appreciated.
You could use:
/catalogue/item[reference='A1']/following-sibling::item[1]/title
Meaning: from an item element child of catalogue root element, having a reference element with 'A1' string value, navegate to first following sibling item element's title child.
I´d probably use xpath to fetch the next/previous (and current) node.
<?php
error_reporting(E_ALL ^ E_NOTICE);
$s = '
<catalogue>
<item>
<reference>A1</reference>
<title>My title1</title>
</item>
<item>
<reference>A2</reference>
<title>My title2</title>
</item>
<item>
<reference>A3</reference>
<title>My title3</title>
</item>
</catalogue>
';
$xml = simplexml_load_string($s);
$reference = 'A3';
list($current) = $xml->xpath('/catalogue/item[reference="' . $reference . '"]');
if($current) {
print 'current: ' . $current->title . '<br />';
list($prev) = $current->xpath('preceding-sibling::*[1]');
if($prev) {
print 'prev: ' . $prev->title . '<br />';
}
list($next) = $current->xpath('following-sibling::*[1]');
if($next) {
print 'next: ' . $next->title . '<br />';
}
}
See the documentation of SimpleXMLElement::xpath and XPath syntax documentation.

Parsing an XML with Xpath in PHP

Consider the following code :
$dom = new DOMDocument();
$dom->loadXML($file);
$xmlPath = new DOMXPath($dom);
$arrNodes = $xmlPath->query('*/item');
foreach($arrNodes as $item){
//missing code
}
The $file is an xml and each item has a title and a description.
How can I display them (title and description)?
$file = "<item>
<title>test_title</title>
<desc>test</desc>
</item>";
I suggest using php's simplexml, with that, you still get xpath functionality, but with easier approach, for example you would access attributes like this:
$name = $item['name'];
Here's an example:
xmlfile.xml:
<?xml version="1.0" encoding="UTF-8"?>
<xml>
<items>
<item title="Hello World" description="Hellowing the world.." />
<item title="Hello People" description="greeting people.." />
</items>
</xml>
do.php:
<?php
$xml_str = file_get_contents('xmlfile.xml');
$xml = new SimpleXMLElement($xml_str);
$items = $xml->xpath('*/item');
foreach($items as $item) {
echo $item['title'], ': ', $item['description'], "\n";
}
If your item looks like this:
<item>
<title>foo</title>
<description>frob</description>
</item>
You could use getElementsByTagName() and nodeValue:
foreach($arrNodes as $item){
print $item->getElementsByTagName('title')->item(0)->nodeValue;
}
Are title and description attributes? E. g. does an item look like this:
<item title="foo" description="frob" />
If so, you could just use getAttribute():
...
foreach($arrNodes as $item){
print $item->getAttribute('title');
}
The right XPath expression should be:
/*/item/title | /*/item/desc
Or
/*/item/*[self::title or self::desc]
This is evaluate to a node set with title and desc element in document order

Categories