Currently browsing simplexml


Flickr Namespace and array_multisort() Issues

Fri, 15 Dec 2006 18:15 UTC

Aaron Wormus recently criticized me on IRC for putting too much thought and effort into blogging. He may have a point there. I’ve got a huge list of things I want to write about, but I haven’t put forth the effort because I do take too much time to write a post. So, here goes one for writing up a quick post . . .

I recently upgraded a few things around here (in particular, an upgrade to PHP 5.2), and I noticed two issues that occurred after the upgrade:

  1. My Flickr photo feed no longer worked, and
  1. My blogroll was no longer sorting alphabetically

    I easily solved both of these issues:

    The Flickr photo feed

    I’m not entirely sure whether this problem was a result of the PHP 5.2 upgrade and SimpleXML becoming more particular about namespaces or Flickr simply changing the namespace string in their feed. I believe it was the latter. In short, my code stopped working because the namespace lacked a trailing slash (/). It would’ve been great if Flickr had notified everyone about this first.

    The code looked something like this:

    <?php
     
    $flickr_rss = simplexml_load_file('http://www.flickr.com/services/feeds/photos_public.gne?id=49198866@N00&format=rss_200');
     
    foreach ($flickr_rss->channel->item as $item)
    {
        $link   = (string) $item->link;
        $media  = $item->children('http://search.yahoo.com/mrss');
        $thumb  = $media->thumbnail->attributes();
        $url    = (string) $thumb['url'];
        $width  = (string) $thumb['width'];
        $height = (string) $thumb['height'];
        $title  = (string) $item->title;
     
        // display image here
    }
     
    ?>

    Note the namespace listed in $item->children(‘http://search.yahoo.com/mrss’);. It’s lacking a trailing slash. This was never a problem before, but it seems that the Flickr feed changed to include a trailing slash, so SimpleXML was no longer able to properly get the data. I simply changed it to http://search.yahoo.com/mrss/ (note the trailing slash), and all worked fine.

    Blogroll sorting

    This was more than likely a result of the upgrade to PHP 5.2, though I can’t be sure. My blog sorting code worked like this:

    <?php
     
    // sort by name
    $name = array();
    foreach ($blogs as $k => $v)
    {
        $name[$k] = $v['name'];
    }
    array_multisort($name, SORT_ASC, $blogs);
     
    ?>

    Unfortunately, after the upgrade, this no longer worked. I had to add the SORT_STRING flag as a parameter to array_multisort() so that the line now reads:

    <?php
     
    array_multisort($name, SORT_ASC, SORT_STRING, $blogs);
     
    ?>

    And that fixed it.

    Just thought I’d share the info in case this helps anyone.

    Comments 2 Comments »  Permalink Permalink  Tags Tags: , , , ,


Create an Image from XML Data

Fri, 19 May 2006 1:52 UTC

I had some time to kill and a silly problem to solve, which means here’s some more SimpleXML fun for you:

The Problem: It’s not really a “problem,” but FeedBurner’s FeedCountTM image is a rigid 88 pixels wide, and I wanted to include it on my homepage under the “syndicate” heading, an area that I’ve defined in my template as having only 80 pixels in width. The 88 pixels were throwing things off, so I used the width attribute of the HTML img tag to solve the problem. Unfortunately, it just squeezes the image, making the text in it appear fuzzy.

The Solution: FeedBurner conveniently provides what they call their “Awareness API,” which is a RESTful interface to retrieve (as XML data) the same exact information displayed in the FeedCountTM image. Since I wanted to maintain the same kind of image (because it’s a recognized look-and-feel for FeedBurner feeds), I simply fired up an image editing program, shuffled things around a bit until the image was a nice, clean 80 pixels wide, and saved it as the base image (shown to the right) I would use for generating an image similar to the one FeedBurner provides.

Base FeedBurner imageThen, I wrote a script to grab the FeedBurner data (using SimpleXML) and used PHP’s image functions to open the base image, write the FeedBurner circulation data to it, and save it to use on my site. I simply have a cron job that runs this script once a day to keep my image updated.

Here’s the code. Enjoy!

<?php
// Get the XML data from Feedburner
$sxe = new SimpleXMLElement('http://api.feedburner.com/awareness/1.0/GetFeedData?uri=ramsey', NULL, TRUE);
$readers = (string) $sxe->feed->entry['circulation'];
 
// make sure it's a number
$readers = is_numeric($readers) ? $readers : '0';
 
// 39 is the base position; 6 the width of each char
$xpos = 39 - (strlen($readers) * 6);
 
// Create the image from the base image
$img = imagecreatefromgif('feedburner-base.gif');
$color = imagecolorallocate($img, 0x00, 0x66, 0xCC);
imagestring($img, 2, $xpos, 2, $readers, $color);
 
// Save the image
imagegif($img, 'feedburner-readers.gif');
?>

Note that I determined the numbers used in lining up the text in the image by trial-and-error. I played around with it a bit to get things right. The $xpos variable is my attempt to right-align the text because you can only specify the left edge of the text with the x coordinate.

Comments No Comments  Permalink Permalink  Tags Tags: , , , ,


Add Children with SimpleXML

Thu, 11 May 2006 3:05 UTC

I was very excited today while glancing through the code in ext/simplexml/simplexml.c to find some, as of yet, undocumented methods in PHP’s SimpleXMLElement class. This discovery came after I’ve spent several hours over the last couple of nights banging my head against the desk to figure out a way to create a class that extends SimpleXMLElement and adds a new method for adding a child, which would have to use DOM in order to work—or so I thought.

During this process, I’ve discovered two major limitations of SimpleXML:

  • You cannot override the SimpleXMLElement constructor; it is a “final” method in the internals
  • You can extend SimpleXMLElement and add new methods, but looping through child nodes creates new SimpleXMLElement objects that do not use your class and, thus, cannot use your methods

    Nevertheless, I can get over these limitations after discovering these new SimpleXMLElement methods in PHP 5.1.4. In particular, the last three are what interest me most (these are not yet documented in the PHP manual ):

    bool   SimpleXMLElement->registerXPathNamespace(string prefix, string uri)
    array  SimpleXMLElement->getNamespaces([bool recursive])
    array  SimpleXMLElement->getDocNamespaces([bool recursive])
    string SimpleXMLElement->getName()
    object SimpleXMLElement->addChild(string name [, string value [, string ns]])
    void   SimpleXMLElement->addAttribute(string name, string value [,string ns])

    Previously, one of the biggest limitations of SimpleXML was that you could not add new child nodes to an XML document. Adding attributes to an element was no problem, but in order to add a child element, you had to go a round-about way through importing the SimpleXML object to DOM with dom_import_simplexml(), adding the child element, and importing the DOM object back to SimpleXML with simplexml_import_dom(). This was messy and anything but simple.

    Now, it’s clean and simple, as SimpleXML should be:

    <?php
     
    $xml = <<<XML
    <books>
        <book title="Fahrenheit 451" author="Ray Bradbury"/>
        <book title="Stranger in a Strange Land" author="Robert Heinlein"/>
    </books>
    XML;
     
    $sxe = new SimpleXMLElement($xml);
     
    $new_book = $sxe->addChild('book');
    $new_book->addAttribute('title', '1984');
    $new_book->addAttribute('author', 'George Orwell');
     
    echo $sxe->asXML();
     
    ?>

    UPDATE: I’ve added all of these (except for registerXPathNamespace(), which I can’t seem to figure out) to the documentation for SimpleXML in the PHP Manual. The documentation for each new method will be available the next time the scripts run to update the manual.

    Comments 6 Comments »  Permalink Permalink  Tags Tags: , ,