PHP check if XML node exists before saving to variable? - php

Here is a snippet of the xml I am working with:
My example xml
A client requested that we add the ability to filter which type of "news articles" are displayed on specific pages. They create these articles on another website, where they now have the ability to assign a one or more categories to each of the articles. We load the articles via php and xml.
The error I receive is:
Call to a member function getElementsByTagName() on null in ...
Here is the code from 2012 that I am working with:
$item = $dom_object->getElementsByTagName("Releases");
foreach( $item as $value )
{
$Release = $value->getElementsByTagName("Release");
foreach($Release as $ind_Release){
$Title = $ind_Release->getElementsByTagName("Title");
$PublishDateUtc = $ind_Release->getAttribute('PublishDateUtc');
$DetailUrl = $ind_Release->getAttribute('DetailUrl');
$parts = explode('/', $DetailUrl);
$last = end($parts);
I am trying to transverse to the category code and set a variable with:
$newsCategory = $ind_Release->getElementsByTagName("Categories")->item(0)->getElementsByTagName("Category")->item(0)->getElementsByTagName("Code")->item(0)->nodeValue;
This loads the current 2018 articles with the category slug being echoed, because they have an assigned category, but it fails to load 2017, 2016, and so on, I believe, because they are not assigned a category within the XML and this is breaking something.
A news article without a category appears with an empty categories node within XML
I understand that I am using getElementsByTagName, and because there is no element beyond the first categories node it breaks.
Is there a way to check that there is indeed a path to Categories->Category->Code[CDATA] before trying to set it as a variable and breaking it?
I apologize if this is confusing, I am not a PHP expert and could use all the help I can get. Is there a better way to transverse to the needed node?
Thanks.

You need to use XPath. If you're using DOMDocument, this is done via DOMXpath.
Your current approach uses chaining, and the problem with chaining is it breaks down if a particular juncture of it doesn't return what the following method relies on. Hence your error.
Instead, check the whole path from the start:
$domxp = new DOMXpath($dom_object);
$node = $domxp->query('/Categories[1]/Category[1]/Code[1]');
if (count($node)) {
//found - do something
}

Related

Drupal 7: How do I retrieve a node's Content Type from within a component's prepocess function?

I've got a component that requires me to get the content type of the node the component appears on. I saw there exists a function to get that for me:
node_type_get_name($node)
However, when I use this function within the components pre-process hook, eg:
my_component_preprocess_my_component_theme(&$variables, $node) {
dpm(node_type_get_name($node));
}
I get nothing.
If I dpm($node); I get the title of the component, not the node.
Would anyone know how I can retrieve the node's content-type?
You can load current node like this:
<?php
$node = menu_get_object();
if ( !empty($node) ) {
print "Have node";
}
?>
So, you'll have full node loaded and can check it's type ($node->type) and anything else you need.
https://www.drupal.org/forum/support/post-installation/2010-07-28/how-to-get-node-object-or-nid-for-the-current-page
And if you don't have the node it means, of course, current page is not a node (maybe a view or some custom page...).

Wikipedia API - get full information from infobox

i am trying to extract the parent company information (in infobox pane) for a page such as "KFC".
If you access the
http://en.wikipedia.org/wiki/KFC
url... the info box contains the property (Parent = Yum! Brands)
.. howver, when i access through the PHP API.. the parent info is not included.
http://en.wikipedia.org/w/api.php?action=query&prop=revisions&rvprop=content&format=json&titles=KFC&rvsection=0
How do i ensure that Wikipedia API returns the "Parent = " information as well (for a brand term like "KFC"). Essentially, I want to extract info that Yum Brands is the parent of KFC through the wikipedia API.
Thanks!
Take a look at the wikipedia wiki official ways of getting informations.
My suggestion would be to use the screen scraping throught PHP Simple HTML DOM Parser which will always be the best, even if it's deprecated. The only downside is that if Wikipedia changes how it looks like you will have to update your code.
A guide to PHP Simple HTML DOM Parser.
Edit:
At least i'm doing something instead of linking to non working resources and downvoting right answers ...
Here's the code I made to get the Parent company information from the Infobox pane with the PHP Simple HTML DOM Parser.
<?php
//The folder where you uploaded simple_html_dom.php
require_once('/homepages/../htdocs/simple_html_dom.php');
//Wikipedia page to parse
$html = file_get_html('http://en.wikipedia.org/wiki/KFC');
foreach ( $html->find ( 'tr th a[title=Holding company]' ) as $element ) {
$element = $element->parent;
$element = $element->parent;
$tabella = $element->find ( 'td', 0 );
//Now $parent contains "Yum! Brands"
$parent = $tabella->plaintext;
echo $parent;
}
?>
If this answer suit your needs please choose it as best answer and upvote it because it took me a lot of effort, about 1 hour =/
Thanks ;)

How can I get an id from a simplepie post which can be used to look it up later?

I've recently started developing a portfolio website which I would like to link to my wordpress blog using simplepie. It's been quite a smooth process so far - loading names and descriptions of posts, and linking them to the full post was quite easy. However, I would like the option to render the posts in my own website as well. Getting the full content of a given post is simple, but what I would like to do is provide a list of recent posts which link to a php page on my portfolio website that takes a GET variable of some sort to identify the post, so that I can render the full content there.
That's where I've run into problems - there doesn't seem to be any way to look up a post according to a specific id or name or similar. Is there any way I can pull some unique identifier from a post object on one page, then pass the identifier to another page and look up the specific post there? If that's impossible, is there any way for me to simply pass the entire post object, or temporarily store it somewhere so it can be used by the other page?
Thank you for your time.
I stumbled across your question looking for something else about simplepie. But I do work with an identifier while using simplepie. So this seems to be the answer to your question:
My getFeedPosts-function in PHP looks like this:
public function getFeedPosts($numberPosts = null) {
$feed = new SimplePie(); // default options
$feed->set_feed_url('http://yourname.blogspot.com'); // Set the feed
$feed->enable_cache(true); /* Enable caching */
$feed->set_cache_duration(1800); /* seconds to cache the feed */
$feed->init(); // Run SimplePie.
$feed->handle_content_type();
$allFeeds = array();
$number = $numberPosts>0 ? $numberPosts : 0;
foreach ($feed->get_items(0, $number) as $item) {
$singleFeed = array(
'author'=>$item->get_author(),
'categories'=>$item->get_categories(),
'copyright'=>$item->get_copyright(),
'content'=>$item->get_content(),
'date'=>$item->get_date("d.m.Y H:i"),
'description'=>$item->get_description(),
'id'=>$item->get_id(),
'latitude'=>$item->get_latitude(),
'longitude'=>$item->get_longitude(),
'permalink'=>$item->get_permalink(),
'title'=>$item->get_title()
);
array_push($allFeeds, $singleFeed);
}
$feed = null;
return json_encode($allFeeds);
}
As you can see, I build a associative array and return it as JSON what makes it really easy using jQuery and ajax (in my case) on the client side.
The 'id' is a unique identifier of every post in my blog. So this is the key to identify the same post also in another function/on another page. You just have to iterate the posts and compare this id. As far as I can see, there is no get_item($ID)-function. There is an get_item($key)-function but it is also just taking out a specific post from the list of all posts by the array-position (which is nearly the same way I suggest).

Reading node field values in module code using Drupal 6

I have created a custom module and am using hook_block to programmatically create some blocks.
My question is how can I access field values including CCK fields for the current node within my module?
I basically want to get a value from a CCK field and use the value when building my block for that page.
Getting at the current node is an awkward pain in the posterior. Standard practice is to do something like this:
if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == '') {
$node = node_load(arg(1));
// Collect output.
}
arg() pulls elements out of the Drupal path. Since all nodes (regardless of what a path alias might show you) appears at node/#, by checking for 'node' and that the second element is a number, you are fairly well guaranteed to have your hands on a node. Checking the third path element allows you to avoid processing on the node edit form and other pages that hang off a specific node.
CCK Values are loaded into the node, and usually look something like this:
// Text field. Structure also works for number fields.
$text = $node->field_my_text_field[0]['value']
// Node Reference field.
$nref = $node->field_my_nref_field[0]['nid']
// User Reference field.
$uref = $node->field_my_uref_field[0]['uid']
The "0" array element specifies the delta of the field. Any given field can actually process multiple values, and the array structure in CCK assumes this possibility even if you restrict the field to a single value.
In Drupal 6 there is a built-in Drupal function to get the node object.
if ($node = menu_get_object()) {
…
}
Read more here http://api.drupal.org/api/function/menu_get_item/6.

