Can this iteration through a XML be rewritten? - php

I have below code to iterate through a xml file.
$nodelist = $xml->getElementsByTagName('cv');
foreach ($nodelist as $node) {
$naam = $node->getElementsByTagName('naam');
$naamid = $naam->item(0)->nodeValue;
}
It there a way to get the value in one line?
$nodelist = $xml->getElementsByTagName('cv');
foreach ($nodelist as $node) {
$naamid = <a one line to get the nodevalue of naam out of the xml>;
}

You could even do the entire program on one line, using Generators you could create a one-liner function which gets all instances of the naam element:
// Returns a generator which gets all elements with 'naam'
function getNaamElements()
{
foreach ($xml->getElementsByTagName('cv') as $node)
{
yield $node->getElementsByTagName('naam')->item(0)->nodeValue;
}
}
// To get an array:
$array = iterator_to_array(getNaamElements());
// To loop over all 'naam' elements in another loop, use the generator instead
foreach (getNaamElements() as $naam)
{
// Do stuff with $naam
}

Related

Can I put new values in array inide foreach?

I have a foreach loop, in which I loop through the array. I want to add elements as I go through it and have new ones go through it as well.
Now with this code it only does the iterations that I have in the array at the beginning (1 in this case).
Can somebody help me
Thanks
public static function getDirectoriesChilds($id_parent, $parents_array) {
$session_client = Client::getSessionClient();
array_push($parents_array, $id_parent);
$parents_array = array_unique($parents_array);
foreach ($parents_array as $element) {
$childs = Directory::where('id_parent' , '=', $element)->get();
foreach ($childs as $child) {
if ($child->deleted == Controller::DISABLED) {
array_push($parents_array, $child->id);
$parents_array = array_unique($parents_array);
}
}
}
return $parents_array;
}
If changes foreach to for works.
for($i=0; $i<count($parents_array); $i++){

passing more then one path to xPath query

I have links with a different paths, and trying retrieve data from those links. So I don't want to do it separate. Made a query list, and used foreach on that list.
function passPath($list){
$list = [
"//li[#class='out']/a[1]",
"//ul[#class='ul right_ul clearfix']/li[2]/a",
"//ul[#class='ul right_ul clearfix']/li[2]/a"
];
foreach($list as $val){
return $val;
}
}
Then used that function inside DOMXpath's query.
function getPath($urls){
foreach($urls as $k => $val){
$url = $urls;
$html = content($val);
$path = new \DOMXPath($html);
$xPath = passPath($val);
$route = $path->query($xPath);
foreach($route as $value){
if ($value->nodeValue != false) {
$urls [] = trim($value->getAttribute('href'));
unset($urls[$k]);
}
}
}
return array_unique($urls);
}
it's running without an error. But there is foreach problem here. because it's just retrieving one element's data. not keep going other elements... What I am missing here?
$data = getPath($urls)
var_dump($data)
by the way: content() is file_get_content/loadHTML function.
I changed your code for earning list of href.
# You want to parse all pages using url list. So you created function named `getPath($urls)`.
function getPath($urls) {
# I suggest you'd rather declare $ret for storing values to return.
$ret = [];
# Using foreach, you can parse all url.
foreach ($urls as $k => $url) { # $val is url value of $urls. And I changed $val to $url.
# content() is file_get_content/loadHTML function.
$html = content($url);
# Create new DOMXPath object using $html.
$path = new \DOMXPath($html);
# This function is not required.
# By the way, second element and third element of $xPathList are equal. I think the third element is not required.
// $xPath = passPath($url);
$xPathList = [
"//li[#class='out']/a[1]",
"//ul[#class='ul right_ul clearfix']/li[2]/a",
"//ul[#class='ul right_ul clearfix']/li[2]/a"
];
foreach ($xPathList as $xPath) {
$nodes = $path->query($xPath);
foreach ($nodes as $node) {
if ($node->nodeValue != false) {
$ret[] = trim($node->getAttribute('href'));
}
}
}
}
return array_unique($ret);
}
$data = getPath($urls);
var_dump($data);

Parse DOM document to array php

*
What I want is, for the DOM to instead of printing the results line by line in a "foreach" loop, rather store it in an array.... So it should look like a list i.e.
"[0] 16GB USB Stick" "[1] Computer monitor" "[2] wireless keyboard"
etc etc
So far I have this, but it only stores the last value from the for each loop.. Please help!
*
$html = new DOMDocument();
#$html->loadHtmlFile('some online shop');
$xpath = new DOMXPath($html);
$nodelist = $xpath->query( "//div[#class='productname']/p" );
foreach ($nodelist as $n)
{
$value = $n->nodeValue;
$list = array($value);
}
echo $list[0];
That's because you're overriding it in each loop. Create an array, and add to that array:
$list = array();
foreach ($nodelist as $n)
{
$value = $n->nodeValue;
$list[] = $value;
}
// Check there's at least one item in the array before accessing it
if (count($list) > 0)
{
echo $list[0];
}
You need to look into how arrays work in PHP. What you're doing wrong is you are re-declaring the array on each iteration, instead of adding more information to it.
$list = array();
foreach ($nodelist as $n) {
$list[] = $n->nodeValue;
}
var_dump($list);
Explanation:
[] basically means - add an item in this array, and auto generate the key.
The foreach I wrote is equivalent to this one:
$i = 0;
foreach ($nodelist as $n) {
$list[$i] = $n->nodeValue;
$i ++;
}

How to use array_unique correctly to echo only one time the same posts

I am trying to display the posts of some RSS Feeds and I came up with a question/problem I have, when I have two same feeds I am trying to show not all the posts but the unique. What I was using is this, that shows me all the posts twice (this is logical)
<?php
$feeds = array(
'feed.xml', 'feed.xml'
);
// Get all feed entries
$entries = array();
foreach ($feeds as $feed) {
$xml = simplexml_load_file($feed);
$entries = array_merge($entries, $xml->xpath('/rss/channel//item'));
}
// Sort feed entries by pubDate (ascending)
usort($entries, 'mysort');
function mysort($x, $y) {
return strtotime($y->pubDate) - strtotime($x->pubDate);
}
foreach ($entries as $entry) {
echo $entry->title;
echo "<br>";
}
?>
but when I changed that line to
$entries = array_unique(array_merge($entries, $xml->xpath('/rss/channel//item')));
I get only one post shown.
How can I correctly show the posts only once? Thank you.
Update:
function mysort($x, $y) {
return strtotime($y->pubDate) - strtotime($x->pubDate);
}
$feeds = array( 'http://feeds.bbci.co.uk/news/world/rss.xml',
'http://feeds.bbci.co.uk/news/world/rss.xml'
);
// Get all feed entries
$entries = array();
foreach ($feeds as $feed) {
$xml = simplexml_load_file($feed);
$entries = array_merge($entries, $xml->xpath('/rss/channel//item'));
}
$uniqueEntries = array();
foreach ($entries as $entry) {
$uniqueEntries[(string)$entry->title] = $entry;
}
// Sort feed entries by pubDate (ascending)
usort($entries, 'mysort');
foreach ($uniqueEntries as $entry) {
echo $entry->title;
echo "<br>";
}
From the documentation of array_unique
Note: Two elements are considered equal if and only if (string) $elem1
=== (string) $elem2. In words: when the string representation is the same. The first element will be used.
In this case, the objects you're getting out of the XPath query translate to string form like "SimpleXML object" (not exactly like that, but the exact representation is not important). According to the above rules, then, every element looks exactly the same to array_unique.
Unfortunately, there's no way to make array_unique behave the way you want, so you will need to fake it yourself:
$feeds = array(
'myfeed.xml', 'myfeed.xml'
);
// Get all feed entries
$entries = array();
foreach ($feeds as $feed) {
$xml = simplexml_load_file($feed);
$tmp = $xml->xpath('/rss/channel//item');
foreach ($tmp as $item) {
if(!in_array($tmp, $entries)) {
$entries[] = $tmp;
}
}
}
I'm not sure if this will work, as it depends on being able to compare objects, and also I don't know that identical nodes from separate XML documents would compare the same anyway. But try it, and let me know. I can whip something else up if this doesn't work.

PHP foreach Loop Element Index

I have an XPath query that gets Genres of a movie.
$genreXpath = $xml_data->xpath("//category");
I get the attributes from $genreXpath like this
$genreName=array();
$genresID=array();
$i=0;
foreach($genreXpath as $node) {
$genre = $node->attributes();
$genreName[$i] = $node["name"];
$genresID[$i] = $node["id"];
$i++;
}
I'm going to be writing these values to a Db hence the two different arrays.
This code works but I know there has to be a better way of doing this be it with a 2 d array, not using a $i counter or something more obvious that I haven't figured out....any pointers???
foreach($genreXpath as $i=>$node) { //note $i is your index of the current $node
$genre = $node->attributes();
$genreName[$i] = $node["name"];
$genresID[$i] = $node["id"];
}
It auto increments and you do not need to declare it above.
Use foreach($genreXpath as $key => $node) {
If you looking to a multidimensional you could do:
$genres = array();
foreach($genreXpath as $node) {
$genre = $node->attributes();
$genres[] = array($node["name"], $node["id"]);
}

Categories