PHP + RSS duplicate elements - php

Im using this PHP to get a list of Title's from an RSS feed:
<?php require_once('magpie/rss_fetch.inc');
$rss = fetch_rss('http://live.visitmix.com/Sessions/RSS');
foreach ($rss->items as $item) {
$cat = $item['category'];
$title = $item['title'];
echo '<li class="'.$cat.'">'.$title.'</li>';
}
?>
I want to use <category> and add it as the class, however the <category> element appears for each <item> 1,2,3,4 or more times depending on the Title. How can I take the category element and seperate each category with a space if there is more than 1?

what about accumulating the categories in an array and then implode the array?
$categoriesArray = array();
foreach ($rss->items as $item) {
array_push($categoriesArray, $item['category']);
}
$categories = implode(" ", $categoriesArray);
EDIT TO ADD
If the categories are cumulated, you can try something like this:
$categoriesByTitle = array();
foreach ($rss->items as $item) {
$currentTitle = $item['title'];
$categories = $categoriesByTitle[$currentTitle];
if ($categories == NULL) {
$categories = array();
$categoriesByTitle[$currentTitle] = $categories;
}
if (!in_array($item['category'], $categories)) {
array_push($categories, $item['category']);
}
}
foreach ($categoriesByTitle as $title=>$category) {
// use implode for each title
$categoryString = implode(" ", $category);
echo '<li class="'.$categoryString.'">'.$title.'</li>';
}
Check this reference for arrays, it could be very useful for dealing with this kind of problems

Related

Retrieving all google tags xml

