Parsing a single XML section using a query string with PHP - php

I'm trying to retrieve a single section from an XML file using PHP.
Here's the code I'm using:
<?php
$articles = simplexml_load_file('articles.xml');
foreach ($articles as $articlecontent)
{
$title = $articlecontent->title;
$content = $articlecontent->content;
$author = $articlecontent->author;
$date = $articlecontent['date'];
echo "<h1>",$title,"</h1>\n",
"<p><i>",$date,"</i></p>\n",
"<p>",$content,"</p>\n",
"<p>",$author,"</p>\n",
"<p><time>",$date,"</time></p>\n"
;
}
?>
Which shows all the sections in the XML file, but how can I parse just one result but do so using a query string?
Example: articles.php?title=section-one will retrieve the XML section with the title "section-one"

You get the title from the query string by getting it from PHP's superglobal $_GET array, like this:
$title = false;
if (isset($_GET['title']))
{
$title = $_GET['title'];
}
and then the simplest way would be to compare it to the title from the XML file in your foreach loop.

Way to get title from url is using $_GET array, then to get required article by title i think you could use xpath which won't require foreach loop
$title = $_GET['title'];
// there should go some sanitizing
$articles = simplexml_load_file('articles.xml');
//search for article by title
//assuming that xml root tag is articles and article tag is article and searching by attribute named title
$foundArticles = $articles->xpath('articles/article[#title='.$title.']');
//query depends on xml structure
// now you have array of matched articles with matching title from url
foreach($foundArticles as $singleArticle)
{
//do printing here
}
This code is not tested, but principle should work.

