1use strict; 2package XML::XBEL; 3 4use base qw (XML::XBEL::item 5 XML::XBEL::container); 6 7# $Id: XBEL.pm,v 1.9 2005/04/02 20:54:52 asc Exp $ 8 9=head1 NAME 10 11XML::XBEL - OOP for reading and writing XBEL documents. 12 13=head1 SYNOPSIS 14 15 # creating an XBEL document 16 17 use XML::XBEL; 18 use XML::XBEL::Folder; 19 use XML::XBEL::Bookmark; 20 21 my $xbel = XML::XBEL->new(); 22 $xbel->new_document({title=>"My Bookmarks"}); 23 24 $xbel->add_bookmark({href => "http://foo.com", 25 title => "foo", 26 desc => "bar"}); 27 28 my $folder1 = XML::XBEL::Folder->new({title => "comp"}); 29 my $folder2 = XML::XBEL::Folder->new({title => "lang"}); 30 my $folder3 = XML::XBEL::Folder->new({title => "perl"}); 31 32 my $bm = XML::XBEL::Bookmark->new({"title=>"misc"}); 33 $bm->href("http://groups.google.com/groups?q=comp.lang.perl.misc"); 34 35 $folder3->add_bookmark($bm); 36 $folder2->add_folder($folder3); 37 $folder1->add_folder($folder2); 38 39 $xbel->add_folder($folder1); 40 41 print $xbel->toString(); 42 43 # parsing an XBEL document 44 45 use XML::XBEL; 46 47 my $xbel = XML::XBEL->new(); 48 $xbel->parse_file($file); 49 50 foreach my $bm ($xbel->bookmarks()) { 51 52 print sprintf("%s points to %s\n", 53 $bm->title(), 54 $bm->href()); 55 } 56 57=head1 DESCRIPTION 58 59OOP for reading and writing XBEL files. 60 61=cut 62 63$XML::XBEL::VERSION = '1.4'; 64 65use XML::LibXML; 66 67=head1 PACKAGE METHODS 68 69=cut 70 71=head2 __PACKAGE__->new() 72 73Returns an I<XML::XBEL> object. 74 75=cut 76 77sub new { 78 my $pkg = shift; 79 80 return bless {'__doc' => undef, 81 '__root' => undef } , $pkg; 82} 83 84=head1 OBJECT METHODS 85 86=cut 87 88=head2 $self->parse_file($file) 89 90Returns true or false. 91 92=cut 93 94sub parse_file { 95 my $self = shift; 96 my $file = shift; 97 98 my $parser = XML::LibXML->new(); 99 my $doc = $parser->parse_file($file); 100 101 return $self->_parse($doc); 102} 103 104=head2 $self->parse_string($string) 105 106Returns true or false. 107 108=cut 109 110sub parse_string { 111 my $self = shift; 112 my $str = shift; 113 114 my $parser = XML::LibXML->new(); 115 my $doc = $parser->parse_string($str); 116 117 return $self->_parse($doc); 118} 119 120sub _parse { 121 my $self = shift; 122 my $doc = shift; 123 124 $self->{'__doc'} = $doc; 125 $self->{'__root'} = $doc->documentElement(); 126 127 return 1; 128} 129 130=head2 $obj->new_document(\%args) 131 132Valid arguments are : 133 134=over 4 135 136=item * B<title> 137 138String. 139 140=item * B<desc> 141 142String. 143 144=item * B<info> 145 146Hash ref, with the following key/value pairs : 147 148=over 6 149 150=item * I<owner> 151 152Array ref. 153 154=back 155 156=back 157 158Returns true or false. 159 160=cut 161 162sub new_document { 163 my $self = shift; 164 my $args = shift; 165 166 my $doc = XML::LibXML::Document->new(); 167 168 if ($args->{encoding}) { 169 $doc->setEncoding($args->{encoding}); 170 } 171 172 my $root = XML::LibXML::Element->new("xbel"); 173 $doc->setDocumentElement($root); 174 175 $self->{'__doc'} = $doc; 176 $self->{'__root'} = $root; 177 178 foreach my $el ("title","desc","info") { 179 180 if (! exists($args->{$el})) { 181 next; 182 } 183 184 $self->$el($args->{$el}); 185 } 186 187 return 1; 188} 189 190=head2 $obj->title($title) 191 192Get/set the title for an XBEL document. 193 194Returns a string when called with no arguments; 195otherwise returns true or false. 196 197=cut 198 199# Defined in XML::XBEL::item 200 201=head2 $obj->desc($description) 202 203Get/set the description for an XBEL document. 204 205Returns a string when called with no arguments; 206otherwise returns true or false. 207 208=cut 209 210# Defined in XML::XBEL::item 211 212=head2 $obj->info(\%args) 213 214Get/set the metadata for an XBEL document. 215 216Valid args are : 217 218=over 4 219 220=item * B<owner> 221 222Array reference 223 224=back 225 226Returns an array reference when called with no arguments; 227otherwise returns true or false. 228 229=cut 230 231# Defined in XML::XBEL::info 232 233=head2 $obj->bookmarks($recursive) 234 235Returns a list of child I<XML::XBEL::Bookmark> objects. 236 237Where I<$recursive> is a boolean indicating whether to 238return all the bookmarks in an XBEL document or only its 239immediate children. 240 241=cut 242 243# Defined in XML::XBEL::container 244 245=head2 $obj->folders($recursive) 246 247Returns a list of child I<XML::XBEL::Folder> objects. 248 249Where I<$recursive> is a boolean indicating whether to 250return all the folders in an XBEL document or only its 251immediate children. 252 253=cut 254 255# Defined in XML::XBEL::container 256 257=head2 $obj->aliases($recursive) 258 259Returns a list of child I<XML::XBEL::Alias> objects. 260 261Where I<$recursive> is a boolean indicating whether to 262return all the aliases in an XBEL document or only its 263immediate children. 264 265=cut 266 267# Defined in XML::XBEL::container 268 269=head2 $obj->find_by_id($id) 270 271Returns an I<XML::XBEL::Bookmark> or I<XML::XBEL::Folder> 272object whose id attribute matches $id. 273 274=cut 275 276sub find_by_id { 277 my $self = shift; 278 my $id = shift; 279 280 my $node = ($self->{'__root'}->findnodes("//child::*[\@id='$id']"))[0]; 281 282 # print sprintf("%s %s\n",$node,$node->nodeName()); 283 284 if (! $node) { 285 return undef; 286 } 287 288 elsif ($node->nodeName() eq "folder") { 289 require XML::XBEL::Folder; 290 return XML::XBEL::Folder->build_node($node); 291 } 292 293 elsif ($node->nodeName() eq "bookmark") { 294 require XML::XBEL::Bookmark; 295 return XML::XBEL::Bookmark->build_node($node); 296 } 297 298 else { 299 return undef; 300 } 301} 302 303=head2 $obj->find_by_href($href) 304 305Returns a list of I<XML::XBEL::Bookmark> objects whose 306href attribute matches $href. 307 308=cut 309 310sub find_by_href { 311 my $self = shift; 312 my $href = shift; 313 314 my @nodes = $self->{'__root'}->findnodes("//child::*[name()='bookmark' and \@href='$href']"); 315 316 if (! @nodes) { 317 return undef; 318 } 319 320 require XML::XBEL::Bookmark; 321 322 return map { 323 XML::XBEL::Bookmark->build_node($_); 324 } @nodes 325} 326 327=head2 $obj->add_bookmark((XML::XBEL::Bookmark || \%args)) 328 329Add a new bookmark to an XBEL document. 330 331If passed a hash ref, valid arguments are the same as those 332defined for the I<XML::XBEL::Bookmark> object constructor. 333 334=cut 335 336# Defined in XML::XBEL::container 337 338=head2 $obj->add_folder((XML::XBEL::Folder || \%args)) 339 340Add a new folder to an XBEL document. 341 342If passed a hash ref, valid arguments are the same as those 343defined for the I<XML::XBEL::Folder> object constructor. 344 345=cut 346 347# Defined in XML::XBEL::container 348 349=head2 $obj->add_alias((XML::XBEL::Alias || \%args)) 350 351Add a new alias to an XBEL document. 352 353If passed a hash ref, valid arguments are the same as those 354defined for the I<XML::XBEL::Alias> object constructor. 355 356=cut 357 358# Defined in XML::XBEL::container 359 360=head2 $obj->add_separator() 361 362Add a new separator to an XBEL document. 363 364=cut 365 366# Defined in XML::XBEL::container 367 368=head2 $obj->toString($format) 369 370=cut 371 372sub toString { 373 my $self = shift; 374 $self->{'__doc'}->toString(@_); 375} 376 377=head2 $obj->toFile($filename,$format) 378 379=cut 380 381sub toFile { 382 my $self = shift; 383 $self->{'__doc'}->toString(@_); 384} 385 386=head2 $obj->toFH(\*$fh,$format) 387 388=cut 389 390sub toFH { 391 my $self = shift; 392 $self->{'__doc'}->toString(@_); 393} 394 395=head2 $obj->toSAX(A::SAX::Handler) 396 397Generate SAX events for the XBEL object. 398 399=cut 400 401sub toSAX { 402 my $self = shift; 403 my $handler = shift; 404 405 require XML::LibXML::SAX::Parser; 406 my $gen = XML::LibXML::SAX::Parser->new(Handler => $handler); 407 $gen->generate($self->{'__doc'}); 408} 409 410=head1 VERSION 411 4121.4 413 414=head1 DATE 415 416$Date: 2005/04/02 20:54:52 $ 417 418=head1 AUTHOR 419 420Aaron Straup Cope E<lt>ascope@cpan.orgE<gt> 421 422=head1 SEE ALSO 423 424L<XML::XBEL::Folder> 425 426L<XML::XBEL::Bookmark> 427 428L<XML::XBEL::Alias> 429 430L<XML::XBEL::Separator> 431 432=head1 BUGS 433 434It's possible. Please report all bugs via http://rt.cpan.org 435 436=head1 LICENSE 437 438Copyright (c) 2004 Aaron Straup Cope. All rights reserved. 439 440This is free software, you may use it and distribute it under the 441same terms as Perl itself. 442 443=cut 444 445return 1; 446