Im parsing a xml file but im having some issues regarding a tag (":g"), i cant access the information, his content, the problem is when i try to get the categories, i have more than one category.
xml:
<item>
<g:id>4011700742288</g:id>
<title><![CDATA[4711 Acqua Colonia Blood Orange & Basil Eau de Cologne 170ml]]></title>
<link><![CDATA[https://url/asdasd.html]]></link>
<g:image_link><![CDATA[https://url/media/catalog/product/4/7/4711-acqua-colonia-blood-_2.jpg]]></g:image_link>
<g:price>34.86 EUR</g:price>
<g:product_type><![CDATA[Mulher]]></g:product_type>
<g:product_type><![CDATA[Homem]]></g:product_type>
<g:product_type><![CDATA[Unisexo]]></g:product_type>
</item>
I try getting the categories using for example:
$categories = $item->children('g', TRUE)->product_type;
But it only brings the first category, is not geting the rest of the categories.
Here above is my code example of how i get the data.
ex:
foreach($rss->channel->item as $item) {
$categories = $item->children('g', TRUE)->product_type;
// bringing in to array <content:encoded> items from SimpleXMLElement Object()
$content = xmlObjToArr($item->children('content', true)->encoded);
echo $categories . PHP_EOL;
return;
}
function xmlObjToArr($obj) {
$namespace = $obj->getDocNamespaces(true);
$namespace[NULL] = NULL;
$children = array();
$attributes = array();
$name = strtolower((string)$obj->getName());
$text = trim((string)$obj);
if( strlen($text) <= 0 ) {
$text = NULL;
}
// get info for all namespaces
if(is_object($obj)) {
foreach( $namespace as $ns=>$nsUrl ) {
// atributes
$objAttributes = $obj->attributes($ns, true);
foreach( $objAttributes as $attributeName => $attributeValue ) {
$attribName = strtolower(trim((string)$attributeName));
$attribVal = trim((string)$attributeValue);
if (!empty($ns)) {
$attribName = $ns . ':' . $attribName;
}
$attributes[$attribName] = $attribVal;
}
// children
$objChildren = $obj->children($ns, true);
foreach( $objChildren as $childName=>$child ) {
$childName = strtolower((string)$childName);
if( !empty($ns) ) {
$childName = $ns.':'.$childName;
}
$children[$childName][] = xmlObjToArr($child);
}
}
}
return array(
'name'=>$name,
'text'=>$text,
'attributes'=>$attributes,
'children'=>$children
);
}
Your code is correct.
$categories = $item->children('g', TRUE)->product_type;
This will set $categories to an object which gives you access to all the <g:product_type> elements.
Your problem is when you write:
echo $categories . PHP_EOL;
This displays the text content of a single XML element. Since $categories is a collection of multiple elements, SimpleXML guesses that you want the first one. In other words, it's equivalent to:
echo (string)$categories[0] . PHP_EOL;
Where (string) extracts the text content and is implied by echo, and [0] gets the first item in the collection.
Looping over the collection of elements works exactly how you'd expect a list to work - you use foreach:
foreach ( $categories as $cat ) {
echo $cat . PHP_EOL;
}

SimpleXml foreach : ignore element

<?php
$xml = "<articles>
<article id=\"18357302\">
<articleCategories>
<articleCategory id=\"default\"/>
<articleCategory id=\"66607\"/>
</articleCategories>
</article>
</articles>";
$feed = simplexml_load_string($xml);
$items = $feed->article;
foreach ($items as $article) {
// $categorie = $article->articleCategories->articleCategory[id];
$categories = $article->articleCategories;
print_r($categories);
echo "<br>print_r indeed returns an array, but impossible to echo it using foreach!!!<br>";
foreach ($categories->id as $category) {
if ($category != "default") {
echo $category;
}
}
}
?>
not sure what i am doing wrong, i am just trying to find a way to remove the part with the default value inside articlesCategories
<articleCategory id=\"default\"/>
The script needs to ignore this part and just use the next articleCategory from the XML file, and i would prefer to avoid removing it with regex
The script iterates over articleCategories tag.
But it needs to iterate over articleCategory tag.
The following changes will be enough.
foreach ($categories->articleCategory as $category) {
if ($category["id"] != "default") {
echo $category["id"];
}
}

RSS feed limit items

How can i limit the items from my RSS-feed? (Example: 5 items). I hope someone can help me with this code.
<?php
$url = "LINK TO RSS";
$rss = simplexml_load_file($url);
if($rss)
{
$items = $rss->channel->item;
foreach($items as $item)
{
$title = $item->title;
$link = $item->link;
$published_on = $item->pubDate;
$description = $item->description;
echo '<p class="rss-feed">'.$title.'</p>';
echo '<p>'.$description.'</p>';
}
}
?>
If you want to limit the number of items displayed you can use the array_slice function to store a subset of the retrieved values in $items, e.g. change:
$items = $rss->channel->item;
to:
$items = array_slice($rss->channel->item, 0, 5);
If you want to change the number of items fetched from the URL then you need to check whether/how this URL supports this behaviour.

Loop a foreach json loop in another foreach json loop

I'm at a 24 hour hackathon trying to solve this so, excuse if it's a little rushed.
1st for each loop works fine, I'm getting a list of categories from this url
https://dev.xola.com/api/categories
I grab the list with this
$fullurl = "https://dev.xola.com/api/categories";
$string .= file_get_contents($fullurl); // get json content
$json_a = json_decode($string, true); //json decoder
then loop it with this
<?
foreach($json_a as $v)
{?>
echo $v ?}>
Now with the second for each look, I want to grab the items from this url
https://dev.xola.com/api/experiences
that match the category from the last url
so samething
$fullurl = "https://dev.xola.com/api/categories";
$string .= file_get_contents($fullurl); // get json content
$json_b = json_decode($string, true); //json decoder
here's the complete loop I tried
<?
$i=0;
foreach($json_a as $v)
$i++
{?>
echo $v ?
foreach($json_b as $x){?>
if($v==$x):
echo $v
endif;
?>
}?>
This will create a $result array with only the data that had the categories early acquired:
<?php
$categories_url = "https://dev.xola.com/api/categories";
$data = file_get_contents($categories_url);
$categories = json_decode($data, true);
$experiences_url = "https://dev.xola.com/api/experiences";
$data = file_get_contents($experiences_url);
$experiences = json_decode($data, true);
$result = array();
foreach ($experiences['data'] as $experience)
{
if (in_array($experience['category'], $categories))
{
$result[] = $experience;
}
}
print_r($result);
And you can easily read the result with:
foreach ($result as $item)
{
echo $item['category'], "\n";
echo $item['desc'], "\n";
//... other data available ...
}
The data structure of the experiences JSON is not the same as the categories JSON, therefore if($v==$x) will never match. If you want to find all results in experiences with a category from the categories url you can do the following:
<?
$BASE_URL = 'https://dev.xola.com/api/';
$categories = json_decode(file_get_contents($BASE_URL . 'categories'));
$experiences = json_decode(file_get_contents($BASE_URL . 'experiences'));
$matches = array();
foreach( $categories as $category ) {
foreach( $experiences->data as $experience ) {
if( $experience->category === $category ) {
$matches[] = $experience;
}
}
}
?>
<? foreach( $matches as $match ) : ?>
<? echo $match->category; ?><br>
<? endforeach; ?>

Create nested list with PHP from XML dataset

I'm trying to build an unordered list from an existing XML file which contains categories and subcategories + images. I need each subcategory to be an item in an unordered list with each related image in a nested list. The subcategories should be shown only once (must not repeat if it's the same). I believe what I'm looking for is a recursive loop, but that's where I get lost.
Essentially, I'm trying to achieve a look similar to this:
--------------DOGS-------------
[..........small..........]
[picture] [picture]
[..........large..........]
[picture]
--------------CATS-------------
[..........medium..........]
[picture]
[..........large..........]
[picture] [picture]
My XML file structure:
<root>
<animal>
<category>DOGS</category>
<subcategory>small</subcategory>
<name>Terrier</name>
<image>aaa.jpg</image>
</animal>
<animal>
<category>-</category>
<subcategory>small</subcategory>
<name>Havanese</name>
<image>bbb.jpg</image>
</animal>
<animal>
<category>-</category>
<subcategory>large</subcategory>
<name>Dalmatian</name>
<image>ccc.jpg</image>
</animal>
<animal>
<category>CATS</category>
<subcategory>medium</subcategory>
<name>Abyssinian</name>
<image>ddd.jpg</image>
</animal>
<animal>
<category>-</category>
<subcategory>large</subcategory>
<name>Birman</name>
<image>eee.jpg</image>
</animal>
<animal>
<category>-</category>
<subcategory>large</subcategory>
<name>American Shorthair</name>
<image>fff.jpg</image>
</animal>
</root>
Here's what I have attempted so far:
<?php
$xml = simplexml_load_file("file.xml");
$categories = array();
$subcategories = array();
$names = array();
$image = array();
foreach($xml->animal as $animals) {
$category = $animals->category;
$subcategory = $animals->subcategory;
$name = $animals->name;
$image = $animals->image;
$categories[] = $category;
$subcategories[] = $subcategory;
$names[] = $name;
$images[] = $image
}
function getMenu($xml, $categories, $subcategories, $names, $images) {
$output = '<ul>';
foreach(array_keys($images) as $n) {
$output .= '<li class="animals" data-tags="'.$names[$n].'">';
$output .= '<img src="xml/'.$images[$n].'" width="75" height="75" alt="'.$names[$n].'" />';
$output .= '</li>';
}
$output.= '</ul>';
return array($output);
}
$result = getMenu($xml, $categories, $subcategories, $names, $images);
echo json_encode($result);
?>
There are literally a thousand ways how you can do that. Most straight forward is probably with xpath(). It's a powerful XML querying language worth to learn. Example with your $xml simplexmlelement:
foreach ($xml->xpath('//category[not(. = following::category)]') as $category) {
echo "=== $category === \n";
foreach ($xml->xpath("//animal[category = '$category']/subcategory[not(. = following::animal[category = '$category']/subcategory)]") as $subcategory) {
echo " = $subcategory =\n";
foreach ($xml->xpath("//animal[category = '$category' and subcategory = '$subcategory']") as $animal) {
echo " * $animal->name ($animal->image)\n";
}
}
}
Output:
=== DOGS ===
= small =
* Terrier (aaa.jpg)
* Havanese (bbb.jpg)
= large =
* Dalmatian (ccc.jpg)
You further on might want to replace the lengthy xpath strings out there. With the help of a closure and an iterator aggregate, it's even possible to reduce the code quite comfortable to:
foreach ($categories as $category) {
echo "=== $category === \n";
foreach ($subcategories as $subcategory) {
echo " = $subcategory =\n";
foreach ($animals as $animal) {
echo " * $animal->name ($animal->image)\n";
}
}
}
This would allow to change the XML structure later on and have the xpath's configured in a central location:
$categories = $vpath('//category[not(. = following::category)]');
$subcategories = $vpath('//animal[category = "%1$s"]/subcategory[not(. = following::animal[category = "%1$s"]/subcategory)]', [&$category]);
$animals = $vpath("//animal[category = '%s' and subcategory = '%s']", [&$category, &$subcategory]);
I have put that example online as a demo.
I have the output just as text with indents, however thanks to the foreachs it should be really straight forward to turn that into HTML. I leave that as an exercise.

Categories