To receive Query String Variable (in our case 'title') from URL you can use $_REQUEST also. Little bit corrected code (#user1597483) with some more advanced updates.
$articles = simplexml_load_file('articles.xml');
$title = "";
if(isset($_REQUEST['title'])) //receiving Query String from URL
$title = $_REQUEST['title'];
if(count($articles)):
//Fixed search means that will one return article if 'section-one' in title
//$result = $articles->xpath("//article[title='Section-one']");
//Match All Search means that will return all articles that contains 'section-one' in title
$result = $articles->xpath("//article[contains(translate(title, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),'".strtolower($title)."')]");
foreach ($result as $articleItem):
$title=$articleItem->title;
$content=$articleItem->content;
$author=$articleItem->author;
$date=$articleItem->date;
echo "<h1>",$title,"</h1>\n";
echo "<p><i>",$date,"</i></p>\n";
echo "<p>",$content,"</p>\n";
echo "<p>",$author,"</p>\n";
echo "<p><time>",$date,"</time></p>\n";
endforeach;
endif;
In the code above I have specified two types of filter through which you can get result with Specific Article by exact match or wild card type matching by contains function. And I have also used translate function which will convert value of title element to lowercase and also converted value of Query String Variable to lowercase. So that regardless of Upper/Lower case, condition will be checking with lowercase and if condition matched then resultant articles will be returned.

You can achieve that by inserting a condition into the foreach loop testing if the title-filter is in action and does not match. If so, skip that entry by using the continue keyword:
$titleFilter = trim(isset($_GET['title']) ? $_GET['title'] : '');
...
foreach ($articles as $articlecontent)
{
$title = $articlecontent->title;
if (strlen($titleFilter) and $title !== $titleFilter) {
continue;
}
...

Related

PHP - Output array value that contains a specific text marker

I'm using a function to output a collection of products in Shopify, onto a WordPress page.
I've got most of the data displaying correctly, except a custom value that is entered as a tag in Shopify. Using the api, I'm then trying to get this specific tag for the product subtitle which is formatted with att:Subtitle: before each product custom value/text.
This is the code I have got to (I've commented other unsuccessful attempts in the middle) - this is inside the overall code to show the 4 products in the Shopify collection:
// Using tags to output custom data from products
$tags = $current_product['tags'];
// $tags is a string, this turns the values into an array
$product_tags = explode(',', $tags);
// Evaluate if there is a string with att:Subtitle in the product tags
// https://tecadmin.net/check-string-contains-substring-in-php/
$subtitle_attribute_key = "att:Subtitle:";
if (strpos($tags, 'att:Subtitle:') !== false) {
// Returns a numbered value corresponding to my subtitle attribute
// $key = array_search($subtitle_attribute_key, $product_tags);
$sub = strpos($tags, $subtitle_attribute_key);
// Turns the numbered value into a text value
// $numArray = explode(" ", $sub);
// var_dump($numArray);
$value = print_r($sub, true);
// $value = array_search("att:Subtitle:",$product_tabs);
// $value = array_search("att:Subtitle:", $tabs); // Warning: array_search() expects parameter 2 to be array, null given
// $result = $product_tags['$value']; // my attempt to return the text
// Remove att:Subtittle: in front of the subtitle value to output the clean final value
$subtitle = ltrim($value, 'att:Subtitle:');
}
So far it comes out as a number value where I'm displaying $subtitle... but I can't figure out how to display the custom text value instead.
Any ideas?
Thanks
EDIT: I am working with products that have multiple tags and I do not control these. Out of the tags I'm trying to find the one that starts with att:Subtitle: but only show the custom value after that marker.
When I echo $tags, the ist comes out something like this:
att:Benefit:balance, att:Perfect:Combination Skin, att:Size: 1.8 oz, att:Subtitle: Multi-Tasking Product, Key Ingredient 1, Key Ingredient 2, Essentials, meta-related-product-xyz, meta-related-product-brandname
They will all have a different list of tags
Of course it comes out as a number. You're getting a number from the strpos() and ultimate trying to run ltrim() on it.
If you're expecting the desired text to be in $tags immediately following 'att:Subtitle:' and have nothing else in that string, $subtitle = substr($tags, strpos('att:Subtitle:') + strlen('att:Subtitle:')); should give it to you. If you're expecting it to possibly be an element in the $product_tags array, need to loop (I'm assuming it shows up once, at most):
foreach ($product_tags as $product_tag) {
if (strpos($product_tag, 'att:Subtitle:') !== false) {
$subtitle = substr($product_tag, strpos($product_tag, 'att:Subtitle:') + strlen('att:Subtitle:'));
break;
}
}
So for what I understand you're trying to get rid of 'att:Subtitle:' from the tags on your products descriptions? maybe you should try replacing that value on your tags array
// Using tags to output custom data from products
$tags = $current_product['tags'];
// $tags is a string, this turns the values into an array
$product_tags = explode(',', $tags);
// Get rid of attribute on product tag
for($i = 0; $i < count($product_tags); $i++){
$subtitle = str_replace(':att:Subtitle','',$product_tags[i]);
}

How to display this JSON data 'item' only once in this foreach loop (PHP)

I have a small function that grabs the avatars of comment authors on a specified video. It simply loops through the JSON data returned by YouTube API v3 commentThreads method.
The only issue is that sometimes an author has commented more than once, so my function is displaying the authors avatar more than once. I'd like to only display it one time, and on to the next avatar.
Here's a picture of what I mean:
Currently my function looks like this:
function videoCommentAvatars($video) {
// Parse YouTube video ID from the url
if (preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $video, $match)) {
$video_id = $match[1];
}
// Gather Video stats with YouTube API v3
$api_key = "API_KEY_HERE";
$JSON = file_get_contents('https://www.googleapis.com/youtube/v3/commentThreads?part=snippet&videoId='.$video_id.'&key='.$api_key);
$json_data = json_decode($JSON, true);
if (!empty($json_data)) {
foreach ($json_data['items'] as $data) {
// Create variables that hold info
$author_name = $data['snippet']['topLevelComment']['snippet']['authorDisplayName']; // Author Name
$author_avatar = $data['snippet']['topLevelComment']['snippet']['authorProfileImageUrl']; // Author Avatar
$author_channel = $data['snippet']['topLevelComment']['snippet']['authorChannelUrl']; // Author Channel URL
echo '<span class="comment-author-avatar">';
echo '<a target="_blank" href="'.$author_channel.'" title="'.$author_name.'"><img width="50" alt="'.$author_name.'" class="comment-author-thumb-single" src="'.$author_avatar.'"></a>';
echo '</span>';
}
}
}
Everything works fine, but there's no way to check if an avatar has been displayed yet. I thought about using an array maybe? Adding each avatar URL to the array, and checking the array to see if the key exists. But that seems like overkill for something that's seemingly more simple. Does anyone have a clever way of checking the foreach loop for duplicates?
to check for duplicates in an array, you have a few options. Firstly, to get rid of any before looping, you can use array_unqiue($array) which will return an array that does not repeat it's values.
Or if you do need initial access to all values in the loop, and to do something if a repeat is present, you can have another array that acts as a record to see if they appear more than once.
$record = array();
foreach ($json_data['items'] as $data) {
// Create variables that hold info
$author_name = $data['snippet']['topLevelComment']['snippet']['authorDisplayName']; // Author Name
if(!in_array($author_name, $record)){
$author_avatar = $data['snippet']['topLevelComment']['snippet']['authorProfileImageUrl']; // Author Avatar
$author_channel = $data['snippet']['topLevelComment']['snippet']['authorChannelUrl']; // Author Channel URL
echo '<span class="comment-author-avatar">';
echo '<a target="_blank" href="'.$author_channel.'" title="'.$author_name.'"><img width="50" alt="'.$author_name.'" class="comment-author-thumb-single" src="'.$author_avatar.'"></a>';
echo '</span>';
$record[] = $author_name;
}
}
You can try a multi array with a unique index in your loop.
$author[$data['snippet'][...]['authorDisplayName']['avatar'] = $data['snippet'][...]['authorProfileImageUrl'];
So only unique results in the array.

How to get iTunes-specific child nodes of RSS feeds?

I'm trying to process an RSS feed using PHP and there are some tags such as 'itunes:image' which I need to process. The code I'm using is below and for some reason these elements are not returning any value. The output is length is 0.
How can I read these tags and get their attributes?
$f = $_REQUEST['feed'];
$feed = new DOMDocument();
$feed->load($f);
$items = $feed->getElementsByTagName('channel')->item(0)->getElementsByTagName('item');
foreach($items as $key => $item)
{
$title = $item->getElementsByTagName('title')->item(0)->firstChild->nodeValue;
$pubDate = $item->getElementsByTagName('pubDate')->item(0)->firstChild->nodeValue;
$description = $item->getElementsByTagName('description')->item(0)->textContent; // textContent
$arrt = $item->getElementsByTagName('itunes:image');
print_r($arrt);
}
getElementsByTagName is specified by DOM, and PHP is just following that. It doesn't consider namespaces. Instead, use getElementsByTagNameNS, which requires the full namespace URI (not the prefix). This appears to be http://www.itunes.com/dtds/podcast-1.0.dtd*. So:
$img = $item->getElementsByTagNameNS('http://www.itunes.com/dtds/podcast-1.0.dtd', 'image');
// Set preemptive fallback, then set value if check passes
urlImage = '';
if ($img) {
$urlImage = $img->getAttribute('href');
}
Or put the namespace in a constant.
You might be able to get away with simply removing the prefix and getting all image tags of any namespace with getElementsByTagName.
Make sure to check whether a given item has an itunes:image element at all (example now given); in the example podcast, some don't, and I suspect that was also giving you trouble. (If there's no href attribute, getAttribute will return either null or an empty string per the DOM spec without erroring out.)
*In case you're wondering, there is no actual DTD file hosted at that location, and there hasn't been for about ten years.
<?php
$rss_feed = simplexml_load_file("url link");
if(!empty($rss_feed)) {
$i=0;
foreach ($rss_feed->channel->item as $feed_item) {
?>
<?php echo $rss_feed->children('itunes', true)->image->attributes()->href;?>
<?php
}
?>

How can I use Zend_Dom_Query to get meta data

Using Zend_Dom_Query, I would like to retrieve meta data out of an HTML string.
to retrieve links you can simply query like so:
$results = $dom->query('a'); //Where $dom is your html string
Unfortunately this doesn't seem to work with meta
$results = $dom->query('meta'); //doesn't work
How can I retrieve meta data and then filter by its 'property' attribute?
An example of what I'm looking for:
public function meta($dom)
{
$results = $dom->query('meta'); //This is not a correct query (does anyone have an alternative?)
$links = array();
foreach ($results as $index => $result) {
if ($result->getAttribute('property') == 'title') { //find <meta property="title"
echo $result->getAttribute('content') . '<br />'; //echo the content attribute of the title
}
}
return $results;
}
This code would work once the query is correct. However I would like to take it a step further and query directly for <meta property="title" content="This is the Title" /> instead of retrieving all meta and looping around to get the right one.
Any help with either getting all meta data using zend_dom_query or (more importantly) querying to receive only the meta data where property == title would be appreciated.
Thanks
the meta tag in not a valid CSS selector so you have to use the $dom->queryXpath($xPathQuery) method instead of $dom->query().
maybe something like:
$dom->queryXpath('/html/head');
I'm not sure of the exact query string to use, but this is the idea.
Zend_Dom_Query Theory of Operation.
if you have got url try this:
$metatagarray = get_meta_tags($url);
if (!empty($metatagarray["keywords"]))
$metakey = $metatagarray["keywords"];
if (!empty($metatagarray["description"]))
$metadesc = $metatagarray["description"];

Retrieve only the category ID from URL

I have my URL structure as www.site.com/listings/232-real-estate where 232 is the category ID and real-estate as my category name.
I want to retrieve only the numeric ID, to be used to extract data from the database using the category ID. How do I do that?
You can use something as simple as:
<?php
preg_match_all('#(\d+)#', $url, $matches);
$catid = $matches[0];
?>
But this does not have adequate checks in place. Ideally, you want to split on basis of /:
<?php
$elements = explode('/',$url);
$category = $elements[2];
$subelements = explode('-',$category);
$categoryid = intval($subelements[0]);
?>
You can use preg_replace:
id = preg_replace('/^.*\/([0-9]*)-[^\/]*$/','$1')
This assumes that the last / in the url is just before the category ID.
If 232-real-estate is stored in the variable $var you can get the ID using:
$id = strtok($var, '-');
Incidentally, it is then trivial to get the name:
$name = strtok(''); // returns: estate-agent

Categories