Setting A Header Image for a Wordpress Page and all its children

Wordpress. I've got a handful of pages, each with children -- varying depths.
Let's say it's like this:
+about
-- page1
-- page2
+stuff
-- page1
--- sub-sub-page
-- page2
My problem:
I want to set a graphic header for all the "about" pages, including all its children... and a different graphic header for all "stuff" pages and all its children.
I could do this using a custom field for each individual page, but I don't trust my users to remember to set this field.
I thought about adding to the page.php template and telling the page to find its parent top-level page to determine which "family" it's in, then set the header graphic that way...but I don't want to invest a ton of time (and run-time) resources traversing up the hierarchy.
Any ideas?
Much thanks in advance...
UPDATE:
Taking the code from below, I modified it to use outside of the Wordpress Loop (have not yet integrated the "default" value yet).
<?php
global $wp_query;
$postid = $wp_query->post->ID;
$header_swf = get_post_meta($postid, 'header_swf', true);
if (!$header_swf) {
$parent = get_page($wp_query->post->post_parent); //array of values for this page's parent, directly above it
while (!$header_swf && $parent) {
$header_swf = get_post_meta($parent->ID, 'header_swf', true);
$parent = get_page($parent->post_parent); //new parent
}
}
?>
Note: This answer assumes (perhaps incorrectly) there is no built-in method to do this.
You could write something in the template that looked for a predefined custom field. If none exists, it could ask the parent page for its version of the custom field, and so on.
$val = get_post_custom_values('header_image');
if (!val) {
$parent = get_page($post->post_parent);
while (!$val && $parent) {
$val = get_post_custom_values('header_image', $parent->id);
$parent = get_page($parent->post_parent);
}
if (!$parent && !val) // has failed to find a header image!
$val = 'my default value';
}
Or something like that.....
I should point out that might be really database heavy so it might be worth caching the value for each given URL. I'd personally recommend memcached but there are other methods.
I'd say test for the current page's family. I wouldn't think it'd be too taxing, as it's just a simple short-circuit.
Here's a previous SO thread on how you'd accomplish this.

Categories