Moving on…

Today, after 3½ years at Yahoo! – the longest I have ever held a single job – I officially handed a resignation letter to my manager.

I’m not going to rant about what’s wrong with Yahoo! – no company is perfect, and mostly I feel incredibly grateful to have had the chance to work there. I got to build things that are seen, used, and hopefully enjoyed every day by a mind-numbing amount of users. That has been a very humbling experience.

For anyone who speaks HTML/CSS/JS/PHP and wants to learn about scalable web development, Yahoo! is probably one of the best places to do so. There is a great company culture in place, cutting edge technologies being worked on (YQL, YUI, Hadoop…), and while the food isn’t free, it really isn’t bad. And you do get free coffee, smart colleagues, massive amounts of bandwidth, and the freedom to put stickers all over your laptop! If you want to work at Yahoo!, do get in touch, and I will make sure your resume is on top of the pile.

So… most of my readers should already know by now (hi mom!), but here’s the news: in two weeks I shall begin working at Twitter. For those of you who don’t know what Twitter is, you should really get out from under that rock.

The office is located in downtown San Francisco. I’m going to learn me some Ruby and work on all things front-end, from the twitter.com site itself to, who knows, @anywhere.

I am so psyched about this opportunity, I’m having twouble spelling. If you too want to work at Twitter, hit @jointheflock or, if in Austin this week, you can stalk Twitter People.

In conclusion, if next year I don’t finally make it to SxSW, something is wrong. ;-)

Follow me @gaarf

Happy 2010!

It’s the holiday break, and if you are anything like me, that means it’s time to print out a new calendar for the coming year. I use a one-sheet paper calendar to track when bills come in. This year I made it with YUI3, and I am passing the savings on to YOU!

Enjoy: http://daltonx.net/hacks/yearcal.html

Click the “2010″ at the top-left of the table to render a different year.

Yahoo! Messenger 10 beta

Nifty New Insider

Yahoo! Messenger 10 beta (windows download) was released yesterday. It is a major milestone for the instant messaging team, and for me in particular because it means the new insider page is now live! This is the project I have been working on for the past few months. It is essentially a mini version of the Yahoo! homepage built with YQL cloud technology, complete with mail, news, weather, search assist, a high-revenue ad position, alternate stylesheets (skins!), a location picker, and there’s even an easter egg or two. Go find them if you can. ;)

The page is intended to run “inside the IM client” but it works just fine in any modern browser window, too. Check it out here (you will need a Yahoo! id).

XML string to PHP array

UPDATEthe code is now on github

One common need when working in PHP is a way to convert an XML document into a serializable array. If you ever tried to serialize() and then unserialize() a SimpleXML or DOMDocument object, you know what I’m talking about.

Assume the following XML snippet:

<tv>
  <show name="Family Guy">
    <dog>Brian</dog>
    <kid>Chris</kid>
    <kid>Meg</kid>
  </show>
</tv>

There’s a quick and dirty way to do convert such a document to an array, using type casting and the JSON functions to ensure there are no exotic values that would cause problems when unserializing:

<?php
  $a = json_decode(json_encode((array) simplexml_load_string($s)),1);
?>

Here is the result for our sample XML, eg if we print_r($a):

Array
(
    [show] => Array
        (
            [@attributes] => Array
                (
                    [name] => Family Guy
                )
            [dog] => Brian
            [kid] => Array
                (
                    [0] => Chris
                    [1] => Meg
                )
        )
)

Pretty nifty, eh? But maybe we want to embed some HTML tags or something crazy along those lines. then we need a CDATA node…

<tv>
  <show name="Family Guy">
    <dog>Brian</dog>
    <kid>Chris</kid>
    <kid>Meg</kid>
    <kid><![CDATA[<em>Stewie</em>]]></kid>
  </show>
</tv>

The snippet of XML above would yield the following:

Array
(
    [show] => Array
        (
            [@attributes] => Array
                (
                    [name] => Family Guy
                )
            [dog] => Brian
            [kid] => Array
                (
                    [0] => Chris
                    [1] => Meg
                    [2] => Array
                        (
                        )
                )
        )
)

That’s not very useful. We got in trouble because the CDATA node, a SimpleXMLElement, is being cast to an array instead of a string. To handle this case while still keeping the nice @attributes notation, we need a slightly more verbose conversion function. Here is my version, hereby released under a do-whatever-but-dont-sue-me license.

<?php
/**
 * convert xml string to php array - useful to get a serializable value
 *
 * @param string $xmlstr
 * @return array
 * @author Adrien aka Gaarf
 */
function xmlstr_to_array($xmlstr) {
  $doc = new DOMDocument();
  $doc->loadXML($xmlstr);
  return domnode_to_array($doc->documentElement);
}
function domnode_to_array($node) {
  $output = array();
  switch ($node->nodeType) {
   case XML_CDATA_SECTION_NODE:
   case XML_TEXT_NODE:
    $output = trim($node->textContent);
   break;
   case XML_ELEMENT_NODE:
    for ($i=0, $m=$node->childNodes->length; $i<$m; $i++) {
     $child = $node->childNodes->item($i);
     $v = domnode_to_array($child);
     if(isset($child->tagName)) {
       $t = $child->tagName;
       if(!isset($output[$t])) {
        $output[$t] = array();
       }
       $output[$t][] = $v;
     }
     elseif($v) {
      $output = (string) $v;
     }
    }
    if(is_array($output)) {
     if($node->attributes->length) {
      $a = array();
      foreach($node->attributes as $attrName => $attrNode) {
       $a[$attrName] = (string) $attrNode->value;
      }
      $output['@attributes'] = $a;
     }
     foreach ($output as $t => $v) {
      if(is_array($v) && count($v)==1 && $t!='@attributes') {
       $output[$t] = $v[0];
      }
     }
    }
   break;
  }
  return $output;
}
?>

and the result, for our Stewie snippet:

Array
(
    [show] => Array
        (
            [@attributes] => Array
                (
                    [name] => Family Guy
                )
            [dog] => Brian
            [kid] => Array
                (
                    [0] => Chris
                    [1] => Meg
                    [2] => <em>Stewie</em>
                )
        )
)

Victory is mine! :D