Archive for the 'Perl' Category

06
Jan

New CPAN release of WebService::MusicBrainz

0.20 Mon Jan 5th 2009
    - RT Bug 40597 - Slaven
         - Updated Build.PL perl version
    - RT Bug 42169 - pbryan
         - Fixed PUID object creation
         - Added test cases for PUID objects to Track.t

LINK
16
Nov

Open Source Rules

I submitted a patch to the Perl open source web log analyzer called “awstats” and it was recently accepted and applied.  Glad I could contribute to a product that I use.

13
Aug

YUI and parsing JSON

Am I missing something here?  I started a web app using YUI.  The server can generate XML or JSON as a response.  I started with XML but I found the parsing rather limited.  I switched to JSON using the XML::XML2JSON module on CPAN.  This produces JSON following a convention set up by Google.  It seems that YUI can not parse data in this format.

{"encoding":"UTF-8","version":"1.0",
 "metadata":{
    "artist-list":{
        "artist":{
           "life-span":{"@begin":"1992-02-14"},
           "sort-name":{"$t":"Weezer"},
           "name":{"$t":"Weezer"},
           "@id":"6fe07aa5-fec0-4eca-a456-f29bff451b04",
           "@ext:score":"100",
           "@type":"Group"
         },
     "@count":"1","@offset":"0"
   }}}

I found that I can get around the invalid “$t” and “-” in the name string by using a different syntax for JSON location code which includes using brackets and single quotes instead of periods.

mySearchDataSource.responseSchema = {
          resultsList: "['metadata']['artist-list']['artist']",
          fields: ["['sort-name']['$t']", "['@type']", "['@ext:score']"],
                 metaFields: {
                    totalRecords: "['metadata']['artist-list']['@count']"
                 }
             };

But YUI still does not like the “@” in the front of names and the “:” in the middle of a name.

I guess I have these choices:

  1. Switch server response to XML.  Write custom parseXMLData method for YUI DataSource.
  2. Write my own parseJSONData method for YUI DataSource.
  3. Write my own XML -> JSON conversion which constucts JSON data that YUI is happy with.
  4. Server side hack to “clean” JSON data of any offending characters.

Now I’m off to do some more research on this…

12
Feb

XML::Twig and mixed content

Trying to rush and write a quick script to update some XML files, I forgot how XML parsers deal with mixed content.

Example XML:

 	<para>Some TEXT to display with a <link xlink:href="DOC1">link to DOC1</link>, followed by some more TEXT.</para>

Say I wanted to update the string “TEXT” to “text” so the sentence reads better. Originally, I thought the code would look like this.

foreach my $xPara ($xRoot->get_xpath(’.//para’)) {

my $text_content = $xPara->text();

$text_content =~ s/TEXT/text/s;

$xPara->set_text($text_content);

}

It turns out this is incorrect because it blows away the <link> tag but leaves it’s PCDATA content.The thing to remember here is that there are 3 children to the <para> tag. they are the first PCDATA node (the text before the link node), the <link> node, and the second PCDATA node (after the link node).

Here is some code that updates the XML correctly.

foreach my $xPara ($xRoot->get_xpath(’.//para’)) {

foreach my $xChild ($xPara->children()) {

if($xChild->is_text()) {

my $text_content = $xChild->text();

$text_content =~ s/TEXT/text/s;

$xChild->set_text($text_content);

}

}

}

24
Jan

File::Find and a need for a closure

Say you need to recurse through a directory and it’s subdirectories for files. Think File::Find. Say you need to query a database for each file you find during the recursive search. Think closure. The “wanted” function reference that is passed to the “find()” function does not except arguments but you need to access data that is outside the scope of this “wanted” function.

The scope of the database handle makes it invisible to the “process_files” function. A closure seems to be a good solution to providing access to it.

package MyPackage;
use strict;
 use base 'MyAppBase';
 use File::Find;
sub run {
 my $self = shift;
 my $dbh = $self->database(); # active DBI connection handle
 my $conf = $self->conf();
sub get_dbh { return $dbh; } # Closure
my $dir_to_search = $conf->{foo_dir};
find(\&process_files, ($dir_to_search));
}
sub process_files {
 my $in_file = $File::Find::name;return unless -f $in_file;
my $dbh = get_dbh(); # use closure
my $sql = "SELECT * FROM TABLE WHERE FILENAME = ?";
my $sth = $dbh->prepare_cached($sql);
$sth->execute($in_file);
my $dbrec = $sth->fetchrow_hashref();
}
05
Dec

WebService::MusicBrainz example

I received an email asking how to access track information using a release title. Below is an example of how this is done.

use strict;
use WebService::MusicBrainz::Release;
use WebService::MusicBrainz::Track;
my $album = "Parachutes";
my $ws = WebService::MusicBrainz::Release->new();
# broad search based on album title
my $response = $ws->search({ TITLE => $album });
# get first match of the release
my $first_match = $response->release();
# now that we know MBID, lets ask for track details
my $release_search = $ws->search({ MBID => $first_match->id(),
                                   INC => 'tracks' });
# get first match with track details
my $release_search_first = $release_search->release();
print "Amazon ASIN : ", $release_search_first->asin(), "\n";
my $track_ws = WebService::MusicBrainz::Track->new();
# track number is not part of the web service data so let's create our own
my $track_num = 0;
foreach my $track (@{ $release_search_first->track_list()->tracks() }) {
    $track_num++;
    # query track data with artist details
    # artist at the release level could be "Various Artists",
    #   so we need to query each track for it's artist
    my $track_response = $track_ws->search({ MBID => $track->id(),
                                             INC => 'artist' });
    my $found_track = $track_response->track();
    print $track_num, ": ", $found_track->title(), " - ",
          $found_track->artist()->sort_name(), "\n";
}

Here is the output from this example:

Amazon ASIN : B00004U9MS
1: Don’t Panic – Coldplay
2: Shiver – Coldplay
3: Spies – Coldplay
4: Sparks – Coldplay
5: Yellow – Coldplay
6: Trouble – Coldplay
7: Parachutes – Coldplay
8: High Speed – Coldplay
9: We Never Change – Coldplay
10: Everything’s Not Lost / Life Is for Living – Coldplay