};
close FH or die "close($_[0]): $!";
return $string;
}
END_OLD
sub _readperl {
my $string = Module::Install::_read($_[0]);
$string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg;
$string =~ s/(\n)\n*__(?:DATA|END)__\b.*\z/$1/s;
$string =~ s/\n\n=\w+.+?\n\n=cut\b.+?\n+/\n\n/sg;
return $string;
}
sub _readpod {
my $string = Module::Install::_read($_[0]);
$string =~ s/(?:\015{1,2}\012|\015|\012)/\n/sg;
return $string if $_[0] =~ /\.pod\z/;
$string =~ s/(^|\n=cut\b.+?\n+)[^=\s].+?\n(\n=\w+|\z)/$1$2/sg;
$string =~ s/\n*=pod\b[^\n]*\n+/\n\n/sg;
$string =~ s/\n*=cut\b[^\n]*\n+/\n\n/sg;
$string =~ s/^\n+//s;
return $string;
}
# Done in evals to avoid confusing Perl::MinimumVersion
eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@;
sub _write {
local *FH;
open( FH, '>', $_[0] ) or die "open($_[0]): $!";
foreach ( 1 .. $#_ ) {
print FH $_[$_] or die "print($_[0]): $!";
}
close FH or die "close($_[0]): $!";
}
END_NEW
sub _write {
local *FH;
open( FH, "> $_[0]" ) or die "open($_[0]): $!";
foreach ( 1 .. $#_ ) {
print FH $_[$_] or die "print($_[0]): $!";
}
close FH or die "close($_[0]): $!";
}
END_OLD
# _version is for processing module versions (eg, 1.03_05) not
# Perl versions (eg, 5.8.1).
sub _version ($) {
my $s = shift || 0;
my $d =()= $s =~ /(\.)/g;
if ( $d >= 2 ) {
# Normalise multipart versions
$s =~ s/(\.)(\d{1,3})/sprintf("$1%03d",$2)/eg;
}
$s =~ s/^(\d+)\.?//;
my $l = $1 || 0;
my @v = map {
$_ . '0' x (3 - length $_)
} $s =~ /(\d{1,3})\D?/g;
$l = $l . '.' . join '', @v if @v;
return $l + 0;
}
sub _cmp ($$) {
_version($_[1]) <=> _version($_[2]);
}
# Cloned from Params::Util::_CLASS
sub _CLASS ($) {
(
defined $_[0]
and
! ref $_[0]
and
$_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s
) ? $_[0] : undef;
}
1;
# Copyright 2008 - 2012 Adam Kennedy.
HTML-Microformats-0.105/inc/Module/Package/ 0000755 0000764 0000764 00000000000 11775404022 016405 5 ustar tai tai HTML-Microformats-0.105/inc/Module/Package/Dist/ 0000755 0000764 0000764 00000000000 11775404022 017310 5 ustar tai tai HTML-Microformats-0.105/inc/Module/Package/Dist/RDF.pm 0000644 0000764 0000764 00000001374 11775403731 020274 0 ustar tai tai #line 1
package Module::Package::Dist::RDF;
my $explanation = q<
This is the component of Module::Package::RDF which gets
bundled with the distribution.
>;
use 5.005;
use strict;
BEGIN {
$Module::Package::Dist::RDF::AUTHORITY = 'cpan:TOBYINK';
$Module::Package::Dist::RDF::VERSION = '0.008';
@Module::Package::Dist::RDF::ISA = 'Module::Package::Dist';
}
sub _main
{
my ($self) = @_;
$self->mi->trust_meta_yml;
$self->mi->auto_install;
}
{
package Module::Package::Dist::RDF::standard;
use 5.005;
use strict;
BEGIN {
$Module::Package::Dist::RDF::standard::AUTHORITY = 'cpan:TOBYINK';
$Module::Package::Dist::RDF::standard::VERSION = '0.008';
@Module::Package::Dist::RDF::standard::ISA = 'Module::Package::Dist::RDF';
}
}
1;
HTML-Microformats-0.105/t/ 0000755 0000764 0000764 00000000000 11775404022 013317 5 ustar tai tai HTML-Microformats-0.105/t/01basic.t 0000644 0000764 0000764 00000000104 11663405777 014737 0 ustar tai tai use Test::More tests => 1;
BEGIN { use_ok('HTML::Microformats') };
HTML-Microformats-0.105/t/12hatom.t 0000644 0000764 0000764 00000004214 11663405777 014776 0 ustar tai tai use Test::More tests => 10;
use HTML::Microformats;
my $html = <<'HTML';
Alice
HTML
my $document = HTML::Microformats->new_document($html, 'http://example.com/');
$document->assume_all_profiles;
my ($blog, $news) = sort { $a->element->getAttribute('id') cmp $b->element->getAttribute('id') }
$document->objects('hAtom');
my @blog_entries = @{ $blog->get_entry };
is( scalar @blog_entries,
2,
"Two entries found in blog.");
my @news_entries = @{ $news->get_entry };
is( scalar @news_entries,
1,
"One entry found in news.");
ok($news_entries[0]->isa('HTML::Microformats::Format::hNews'),
'News item is a news item');
ok($news_entries[0]->isa('HTML::Microformats::Format::hEntry'),
'News item is an entry');
is($news_entries[0]->data->{title},
'First',
'News item has correct entry-title');
is($news_entries[0]->get_author->[0]->get_fn,
'Alice',
'Implied author');
is($news_entries[0]->get_geo->[0]->get_latitude,
'0',
'News item has a geo');
my ($votelink) = $document->objects('VoteLinks');
is($votelink->get_voter->[0]->get_fn,
'Alice',
'hEntry propagates authors to VoteLinks');
is($blog_entries[0]->data->{content},
'HelloWorld',
'Multiple entry-content elements concatenated');
is($document->model->count_statements(
undef,
RDF::Trine::Node::Resource->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
RDF::Trine::Node::Resource->new('http://bblfish.net/work/atom-owl/2006-06-06/#Entry'),
),
3,
'Three atom:Entry resources output (RDF)');
HTML-Microformats-0.105/t/11hcalendar.t 0000644 0000764 0000764 00000010126 11663405777 015605 0 ustar tai tai use Test::More tests => 13; # should add some more
use HTML::Microformats;
my $html = <<'HTML';
2001-02-03T01:02:03+0100
Event 01 - basic
3 Feb
Event 02 - value-title
3 Feb
Event 03 - value-title with space
2001-02-03
01:02:03
+0100
Event 04 - splitting things up
+0100
01:02:03
2001-02-03
Event 05 - mixing them up
Z
01:02:03
2001-02-03
Event 06 - testing 'Z' timezone
+0100
1am
2001-02-03
Event 07 - test 1am
+0100
1 pm
2001-02-03
Event 08 - test 1pm
+0100
01.02 p. M.
2001-02-03
Event 09 - test 01.02 p.M.
+0100
01.02.03 p.M.
2001-02-03
Event 10 - test 01.02.03 p.M.
+0100
01.02.03 p.M.
2001-02-03
1.7.3 pm
Event 11 - dtend feedthrough from dtstart (with 'value')
+0100
01.02.03 p.M.
2001-02-03
13:07:03
Event 12 - dtend feedthrough from dtstart (no 'value')
XXX 3 Feb
Todo 01 - invalid value-title
HTML
my $document = HTML::Microformats->new_document($html, 'http://example.com/');
$document->assume_all_profiles;
my ($calendar) = $document->objects('hCalendar');
my @events = sort { $a->data->{summary} cmp $b->data->{summary} }
@{ $calendar->get_vevent };
is($events[0]->get_dtstart,
'2001-02-03T01:02:03+0100',
$events[0]->get_summary);
is($events[1]->get_dtstart,
'2001-02-03T01:02:03+0100',
$events[1]->get_summary);
is($events[2]->get_dtstart,
'2001-02-03T01:02:03+0100',
$events[2]->get_summary);
is($events[3]->get_dtstart,
'2001-02-03T01:02:03+0100',
$events[3]->get_summary);
is($events[4]->get_dtstart,
'2001-02-03T01:02:03+0100',
$events[4]->get_summary);
is($events[5]->get_dtstart,
'2001-02-03T01:02:03+0000',
$events[5]->get_summary);
is($events[6]->get_dtstart,
'2001-02-03T01:00+0100',
$events[6]->get_summary);
is($events[7]->get_dtstart,
'2001-02-03T13:00+0100',
$events[7]->get_summary);
is($events[8]->get_dtstart,
'2001-02-03T13:02+0100',
$events[8]->get_summary);
is($events[9]->get_dtstart,
'2001-02-03T13:02:03+0100',
$events[9]->get_summary);
is($events[10]->get_dtend,
'2001-02-03T13:07:03+0100',
$events[10]->get_summary);
is($events[11]->get_dtend,
'2001-02-03T13:07:03+0100',
$events[11]->get_summary);
my @todos = sort { $a->data->{summary} cmp $b->data->{summary} }
@{ $calendar->get_vtodo };
is($todos[0]->get_dtstart,
undef,
$todos[0]->get_summary);
HTML-Microformats-0.105/t/14reltag.t 0000644 0000764 0000764 00000002523 11663405777 015147 0 ustar tai tai use Test::More tests => 8;
use HTML::Microformats;
my $html = <<'HTML';
Cats
HTML
my $document = HTML::Microformats->new_document($html, 'http://example.com/');
$document->assume_all_profiles;
my @tags = sort { $a->get_tag cmp $b->get_tag }
$document->objects('RelTag');
is($tags[0]->get_tag,
'Astronaut',
'tag Astronaut found');
is($tags[1]->get_tag,
'Bees',
'tag Bees found');
is($tags[2]->get_tag,
'Cats',
'tag Cats found');
for my $i (0..2)
{
is($tags[$i]->get_tagspace,
'http://example.com/tag/',
'tag has correct tag space');
}
my $model = $document->model;
is($model->count_statements(
RDF::Trine::Node::Resource->new('http://example.com/'),
RDF::Trine::Node::Resource->new('http://www.holygoat.co.uk/owl/redwood/0.1/tags/taggedWithTag'),
undef),
3,
'Page tagged with three tags.');
my ($armstrong) = $document->objects('hCard');
is($model->count_statements(
$armstrong->id(1),
RDF::Trine::Node::Resource->new('http://www.holygoat.co.uk/owl/redwood/0.1/tags/taggedWithTag'),
undef),
1,
'VCard tagged.');
HTML-Microformats-0.105/t/13xfn.t 0000644 0000764 0000764 00000004310 11663405777 014457 0 ustar tai tai use Test::More tests => 6;
use HTML::Microformats;
my $html = <<'HTML';
Alice
Bob
Carol
HTML
my $document = HTML::Microformats->new_document($html, 'http://alice.example.com/');
$document->assume_all_profiles;
my $model = $document->model;
ok($model->count_statements(
RDF::Trine::Node::Resource->new('http://alice.example.com/'),
RDF::Trine::Node::Resource->new('http://vocab.sindice.com/xfn#met-hyperlink'),
RDF::Trine::Node::Resource->new('mailto:bob@example.com'),
),
"XFN vocab *-hyperlink works."
);
my $iter = $model->get_statements(
undef,
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/page'),
RDF::Trine::Node::Resource->new('http://carol.example.com/'),
);
my $st = $iter->next;
my $carol = $st->subject;
ok($model->count_statements(
undef,
RDF::Trine::Node::Resource->new('http://vocab.sindice.com/xfn#met'),
$carol,
),
"Alice met Carol."
);
ok($model->count_statements(
$carol,
RDF::Trine::Node::Resource->new('http://vocab.sindice.com/xfn#met'),
undef,
),
"Carol met Alice."
);
ok($model->count_statements(
undef,
RDF::Trine::Node::Resource->new('http://buzzword.org.uk/rdf/xen#nemesis'),
$carol,
),
"XEN profile detected."
);
ok($model->count_statements(
undef,
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/knows'),
$carol,
),
"Infer foaf:knowses."
);
ok($model->count_statements(
undef,
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/mbox'),
RDF::Trine::Node::Resource->new('mailto:bob@example.com'),
),
"mailto: links treated as mbox rather than page."
);
#use RDF::TrineShortcuts;
#$RDF::TrineShortcuts::Namespaces->{'vx'} = 'http://buzzword.org.uk/rdf/vcardx#';
#$RDF::TrineShortcuts::Namespaces->{'hcard'} = 'http://purl.org/uF/hCard/terms/';
#$RDF::TrineShortcuts::Namespaces->{'xfn'} = 'http://vocab.sindice.com/xfn#';
#$RDF::TrineShortcuts::Namespaces->{'xen'} = 'http://buzzword.org.uk/rdf/xen#';
#diag rdf_string($model => 'rdfxml');
HTML-Microformats-0.105/t/15rellicense.t 0000644 0000764 0000764 00000002650 11663405777 016020 0 ustar tai tai use Test::More tests => 8;
use HTML::Microformats;
my $html = <<'HTML';
License
HTML
my $document = HTML::Microformats->new_document($html, 'http://example.com/');
$document->assume_all_profiles;
my ($l) = $document->objects('RelLicense');
is($l->get_href,
'http://example.com/l',
'License URI correct.');
is($l->get_title,
'License',
'License title correct');
is($l->get_label,
'Lic',
'License label correct');
my $model = $document->model;
foreach my $uri (qw(http://creativecommons.org/ns#license
http://www.w3.org/1999/xhtml/vocab#license
http://purl.org/dc/terms/license))
{
ok($model->count_statements(
RDF::Trine::Node::Resource->new('http://example.com/'),
RDF::Trine::Node::Resource->new($uri),
RDF::Trine::Node::Resource->new('http://example.com/l')),
"RDF Predicate <$uri> set");
}
ok($model->count_statements(
RDF::Trine::Node::Resource->new('http://example.com/'),
RDF::Trine::Node::Resource->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
RDF::Trine::Node::Resource->new('http://creativecommons.org/ns#Work')),
"cc:Work set");
ok($model->count_statements(
RDF::Trine::Node::Resource->new('http://example.com/l'),
RDF::Trine::Node::Resource->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
RDF::Trine::Node::Resource->new('http://creativecommons.org/ns#License')),
"cc:License set");
HTML-Microformats-0.105/t/10hcard.t 0000644 0000764 0000764 00000004202 11663405777 014742 0 ustar tai tai use Test::More tests => 10;
use HTML::Microformats;
my $html = <<'HTML';
My Org
General Enquiries:
+44 1234 567 890
Fax:
+44 1234 567 891
Help Desk
+44 1234 567 899
HTML
my $document = HTML::Microformats->new_document($html, 'http://example.com/');
$document->assume_all_profiles;
my @cards = sort { $a->data->{fn} cmp $b->data->{fn} }
$document->objects('hCard');
is($cards[0]->get_kind,
'group',
'Auto-detect group kind.');
is($cards[1]->get_kind,
'org',
'Auto-detect organisation kind.');
is($cards[0]->element->tagName,
'p',
'Can get links back to elements.');
is($cards[1]->get_tel->[0]->get_value,
'tel:+441234567890',
'Parsed tel without type+value');
is($cards[1]->get_tel->[1]->get_value,
'tel:+441234567891',
'Parsed tel with type+value');
is($cards[1]->get_agent->[0],
$cards[0],
'Agent works OK');
my $model = $document->model;
ok($model->count_statements(
$cards[1]->id(1),
RDF::Trine::Node::Resource->new('http://www.w3.org/2006/vcard/ns#agent'),
$cards[0]->id(1),
),
"Agent works OK (RDF)"
);
ok($model->count_statements(
$cards[1]->id(1),
RDF::Trine::Node::Resource->new('http://www.w3.org/2006/vcard/ns#fn'),
RDF::Trine::Node::Literal->new('My Org', 'en'),
),
"Languages work OK (RDF)"
);
ok($model->count_statements(
$cards[1]->id(1, 'holder'),
RDF::Trine::Node::Resource->new('http://purl.org/uF/hCard/terms/hasCard'),
$cards[1]->id(1),
),
"Differentiates between vcards and their holders (RDF)"
);
ok($model->count_statements(
$cards[1]->id(1, 'holder'),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/name'),
RDF::Trine::Node::Literal->new('My Org', 'en'),
),
"Infers information about vcard holder from the vcard (RDF)"
);
HTML-Microformats-0.105/README 0000644 0000764 0000764 00000021622 11775403731 013745 0 ustar tai tai NAME
HTML::Microformats - parse microformats in HTML
SYNOPSIS
use HTML::Microformats;
my $doc = HTML::Microformats
->new_document($html, $uri)
->assume_profile(qw(hCard hCalendar));
print $doc->json(pretty => 1);
use RDF::TrineShortcuts qw(rdf_query);
my $results = rdf_query($sparql, $doc->model);
DESCRIPTION
The HTML::Microformats module is a wrapper for parser and handler
modules of various individual microformats (each of those modules has a
name like HTML::Microformats::Format::Foo).
The general pattern of usage is to create an HTML::Microformats object
(which corresponds to an HTML document) using the "new_document" method;
then ask for the data, as a Perl hashref, a JSON string, or an
RDF::Trine model.
Constructor
"$doc = HTML::Microformats->new_document($html, $uri, %opts)"
Constructs a document object.
$html is the HTML or XHTML source (string) or an
XML::LibXML::Document.
$uri is the document URI, important for resolving relative URL
references.
%opts are additional parameters; currently only one option is
defined: $opts{'type'} is set to 'text/html' or
'application/xhtml+xml', to control how $html is parsed.
Profile Management
HTML::Microformats uses HTML profiles (i.e. the profile attribute on the
HTML element) to detect which Microformats are used on a page.
Any microformats which do not have a profile URI declared will not be
parsed.
Because many pages fail to properly declare which profiles they use,
there are various profile management methods to tell HTML::Microformats
to assume the presence of particular profile URIs, even if they're
actually missing.
"$doc->profiles"
This method returns a list of profile URIs declared by the document.
"$doc->has_profile(@profiles)"
This method returns true if and only if one or more of the profile
URIs in @profiles is declared by the document.
"$doc->add_profile(@profiles)"
Using "add_profile" you can add one or more profile URIs, and they
are treated as if they were found on the document.
For example:
$doc->add_profile('http://microformats.org/profile/rel-tag')
This is useful for adding profile URIs declared outside the document
itself (e.g. in HTTP headers).
Returns a reference to the document.
"$doc->assume_profile(@microformats)"
For example:
$doc->assume_profile(qw(hCard adr geo))
This method acts similarly to "add_profile" but allows you to use
names of microformats rather than URIs.
Microformat names are case sensitive, and must match
HTML::Microformats::Format::Foo module names.
Returns a reference to the document.
"$doc->assume_all_profiles"
This method is equivalent to calling "assume_profile" for all known
microformats.
Returns a reference to the document.
Parsing Microformats
Generally speaking, you can skip this. The "data", "json" and "model"
methods will automatically do this for you.
"$doc->parse_microformats"
Scans through the document, finding microformat objects.
On subsequent calls, does nothing (as everything is already parsed).
Returns a reference to the document.
"$doc->clear_microformats"
Forgets information gleaned by "parse_microformats" and thus allows
"parse_microformats" to be run again. This is useful if you've
modified added some profiles between runs of "parse_microformats".
Returns a reference to the document.
Retrieving Data
These methods allow you to retrieve the document's data, and do things
with it.
"$doc->objects($format);"
$format is, for example, 'hCard', 'adr' or 'RelTag'.
Returns a list of objects of that type. (If called in scalar
context, returns an arrayref.)
Each object is, for example, an HTML::Microformat::hCard object, or
an HTML::Microformat::RelTag object, etc. See the relevent
documentation for details.
"$doc->all_objects"
Returns a hashref of data. Each hashref key is the name of a
microformat (e.g. 'hCard', 'RelTag', etc), and the values are
arrayrefs of objects.
Each object is, for example, an HTML::Microformat::hCard object, or
an HTML::Microformat::RelTag object, etc. See the relevent
documentation for details.
"$doc->json(%opts)"
Returns data roughly equivalent to the "all_objects" method, but as
a JSON string.
%opts is a hash of options, suitable for passing to the JSON
module's to_json function. The 'convert_blessed' and 'utf8' options
are enabled by default, but can be disabled by explicitly setting
them to 0, e.g.
print $doc->json( pretty=>1, canonical=>1, utf8=>0 );
"$doc->model"
Returns data as an RDF::Trine::Model, suitable for serialising as
RDF or running SPARQL queries.
"$object->serialise_model(as => $format)"
As "model" but returns a string.
"$doc->add_to_model($model)"
Adds data to an existing RDF::Trine::Model.
Returns a reference to the document.
Utility Functions
"HTML::Microformats->modules"
Returns a list of Perl modules, each of which implements a specific
microformat.
"HTML::Microformats->formats"
As per "modules", but strips 'HTML::Microformats::Format::' off the
module name, and sorts alphabetically.
WHY ANOTHER MICROFORMATS MODULE?
There already exist two microformats packages on CPAN (see
Text::Microformat and Data::Microformat), so why create another?
Firstly, HTML::Microformats isn't being created from scratch. It's
actually a fork/clean-up of a non-CPAN application (Swignition), and in
that sense predates Text::Microformat (though not Data::Microformat).
It has a number of other features that distinguish it from the existing
packages:
* It supports more formats.
HTML::Microformats supports hCard, hCalendar, rel-tag, geo, adr,
rel-enclosure, rel-license, hReview, hResume, hRecipe, xFolk, XFN,
hAtom, hNews and more.
* It supports more patterns.
HTML::Microformats supports the include pattern, abbr pattern, table
cell header pattern, value excerpting and other intricacies of
microformat parsing better than the other modules on CPAN.
* It offers RDF support.
One of the key features of HTML::Microformats is that it makes data
available as RDF::Trine models. This allows your application to
benefit from a rich, feature-laden Semantic Web toolkit. Data
gleaned from microformats can be stored in a triple store; output in
RDF/XML or Turtle; queried using the SPARQL or RDQL query languages;
and more.
If you're not comfortable using RDF, HTML::Microformats also makes
all its data available as native Perl objects.
BUGS
Please report any bugs to .
SEE ALSO
HTML::Microformats::Documentation::Notes.
Individual format modules:
* HTML::Microformats::Format::adr
* HTML::Microformats::Format::figure
* HTML::Microformats::Format::geo
* HTML::Microformats::Format::hAtom
* HTML::Microformats::Format::hAudio
* HTML::Microformats::Format::hCalendar
* HTML::Microformats::Format::hCard
* HTML::Microformats::Format::hListing
* HTML::Microformats::Format::hMeasure
* HTML::Microformats::Format::hNews
* HTML::Microformats::Format::hProduct
* HTML::Microformats::Format::hRecipe
* HTML::Microformats::Format::hResume
* HTML::Microformats::Format::hReview
* HTML::Microformats::Format::hReviewAggregate
* HTML::Microformats::Format::OpenURL_COinS
* HTML::Microformats::Format::RelEnclosure
* HTML::Microformats::Format::RelLicense
* HTML::Microformats::Format::RelTag
* HTML::Microformats::Format::species
* HTML::Microformats::Format::VoteLinks
* HTML::Microformats::Format::XFN
* HTML::Microformats::Format::XMDP
* HTML::Microformats::Format::XOXO
Similar modules: RDF::RDFa::Parser, HTML::HTML5::Microdata::Parser,
XML::Atom::Microformats, Text::Microformat, Data::Microformats.
Related web sites: ,
.
AUTHOR
Toby Inkster .
COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
HTML-Microformats-0.105/lib/ 0000755 0000764 0000764 00000000000 11775404022 013622 5 ustar tai tai HTML-Microformats-0.105/lib/HTML/ 0000755 0000764 0000764 00000000000 11775404022 014366 5 ustar tai tai HTML-Microformats-0.105/lib/HTML/Microformats.pm 0000644 0000764 0000764 00000030344 11775403507 017404 0 ustar tai tai package HTML::Microformats;
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::HTML5::Parser;
use HTML::HTML5::Sanity qw(fix_document);
use HTML::Microformats::DocumentContext;
use HTML::Microformats::Datatype;
use HTML::Microformats::Format;
use JSON;
use RDF::Trine 0.130;
use XML::LibXML;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::VERSION = '0.105';
}
sub new_document
{
my $class = shift;
my $document = shift;
my $uri = shift;
my %opts = @_;
my $self = bless {}, $class;
$self->modules; # force modules to be loaded
if (ref $document && $document->isa('XML::LibXML::Document'))
{
}
elsif ($opts{'type'} =~ /x(ht)?ml/i)
{
my $parser = XML::LibXML->new;
$document = $parser->parse_string($document);
}
else
{
my $parser = HTML::HTML5::Parser->new;
$document = fix_document( $parser->parse_string($document) );
}
$self->{'context'} = HTML::Microformats::DocumentContext->new($document, $uri);
return $self;
}
sub profiles
{
my $self = shift;
return $self->{'context'}->profiles(@_);
}
sub has_profile
{
my $self = shift;
return $self->{'context'}->has_profile(@_);
}
sub add_profile
{
my $self = shift;
$self->{'context'}->add_profile(@_);
return $self;
}
sub assume_profile
{
my $self = shift;
foreach my $fmt (@_)
{
my $profile = $fmt;
($profile) = "HTML::Microformats::Format::${fmt}"->profiles
if $fmt !~ ':';
$self->add_profile($profile);
}
return $self;
}
sub assume_all_profiles
{
my $self = shift;
$self->assume_profile($self->formats);
return $self;
}
sub parse_microformats
{
my $self = shift;
return if $self->{'parsed'};
foreach my $fmt ($self->formats)
{
my @profiles = "HTML::Microformats::Format::${fmt}"->profiles;
if ($self->has_profile(@profiles))
{
my @objects = "HTML::Microformats::Format::${fmt}"->extract_all(
$self->{'context'}->document->documentElement,
$self->{'context'});
$self->{'objects'}->{$fmt} = \@objects;
}
}
$self->{'parsed'} = 1;
return $self;
}
sub clear_microformats
{
my $self = shift;
$self->{'objects'} = undef;
$self->{'context'}->cache->clear;
$self->{'parsed'} = 0;
return $self;
}
sub objects
{
my $self = shift;
my $fmt = shift;
$self->parse_microformats;
return @{ $self->{'objects'}->{$fmt} }
if wantarray;
return $self->{'objects'}->{$fmt};
}
sub all_objects
{
my $self = shift;
$self->parse_microformats;
return $self->{'objects'};
}
sub TO_JSON
{
return $_[0]->all_objects;
}
sub json
{
my $self = shift;
my %opts = @_;
$opts{'convert_blessed'} = 1
unless defined $opts{'convert_blessed'};
$opts{'utf8'} = 1
unless defined $opts{'utf8'};
return to_json($self->all_objects, \%opts);
}
sub model
{
my $self = shift;
my $model = RDF::Trine::Model->temporary_model;
$self->add_to_model($model);
return $model;
}
sub serialise_model
{
my $self = shift;
my %opts = ref $_[0] ? %{ $_[0] } : @_;
$opts{as} ||= 'Turtle';
my $ser = RDF::Trine::Serializer->new(delete $opts{as}, %opts);
return $ser->serialize_model_to_string($self->model);
}
sub add_to_model
{
my $self = shift;
my $model = shift;
$self->parse_microformats;
foreach my $fmt ($self->formats)
{
foreach my $object (@{ $self->{'objects'}->{$fmt} })
{
$object->add_to_model($model);
}
}
return $self;
}
use Module::Pluggable
require => 1,
inner => 0,
search_path => ['HTML::Microformats::Format'],
only => qr/^HTML::Microformats::Format::[^:]+$/,
sub_name => 'modules',
;
sub formats
{
my $class = shift || __PACKAGE__;
return
sort { lc $a cmp lc $b }
map { s/^HTML::Microformats::Format:://; $_ }
$class->modules;
}
1;
__END__
=head1 NAME
HTML::Microformats - parse microformats in HTML
=head1 SYNOPSIS
use HTML::Microformats;
my $doc = HTML::Microformats
->new_document($html, $uri)
->assume_profile(qw(hCard hCalendar));
print $doc->json(pretty => 1);
use RDF::TrineShortcuts qw(rdf_query);
my $results = rdf_query($sparql, $doc->model);
=head1 DESCRIPTION
The HTML::Microformats module is a wrapper for parser and handler
modules of various individual microformats (each of those modules
has a name like HTML::Microformats::Format::Foo).
The general pattern of usage is to create an HTML::Microformats
object (which corresponds to an HTML document) using the
C method; then ask for the data, as a Perl hashref,
a JSON string, or an RDF::Trine model.
=head2 Constructor
=over 4
=item C<< $doc = HTML::Microformats->new_document($html, $uri, %opts) >>
Constructs a document object.
$html is the HTML or XHTML source (string) or an XML::LibXML::Document.
$uri is the document URI, important for resolving relative URL references.
%opts are additional parameters; currently only one option is defined:
$opts{'type'} is set to 'text/html' or 'application/xhtml+xml', to
control how $html is parsed.
=back
=head2 Profile Management
HTML::Microformats uses HTML profiles (i.e. the profile attribute on the
HTML element) to detect which Microformats are used on a page. Any
microformats which do not have a profile URI declared will not be parsed.
Because many pages fail to properly declare which profiles they use, there
are various profile management methods to tell HTML::Microformats to
assume the presence of particular profile URIs, even if they're actually
missing.
=over 4
=item C<< $doc->profiles >>
This method returns a list of profile URIs declared by the document.
=item C<< $doc->has_profile(@profiles) >>
This method returns true if and only if one or more of the profile URIs
in @profiles is declared by the document.
=item C<< $doc->add_profile(@profiles) >>
Using C you can add one or more profile URIs, and they are
treated as if they were found on the document.
For example:
$doc->add_profile('http://microformats.org/profile/rel-tag')
This is useful for adding profile URIs declared outside the document itself
(e.g. in HTTP headers).
Returns a reference to the document.
=item C<< $doc->assume_profile(@microformats) >>
For example:
$doc->assume_profile(qw(hCard adr geo))
This method acts similarly to C but allows you to use
names of microformats rather than URIs.
Microformat names are case sensitive, and must match
HTML::Microformats::Format::Foo module names.
Returns a reference to the document.
=item C<< $doc->assume_all_profiles >>
This method is equivalent to calling C for
all known microformats.
Returns a reference to the document.
=back
=head2 Parsing Microformats
Generally speaking, you can skip this. The C, C and
C methods will automatically do this for you.
=over 4
=item C<< $doc->parse_microformats >>
Scans through the document, finding microformat objects.
On subsequent calls, does nothing (as everything is already parsed).
Returns a reference to the document.
=item C<< $doc->clear_microformats >>
Forgets information gleaned by C and thus allows
C to be run again. This is useful if you've modified
added some profiles between runs of C.
Returns a reference to the document.
=back
=head2 Retrieving Data
These methods allow you to retrieve the document's data, and do things
with it.
=over 4
=item C<< $doc->objects($format); >>
$format is, for example, 'hCard', 'adr' or 'RelTag'.
Returns a list of objects of that type. (If called in scalar context,
returns an arrayref.)
Each object is, for example, an HTML::Microformat::hCard object, or an
HTML::Microformat::RelTag object, etc. See the relevent documentation
for details.
=item C<< $doc->all_objects >>
Returns a hashref of data. Each hashref key is the name of a microformat
(e.g. 'hCard', 'RelTag', etc), and the values are arrayrefs of objects.
Each object is, for example, an HTML::Microformat::hCard object, or an
HTML::Microformat::RelTag object, etc. See the relevent documentation
for details.
=item C<< $doc->json(%opts) >>
Returns data roughly equivalent to the C method, but as a JSON
string.
%opts is a hash of options, suitable for passing to the L
module's to_json function. The 'convert_blessed' and 'utf8' options are
enabled by default, but can be disabled by explicitly setting them to 0, e.g.
print $doc->json( pretty=>1, canonical=>1, utf8=>0 );
=item C<< $doc->model >>
Returns data as an RDF::Trine::Model, suitable for serialising as
RDF or running SPARQL queries.
=item C<< $object->serialise_model(as => $format) >>
As C but returns a string.
=item C<< $doc->add_to_model($model) >>
Adds data to an existing RDF::Trine::Model.
Returns a reference to the document.
=back
=head2 Utility Functions
=over 4
=item C<< HTML::Microformats->modules >>
Returns a list of Perl modules, each of which implements a specific
microformat.
=item C<< HTML::Microformats->formats >>
As per C, but strips 'HTML::Microformats::Format::' off the
module name, and sorts alphabetically.
=back
=head1 WHY ANOTHER MICROFORMATS MODULE?
There already exist two microformats packages on CPAN (see L
and L), so why create another?
Firstly, HTML::Microformats isn't being created from scratch. It's actually a
fork/clean-up of a non-CPAN application (Swignition), and in that sense
predates Text::Microformat (though not Data::Microformat).
It has a number of other features that distinguish it from the existing
packages:
=over 4
=item * It supports more formats.
HTML::Microformats supports hCard, hCalendar, rel-tag, geo, adr,
rel-enclosure, rel-license, hReview, hResume, hRecipe, xFolk, XFN,
hAtom, hNews and more.
=item * It supports more patterns.
HTML::Microformats supports the include pattern, abbr pattern, table cell
header pattern, value excerpting and other intricacies of microformat parsing
better than the other modules on CPAN.
=item * It offers RDF support.
One of the key features of HTML::Microformats is that it makes data
available as RDF::Trine models. This allows your application to benefit
from a rich, feature-laden Semantic Web toolkit. Data gleaned from
microformats can be stored in a triple store; output in RDF/XML or
Turtle; queried using the SPARQL or RDQL query languages; and more.
If you're not comfortable using RDF, HTML::Microformats also makes
all its data available as native Perl objects.
=back
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L.
Individual format modules:
=over 4
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=item * L
=back
Similar modules:
L,
L,
L,
L,
L.
Related web sites:
L, L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
HTML-Microformats-0.105/lib/HTML/Microformats/ 0000755 0000764 0000764 00000000000 11775404022 017033 5 ustar tai tai HTML-Microformats-0.105/lib/HTML/Microformats/Mixin/ 0000755 0000764 0000764 00000000000 11775404022 020117 5 ustar tai tai HTML-Microformats-0.105/lib/HTML/Microformats/Mixin/Parser.pm 0000644 0000764 0000764 00000065561 11775403507 021735 0 ustar tai tai package HTML::Microformats::Mixin::Parser;
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(/^search/);
use HTML::Microformats::Format::adr;
use HTML::Microformats::Datatype;
use HTML::Microformats::Format::geo;
use HTML::Microformats::Format::hAtom;
use HTML::Microformats::Format::hCalendar;
use HTML::Microformats::Format::hCard;
use HTML::Microformats::Format::hMeasure;
use HTML::Microformats::Format::RelEnclosure;
use HTML::Microformats::Format::RelLicense;
use HTML::Microformats::Format::RelTag;
use HTML::Microformats::Format::species;
use URI::URL;
use XML::LibXML qw(:all);
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Mixin::Parser::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Mixin::Parser::VERSION = '0.105';
}
# Cleans away nested compound microformats. Any intentionally
# nested microformats (e.g. vcard class="agent vcard") should be
# dealt with BEFORE calling the destroyer! Because of the
# destructive nature of this function, make sure that you only
# use it on a clone of the real node.
sub _destroyer
{
my $self = shift;
my $element = shift;
# Classes to be destroyed
my @containers = qw(mfo vcard adr geo vcalendar vevent vtodo valarm
vfreebusy hfeed hentry hslice hreview hresume xfolkentry biota haudio
hmeasure hangle hmoney hlisting vtodo-list figure hproduct hnews);
my %C;
foreach my $c (@containers) { $C{$c}=1; }
# Some classes may be retained, optionally.
foreach my $c (@_) { $C{$c}=0; }
# Assemble them all into the regular expression of death.
@containers = ();
foreach my $c (keys %C) { push @containers, $c if $C{$c}; }
my $regexp = join '|', @containers;
$regexp = "\\b($regexp)\\b";
$regexp =~ s/\-/\\\-/g;
# Destroy child elements matching the regular expression.
foreach my $e ($element->getElementsByTagName('*'))
{
next if $e == $element;
if ($e->getAttribute('class') =~ /$regexp/)
{
$self->_destroy_element($e);
my $newclass = $e->getAttribute('class');
$newclass =~ s/$regexp//g;
$e->setAttribute('class', $newclass);
$e->removeAttribute('class') unless length $newclass;
}
}
}
sub _destroy_element
{
my $self = shift;
my $element = shift;
foreach my $c ($element->getElementsByTagName('*'))
{
$c->removeAttribute('class');
$c->removeAttribute('rel');
$c->removeAttribute('rev');
}
}
sub _expand_patterns
{
my $self = shift;
my $root = shift || $self->element;
my $max_include_loops = shift || 2;
# Expand microformat include pattern.
my $incl_iterations = 0;
my $replacements = 1;
while (($incl_iterations < $max_include_loops) && $replacements)
{
$replacements = $self->_expand_include_pattern($root) + $self->_expand_include_pattern_2($root);
$incl_iterations++;
}
# Table cell headers pattern.
$self->_expand_table_header_pattern($root);
# Magical data-X class pattern.
$self->_expand_dataX_class_pattern($root);
}
sub _expand_dataX_class_pattern
{
my $self = shift;
my $node = shift;
return
unless $self->context->has_profile('http://purl.org/uF/pattern-data-class/1');
foreach my $kid ($node->getElementsByTagName('*'))
{
my $classes = $kid->getAttribute('class');
$classes =~ s/(^\s+|\s+$)//g;
$classes =~ s/\s+/ /g;
my @classes = split / /, $classes;
map s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg, @classes;
my @dataClasses = grep /^data\-/, @classes;
next unless (@dataClasses);
my $val = '';
foreach my $d (@dataClasses)
{
$val = $d unless ((length $val) > (length $d));
}
$val =~ s/^data\-//;
$kid->setAttribute('data-cpan-html-microformats-content', $val);
}
}
sub _expand_table_header_pattern
{
my $self = shift;
my $node = shift;
# Add node itself to list!
my @elements = $node->getElementsByTagName('td');
if (('XML::LibXML::Element' eq ref $node) && $node->tagName =~ /^t[dh]$/i)
{ unshift @elements, $node; }
foreach my $tag (@elements)
{
next unless length $tag->getAttribute('headers');
my $headers = $tag->getAttribute('headers');
$headers =~ s/(^\s+|\s+$)//g;
$headers =~ s/\s+/ /g;
my @headers = split / /, $headers;
foreach my $H (@headers)
{
my $Htag = searchID($H, $self->context->document);
next unless ($Htag);
next unless ($Htag->tagName =~ /^t[dh]$/i);
my $new = $self->context->document->createElement('div');
$new->setAttribute('class', $Htag->getAttribute('class'));
foreach my $kid ($Htag->childNodes)
{
my $x = $kid->cloneNode(1);
if ($kid->nodeType==XML_ELEMENT_NODE || $kid->nodeType==XML_TEXT_NODE)
{
my $r = $new->appendChild($x);
}
}
$tag->appendChild($new);
}
$tag->setAttribute('headers', '');
}
}
sub _expand_include_pattern
# Implements the standard microformats include pattern.
{
my $self = shift;
my $node = shift;
my $class = shift || 'include';
my $rv = 0;
# For each link...
my @links1 = $node->getElementsByTagName('a');
my @links2 = $node->getElementsByTagName('object');
my @links3 = $node->getElementsByTagName('area');
my @links = (@links1, @links2, @links3);
foreach my $link (@links)
{
# Skip pattern if no class attribute found.
my $classList = $link->getAttribute('class') || next;
# We've found a use of the include pattern
if ($classList =~ / (^|\s) $class (\s|$) /x)
{
my $href = $link->hasAttribute('href') ?
$link->getAttribute('href') :
$link->getAttribute('data') ;
my $id = undef;
if ($href =~ /^\#(.*)$/)
{
$id = $1;
}
else
{
next;
}
# find the included node
my $replacement = searchID($id, $self->context->document);
next unless $replacement;
# do not include it if it's an ancestor
my $link_xpath = $link->getAttribute('data-cpan-html-microformats');
my $repl_xpath = $replacement->getAttribute('data-cpan-html-microformats');
next if (substr($link_xpath, 0, length $repl_xpath) eq $repl_xpath);
# replace the including element with the included element
$replacement = $replacement->cloneNode(1);
$link->getParentNode->replaceChild($replacement, $link) && $rv++;
}
}
# Return number of replacements made.
return $rv;
}
sub _expand_include_pattern_2
# Implements the alternative microformats include pattern.
{
my $self = shift;
my $node = shift;
my $classpfx = shift || '#';
my $rv = 0;
# Add node itself to list!
my @elements = $node->getElementsByTagName('*');
unshift @elements, $node;
# For each element...
foreach my $elem (@elements)
{
# Skip pattern if no class attribute found.
my $classList;
$classList = $elem->getAttribute('class')
if 'XML::LibXML::Element' eq ref $elem;
next unless ($classList =~ / $classpfx /x);
my $atEnd = 0;
$classList =~ s/(^\s|\s$)//g;
$classList =~ s/\s+/ /g;
my @classes = split / /, $classList;
my @newClassList = ();
foreach my $c (@classes)
{
if (substr($c,0,1) ne $classpfx && length($c)>=1)
{
push @newClassList, $c;
$atEnd = 1;
next;
}
my $id = $c; $id =~ s/^\#//x;
my $replacement = searchID($id, $self->context->document) || next;
# do not include it if it's an ancestor
my $link_xpath = $elem->getAttribute('data-cpan-html-microformats');
my $repl_xpath = $replacement->getAttribute('data-cpan-html-microformats');
next if (substr($link_xpath, 0, length $repl_xpath) eq $repl_xpath);
$replacement = $replacement->cloneNode(1);
if ($atEnd)
{
$elem->appendChild($replacement) && $rv++;
}
else
{
$elem->insertBefore($replacement, $elem->getFirstChild) && $rv++;
}
}
$elem->setAttribute('class', join(' ', @newClassList))
if 'XML::LibXML::Element' eq ref $elem;
}
# Return number of replacements made.
return $rv;
}
sub _matching_nodes
{
my $self = shift;
my $class = shift;
my $type = shift;
my $root = shift || $self->element;
my @matching_nodes;
if ($type =~ /r/i)
{ @matching_nodes = searchRel($class, $root); }
elsif ($type =~ /t/i)
{ @matching_nodes = $root->getElementsByTagName($class); }
if ($type !~ /[rt]/)
{
my @mn2 = searchClass($class, $root);
push @matching_nodes, @mn2;
}
return @matching_nodes;
}
sub _simple_parse_found_error
{
my $self = shift;
push @{ $self->{ERRORS} }, \@_;
}
# 1 = singular, required
# ? = singular, optional
# + = plural, required
# * = plural, optional
# ** = plural, optional, and funny behaviour with embedded microformats
# d = date
# D = duration
# e = exrule/rrule
# i = interval
# h = HTML
# H = HTML and Text (HTML value is prefixed 'html_')
# m = embedded composite microformat
# M = embedded composite microformat or text
# MM = embedded composite microformat or text, if url use pseudo-microformat
# n = numeric
# r = rel, not class
# R = rel *or* class
# t = tag name, not class
# T = tag name *or* class
# u = URI
# U = URI or fragment or text
# & = concatenate strings
# < = Also store node (in $self->{'DATA_'})
# # = _simple_parse should ignore this property
# v = don't do 'value' excerption
sub _simple_parse
# This was not simple to implement, but should be simple to use.
# This function takes on too much responsibility.
# It should delegate stuff.
{
my $self = shift;
my $root = shift || $self->element;
my $classes = $self->format_signature->{'classes'};
my $options = $self->format_signature->{'options'} || {};
my $page = $self->context;
# So far haven't needed any more than this.
my $uf_roots = {
'hCard' => 'vcard',
'hEvent' => 'vevent',
'hAlarm' => 'valarm',
'hTodo' => 'vtodo',
'hFreebusy' => 'vfreebusy',
'hCalendar' => 'vcalendar',
'hMeasure' => 'hmeasure|hangle|hmoney',
'species' => 'biota',
'hAtom' => 'hfeed'
};
# Derived from HTML::Tagset, but some modifications to the order of attrs.
my $link_elements = {
'a' => ['href'],
'applet' => ['codebase', 'archive', 'code'],
'area' => ['href'],
'base' => ['href'],
'bgsound' => ['src'],
'blockquote' => ['cite'],
# 'body' => ['background'],
'del' => ['cite'],
'embed' => ['src', 'pluginspage'],
'form' => ['action'],
'frame' => ['src', 'longdesc'],
'iframe' => ['src', 'longdesc'],
# 'ilayer' => ['background'],
'img' => ['src', 'lowsrc', 'longdesc', 'usemap'],
'input' => ['src', 'usemap'],
'ins' => ['cite'],
'isindex' => ['action'],
'head' => ['profile'],
'layer' => ['src'], # 'background'
'link' => ['href'],
'object' => ['data', 'classid', 'codebase', 'archive', 'usemap'],
'q' => ['cite'],
'script' => ['src', 'for'],
# 'table' => ['background'],
# 'td' => ['background'],
# 'th' => ['background'],
# 'tr' => ['background'],
'xmp' => ['href'],
};
foreach my $c (@$classes)
{
my $class = $c->[0];
my $type = $c->[1];
my $class_options = $c->[2] || {};
my @try_ufs = split / /, $class_options->{'embedded'};
next if $type =~ /#/;
next unless $type =~ /m/i && defined $try_ufs[0];
my @parsed_objects;
my @matching_nodes = $self->_matching_nodes($class, $type, $root);
my @ok_matching_nodes;
if ($class_options->{'nesting-ok'})
{
@ok_matching_nodes = @matching_nodes;
}
else
{
# This is a little bit of extra code that checks for interleaving uF
# root class elements and excludes them. For example, in the following,
# the outer hCard should not have an agent:
#
my @mfos = qw(mfo vcard adr geo vcalendar vevent vtodo valarm
vfreebusy hfeed hentry hslice hreview hresume xfolkentry biota haudio
hmeasure hangle hmoney hlisting vtodo-list figure hproduct hnews);
my $mfos = '\b('.(join '|', @mfos).')\b';
foreach my $u (@{$class_options->{'allow-interleaved'}})
{ $mfos =~ s/\|$u//; }
foreach my $mn (@matching_nodes)
{
my $is_ok = 1;
my $ancestor = $mn->parentNode;
while (length $ancestor->getAttribute('data-cpan-html-microformats-nodepath') > length $root->getAttribute('data-cpan-html-microformats-nodepath'))
{
if ($ancestor->getAttribute('class')=~$mfos)
{
$is_ok = 0;
last;
}
$ancestor = $ancestor->parentNode;
}
push @ok_matching_nodes, $mn if ($is_ok);
}
}
# For each matching node
foreach my $node (@ok_matching_nodes)
{
my @node_parsed_objects;
# Try each microformat until we find something
no strict 'refs';
foreach my $uf (@try_ufs)
{
my $uf_class = (defined $uf_roots->{$uf}) ? $uf_roots->{$uf} : lc($uf);
last if defined $node_parsed_objects[0];
if ($uf eq '!person')
{
# This is used as a last-ditch attempt to parse a person.
my $obj = HTML::Microformats::Format::hCard->new_fallback($node, $self->context);
push @node_parsed_objects, $obj;
}
elsif ($node->getAttribute('class') =~ /\b($uf_class)\b/)
{
my $pkg = 'HTML::Microformats::Format::'.$uf;
my $obj = eval "${pkg}->new(\$node, \$self->context, in_hcalendar => \$class_options->{'is-in-cal'});";
push @node_parsed_objects, $obj;
}
else
{
my $pkg = 'HTML::Microformats::Format::'.$uf;
my @all = eval "${pkg}->extract_all(\$node, \$self->context, in_hcalendar => \$class_options->{'is-in-cal'});";
push @node_parsed_objects, @all if @all;
}
$self->_simple_parse_found_error('W', "Multiple embedded $uf objects found in a single $class property. This is weird.")
if defined $node_parsed_objects[1];
}
use strict 'refs';
# If we've found something
if (defined $node_parsed_objects[0] && ref $node_parsed_objects[0])
{
unless ($class_options->{'again-again'})
{
# Remove $class from $node's class list, lest we pick it up again
# in the next giant loop!
my $new_class_attr = $node->getAttribute('class');
$new_class_attr =~ s/\b($class)\b//;
$node->setAttribute('class', $new_class_attr);
$node->removeAttribute('class') unless $new_class_attr;
}
# If $type contains '**' then allow
#
foreach my $p (@node_parsed_objects)
{
next unless ref $p;
# Record parent property node in case we need it (hResume does)!
$p->{'parent_property_node'} = $node;
push @parsed_objects, $p;
last unless $type =~ /\*\*/;
}
}
}
# What key should we use to store everything in $self?
my $object_key = $class;
$object_key = $class_options->{'use-key'}
if defined $class_options->{'use-key'};
# Actually do the storing!
if ($type =~ /[1\?]/ && !defined $self->{'DATA'}->{$object_key})
{
$self->{'DATA'}->{$object_key} = $parsed_objects[0]
if @parsed_objects;
$self->{'DATA_'}->{$object_key} = $parsed_objects[0]->{'parent_property_node'}
if @parsed_objects && $type =~ /\;
$self->_simple_parse_found_error('W', "$class is singular, but multiple instances found. Only the first one will be used.")
if defined $parsed_objects[1];
}
else
{
foreach my $value (@parsed_objects)
{
push @{ $self->{'DATA'}->{$object_key} }, $value;
push @{ $self->{'DATA_'}->{$object_key} }, $parsed_objects[0]->{'parent_property_node'}
if $type =~ /\;
}
}
}
# Destroy nested microformats.
$self->_destroyer($root, 'hmeasure', 'hangle', 'hmoney', @{ $options->{'no-destroy'} });
# hmeasure, and destroy each, unless saved by $options->{'no-destroy'}!
my $do_destroy = {
'hmeasure' => 1,
'hangle' => 1,
'hmoney' => 1
};
foreach my $root (@{ $options->{'no-destroy'} })
{ $do_destroy->{$root} = 0; }
# embedded hmeasure
if (defined $options->{'hmeasure'})
{
my @measures = HTML::Microformats::Format::hMeasure->extract_all($root, $self->context);
foreach my $m (@measures)
{
push @{ $self->{$options->{'hmeasure'}} }, $m
unless defined $m->data->{'item'}
|| defined $m->data->{'item_link'}
|| defined $m->data->{'item_label'};
$self->destroy_element($m->{'element'})
if $do_destroy->{ $m->data->{'class'} } && defined $m->{'element'};
}
}
# embedded rel-tag
if (defined $options->{'rel-tag'})
{
my $key = $options->{'rel-tag'};
my @tags = HTML::Microformats::Format::RelTag->extract_all($root, $self->context);
push @{ $self->{'DATA'}->{$key} }, @tags if @tags;
}
# embedded rel-license
if (defined $options->{'rel-license'})
{
my $key = $options->{'rel-license'};
my @licences = HTML::Microformats::Format::RelLicense->extract_all($root, $self->context);
push @{ $self->{'DATA'}->{$key} }, @licences if @licences;
}
# embedded rel-enclosure
if (defined $options->{'rel-enclosure'})
{
my $key = $options->{'rel-enclosure'};
my @encs = HTML::Microformats::Format::RelEnclosure->extract_all($root, $self->context);
push @{ $self->{'DATA'}->{$key} }, @encs if @encs;
}
# For each of the classes that we're looking for...
foreach my $c (@$classes)
{
my $class = $c->[0];
my $type = $c->[1];
my $class_options = $c->[2] || {};
# We've already processed embedded microformats.
next if $type =~ /m/;
# These properties are too complex for _simple_parse.
next if $type =~ /#/;
my @matching_nodes = $self->_matching_nodes($class, $type, $root);
# Parse each node that matched.
my @parsed_values;
my @parsed_values_nodes;
my @parsed_values_alternatives;
foreach my $node (@matching_nodes)
{
# Jump out of the loop if we were only expecting a single value and
# have already found it!
if ($type =~ /[1\?]/ && defined $parsed_values[0])
{
$self->_simple_parse_found_error('W', "$class is singular, but multiple instances found. Only the first one will be used.");
last;
}
# Avoid conflicts between rel=tag and class=category.
next
if (($class eq $options->{'rel-tag'})
&& ($node->getAttribute('rel') =~ /\b(tag)\b/i));
# Ditto rel=license and class=license.
next
if (($class eq $options->{'rel-license'})
&& ($node->getAttribute('rel') =~ /\b(license)\b/i));
# Ditto rel=enclosure and class=attach.
next
if (($class eq $options->{'rel-enclosure'})
&& ($node->getAttribute('rel') =~ /\b(enclosure)\b/i));
# Parse URL types
my ($u, $u_element);
if ($type =~ /(u|U|MM)/)
{
my @value_elements;
@value_elements = searchClass('value', $node)
unless $type=~/v/;
unshift @value_elements, $node;
ELEMENT: foreach my $v (@value_elements)
{
if (defined $link_elements->{lc $v->tagName})
{
ATTR: foreach my $attr (@{ $link_elements->{lc $v->tagName} })
{
if (length $v->getAttribute($attr))
{
$u = $v->getAttribute($attr);
$u_element = $v;
last ELEMENT;
}
}
}
if ($type =~ /U/ && length $v->getAttribute('id'))
{
$u = '#'.$v->getAttribute('id');
$u_element = $v;
last ELEMENT;
}
}
if (defined $u)
{
if ($type =~ /MM/)
{
##TODO: post-0.001
die "Not implemented!";
# my $px = { uri => $page->uri($u) };
# bless $px, "Swignition::uF::Pseudo";
# push @parsed_values, $px;
}
else
{
push @parsed_values, $page->uri($u);
}
push @parsed_values_nodes, $node;
if (length $options->{'rel-me'} && $u_element->getAttribute('rel') =~ /\b(me)\b/i)
{ $self->{'DATA'}->{$options->{'rel-me'}}++; }
next;
}
else
{
push @parsed_values, $self->_stringify($node,
{
'excerpt-class' => ($type=~/v/?undef:'value'),
'value-title' => defined $class_options->{'value-title'} ? $class_options->{'value-title'} : (($type=~/[Ddei]/ && $type!~/v/) ? 'allow' : undef),
'abbr-pattern' => 1,
});
push @parsed_values_nodes, $node;
next;
}
}
# Extract text (and if needed, XML) string from node.
if ($type =~ /H/)
{
push @parsed_values, $self->_stringify($node, ($type=~/v/?undef:'value'));
push @parsed_values_alternatives, $self->_xml_stringify($node, undef, $class_options->{'include-self'});
push @parsed_values_nodes, $node;
}
elsif ($type =~ /h/)
{
push @parsed_values, $self->_xml_stringify($node, undef, $class_options->{'include-self'});
push @parsed_values_nodes, $node;
}
elsif ($type =~ /d/)
{
push @parsed_values, $self->_stringify($node, {
'value-title' => defined $class_options->{'value-title'} ? $class_options->{'value-title'} : (($type=~/[Ddei]/ && $type!~/v/) ? 'allow' : undef),
'excerpt-class' => ($type=~/v/?undef:'value'),
'abbr-pattern' => 1,
'datetime' => 1,
'joiner' => ' ',
'datetime-feedthrough' => defined $class_options->{'datetime-feedthrough'} ? $self->{'DATA'}->{ $class_options->{'datetime-feedthrough'} } : undef,
});
push @parsed_values_nodes, $node;
}
elsif ($type =~ /u/)
{
push @parsed_values, $page->uri($self->_stringify($node, ($type=~/v/?undef:'value')));
push @parsed_values_nodes, $node;
}
else
{
push @parsed_values, $self->_stringify($node, {
'excerpt-class' => ($type=~/v/?undef:'value'),
'value-title' => defined $class_options->{'value-title'} ? $class_options->{'value-title'} : (($type=~/[Ddei]/ && $type!~/v/) ? 'allow' : undef),
'abbr-pattern' => 1,
});
push @parsed_values_nodes, $node;
}
}
# Now we have parsed values in @parsed_values. Sometimes these need to be
# concatenated.
if ($type =~ /\&/)
{
my $joiner = ($type =~ /u/i) ? ' ' : '';
$joiner = $class_options->{'concatenate-with'}
if defined $class_options->{'concatenate-with'};
if (@parsed_values)
{
my $value = join $joiner, @parsed_values;
@parsed_values = ($value);
}
if (@parsed_values_alternatives)
{
my $value = join $joiner, @parsed_values_alternatives;
@parsed_values_alternatives = ($value);
}
}
# Check which values are acceptable.
my @acceptable_values;
my @acceptable_values_nodes;
for (my $i=0; defined $parsed_values[$i]; $i++)
{
my $value = $parsed_values[$i];
# Check date values are OK
if ($type =~ /d/)
{
$value = HTML::Microformats::Datatype::DateTime->parse($value);
if ($value)
{
if ($parsed_values_nodes[$i]->getAttribute('class') =~ /\b(approx)\b/)
{
$value->{datatype} = 'http://dbpedia.org/resource/Approximation';
}
else
{
my @approx = searchClass('approx', $parsed_values_nodes[$i]);
$value->{datatype} = 'http://dbpedia.org/resource/Approximation'
if @approx;
}
push @acceptable_values, $value;
push @acceptable_values_nodes, $parsed_values_nodes[$i];
next;
}
}
# Check durations are OK
elsif ($type =~ /D/)
{
my $D = undef;
if (HTML::Microformats::Datatype::String::isms($value))
{
$D = HTML::Microformats::Datatype::Duration->parse($value->{string}, $value->{dom}, $page)
}
else
{
$D = HTML::Microformats::Datatype::Duration->parse($value, undef, $page)
}
if (defined $D)
{
push @acceptable_values, $D;
push @acceptable_values_nodes, $parsed_values_nodes[$i];
}
else
{
$self->_simple_parse_found_error('E', "$class could not be parsed as a duration.");
}
next;
}
# Check intervals are OK
elsif ($type =~ /i/)
{
my $D;
if (HTML::Microformats::Datatype::String::isms($value))
{
$D = HTML::Microformats::Datatype::Interval->parse($value->{string}, $value->{dom}, $page)
}
else
{
$D = HTML::Microformats::Datatype::Interval->parse($value, undef, $page)
}
if ($D)
{
push @acceptable_values, $D;
push @acceptable_values_nodes, $parsed_values_nodes[$i];
}
else
{
$self->_simple_parse_found_error('E', "$class could not be parsed as an interval.");
}
next;
}
# Check intervals are OK
elsif ($type =~ /e/)
{
my $D;
if (HTML::Microformats::Datatype::String::isms($value))
{
$D = HTML::Microformats::Datatype::RecurringDateTime->parse($value->{string}, $value->{dom}, $page)
}
else
{
$D = HTML::Microformats::Datatype::RecurringDateTime->parse($value, undef, $page)
}
if ($D)
{
push @acceptable_values, $D;
push @acceptable_values_nodes, $parsed_values_nodes[$i];
}
else
{
$self->_simple_parse_found_error('E', "$class could not be parsed as an interval.");
}
next;
}
# Everything else we won't bother to check if it's OK.
else
{
push @acceptable_values, $value;
push @acceptable_values_nodes, $parsed_values_nodes[$i];
next;
}
}
# What key should we use to store everything in $self?
my $object_key = $class;
$object_key = $class_options->{'use-key'}
if (defined $class_options->{'use-key'});
# Actually do the storing!
if ($type =~ /[1\?\&]/ && !defined $self->{$object_key})
{
$self->{'DATA'}->{$object_key} = $acceptable_values[0]
if @acceptable_values;
$self->{'DATA_'}->{$object_key} = $acceptable_values_nodes[0]
if @acceptable_values && $type =~ /\;
}
else
{
for (my $i=0; defined $acceptable_values[$i]; $i++)
{
push @{ $self->{'DATA'}->{$object_key} }, $acceptable_values[$i];
push @{ $self->{'DATA_'}->{$object_key} }, $acceptable_values_nodes[$i]
if ($type =~ /\);
}
}
if ($type =~ /[1\+]/ && !defined $self->{$object_key})
{
$self->_simple_parse_found_error('E', "$class is required, but no acceptable value was found.");
}
# Store HTML values too!
if ($type =~ /H/)
{
if ($type =~ /[1\?\&]/ && defined $parsed_values_alternatives[0])
{
$self->{'DATA'}->{'html_'.$object_key} = $parsed_values_alternatives[0];
}
else
{
foreach my $value (@parsed_values_alternatives)
{
push @{ $self->{'DATA'}->{'html_'.$object_key} }, $value;
}
}
}
# for classes called 'uid', special handling.
if ($class eq 'uid' and !defined $self->{'DATA'}->{$object_key})
{
if ($root->hasAttribute('id') and length $root->getAttribute('id'))
{
$self->{'DATA'}->{$object_key} = $self->context->uri('#'.$root->getAttribute('id'));
}
}
}
}
sub _stringify
{
my $self = shift;
return HTML::Microformats::Utilities::stringify(@_);
}
sub _xml_stringify
{
my $self = shift;
return HTML::Microformats::Utilities::xml_stringify(@_);
}
1;
__END__
=head1 NAME
HTML::Microformats::Mixin::Parser - microformat parsing mixin
=head1 DESCRIPTION
HTML::Microformats::Mixin::Parser implements a number of private methods that
take care of the bulk of parsing complex, compound microformats.
Many of the individual microformat modules multi-inherit from this.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2010 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Mixin/RDF.pm 0000644 0000764 0000764 00000010402 11775403507 021074 0 ustar tai tai package HTML::Microformats::Mixin::RDF;
use strict qw(subs vars); no warnings;
use 5.010;
use Encode qw(encode);
use RDF::Trine;
use Scalar::Util qw();
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Mixin::RDF::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Mixin::RDF::VERSION = '0.105';
}
sub _simple_rdf
{
my $self = shift;
my $model = shift;
my $id = $self->id(1);
return if $self->{'already_added'}->{"$model"};
$self->{'already_added'}->{"$model"}++;
foreach my $rdftype (@{ $self->format_signature->{'rdf:type'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$id,
RDF::Trine::Node::Resource->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
RDF::Trine::Node::Resource->new($rdftype),
));
}
KEY: foreach my $key (sort keys %{ $self->format_signature->{'rdf:property'} })
{
my $rdf = $self->format_signature->{'rdf:property'}->{$key};
next KEY unless defined $self->data->{$key};
my $vals = $self->data->{$key};
$vals = [$vals] unless ref $vals eq 'ARRAY';
foreach my $val (@$vals)
{
my $can_id = Scalar::Util::blessed($val) && $val->can('id');
my $seems_bnode = ($val =~ /^_:\S+$/);
my $seems_uri = ($val =~ /^[a-z0-9\.\+\-]{1,20}:\S+$/);
if ((defined $rdf->{'resource'}||defined $rdf->{'rev'})
&& ($can_id || $seems_uri || $seems_bnode))
{
my $val_node = undef;
if ($can_id)
{
$val_node = $val->id(1);
}
else
{
$val_node = ($val =~ /^_:(.*)$/) ?
RDF::Trine::Node::Blank->new($1) :
RDF::Trine::Node::Resource->new($val);
}
foreach my $prop (@{ $rdf->{'resource'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$id,
RDF::Trine::Node::Resource->new($prop),
$val_node
));
}
foreach my $prop (@{ $rdf->{'rev'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$val_node,
RDF::Trine::Node::Resource->new($prop),
$id
));
}
if ($can_id and Scalar::Util::blessed($val) and $val->can('add_to_model'))
{
$val->add_to_model($model);
}
}
elsif (defined $rdf->{'literal'} and !$can_id)
{
foreach my $prop (@{ $rdf->{'literal'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$id,
RDF::Trine::Node::Resource->new($prop),
$self->_make_literal($val, $rdf->{'literal_datatype'}),
));
}
}
}
}
}
sub _make_literal
{
my ($self, $val, $dt) = @_;
if (Scalar::Util::blessed($val)
and $val->can('to_string')
and $val->can('datatype'))
{
return RDF::Trine::Node::Literal->new(
encode('utf8', $val->to_string), undef, $val->datatype);
}
elsif (Scalar::Util::blessed($val)
and $val->can('to_string')
and $val->can('lang'))
{
return RDF::Trine::Node::Literal->new(
encode('utf8', $val->to_string), $val->lang);
}
else
{
if (defined $dt and length $dt and $dt !~ /:/)
{
$dt = 'http://www.w3.org/2001/XMLSchema#'.$dt;
}
if ($dt eq 'http://www.w3.org/2001/XMLSchema#integer')
{
$val = int $val;
}
return RDF::Trine::Node::Literal->new(encode('utf8', $val), undef, $dt);
}
}
1;
__END__
=head1 NAME
HTML::Microformats::Mixin::RDF - RDF output mixin
=head1 DESCRIPTION
HTML::Microformats::Mixin::RDF provides some utility code for microformat
modules to more easily output RDF. It includes methods C<_simple_rdf> which
takes an RDF::Trine model as a parameter and adds some basic triples to it
based on the object's format signature; and C<_make_literal> taking either
a string plus datatype as parameters, or any of the HTML::Microformats::Datatype
objects, returning an RDF::Trine::Node::Literal.
HTML::Microformats::Format inherits from this module, so by extension, all the
microformat modules do too.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2010 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Datatype.pm 0000644 0000764 0000764 00000003531 11775403507 021155 0 ustar tai tai package HTML::Microformats::Datatype;
use HTML::Microformats::Datatype::DateTime;
use HTML::Microformats::Datatype::Duration;
use HTML::Microformats::Datatype::Interval;
use HTML::Microformats::Datatype::RecurringDateTime;
use HTML::Microformats::Datatype::String;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Datatype::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Datatype::VERSION = '0.105';
}
1;
__END__
=head1 NAME
HTML::Microformats::Datatype - representations of literal values
=head1 DESCRIPTION
Many places you'd expect a Perl scalar to appear, e.g.:
$my_hcard->get_fn;
What you actually get returned is an object from one of the Datatype
modules. Why? Because using a scalar loses information. For example,
most strings have associated language information (from HTML lang and
xml:lang attributes). Using an object allows this information to be kept.
The Datatype modules overload stringification, which means that for
the most part, you can use them as strings (subjecting them to
regular expressions, concatenating them, printing them, etc) and
everything will work just fine. But they're not strings.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L.
L,
L,
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/ 0000755 0000764 0000764 00000000000 11775404022 020263 5 ustar tai tai HTML-Microformats-0.105/lib/HTML/Microformats/Format/hReviewAggregate.pm 0000644 0000764 0000764 00000011012 11775403507 024043 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hReviewAggregate - the hReview-aggregate microformat
=head1 SYNOPSIS
use HTML::Microformats::DocumentContext;
use HTML::Microformats::Format::hReviewAggregate;
my $context = HTML::Microformats::DocumentContext->new($dom, $uri);
my @reviews = HTML::Microformats::Format::hReviewAggregate->extract_all(
$dom->documentElement, $context);
foreach my $review (@reviews)
{
print Dumper($review->data) . "\n";
}
=head1 DESCRIPTION
HTML::Microformats::Format::hReviewAggregate inherits from HTML::Microformats::Format. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=cut
package HTML::Microformats::Format::hReviewAggregate;
use base qw(HTML::Microformats::Format::hReview);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(stringify searchClass);
use HTML::Microformats::Format::hReview::rating;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hReviewAggregate::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hReviewAggregate::VERSION = '0.105';
}
sub new
{
my ($class, $element, $context, %options) = @_;
my $cache = $context->cache;
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
'id.holder' => $context->make_bnode ,
};
bless $self, $class;
my $clone = $element->cloneNode(1);
$self->_expand_patterns($clone);
$self->_simple_parse($clone);
$self->_fallback_item($clone)->_auto_detect_type;
$self->{'DATA'}->{'rating'} =
[ HTML::Microformats::Format::hReview::rating->extract_all($clone, $context) ];
$cache->set($context, $element, $class, $self)
if defined $cache;
return $self;
}
sub format_signature
{
my $self = shift;
my $rev = 'http://www.purl.org/stuff/rev#';
my $hreview = 'http://ontologi.es/hreview#';
my $rv = {
'root' => 'hreview-aggregate',
'classes' => [
['item', 'm1', {'embedded'=>'hProduct hAudio hEvent hCard'}], # lowercase 'm' = don't try plain string.
['summary', '1'],
['type', '?'],
['bookmark', 'ru?', {'use-key'=>'permalink'}],
['description', 'H*'],
['rating', '*#'],
['count', 'n?'],
['votes', 'n?'],
],
'options' => {
'rel-tag' => 'tag',
'rel-license' => 'license',
},
'rdf:type' => ["${hreview}Aggregate"] ,
'rdf:property' => {
'description' => { 'literal' => ["${rev}text"] },
'type' => { 'literal' => ["${rev}type"] },
'summary' => { 'literal' => ["${rev}title", "http://www.w3.org/2000/01/rdf-schema#label"] },
'rating' => { 'resource' => ["${hreview}rating"] },
'tag' => { 'resource' => ['http://www.holygoat.co.uk/owl/redwood/0.1/tags/taggedWithTag'] },
'license' => { 'resource' => ["http://www.iana.org/assignments/relation/license", "http://creativecommons.org/ns#license"] },
'permalink' => { 'resource' => ["http://www.iana.org/assignments/relation/self"] },
'count' => { 'literal' => ["${hreview}count"] },
'votes' => { 'literal' => ["${hreview}votes"] },
},
};
return $rv;
}
sub profiles
{
my $class = shift;
return qw(http://microformats.org/wiki/hreview-aggregate);
}
1;
=head1 MICROFORMAT
HTML::Microformats::Format::hReviewAggregate supports hReview-aggregate 0.2 as described at
L with the following differences:
=over 4
=item * hAudio
hAudio microformats can be used as the reviewed item.
=item * hReview properties
A few properties are supported from (non-aggregate) hReview - e.g.
'bookmark', 'tag', 'description' and 'type'.
=back
=head1 RDF OUTPUT
L, L.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hNews.pm 0000644 0000764 0000764 00000012152 11775403507 021715 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hNews - the hNews microformat
=head1 SYNOPSIS
use HTML::Microformats::DocumentContext;
use HTML::Microformats::Format::hNews;
my $context = HTML::Microformats::DocumentContext->new($dom, $uri);
my @objects = HTML::Microformats::Format::hNews->extract_all(
$dom->documentElement, $context);
foreach my $article (@objects)
{
printf("%s %s\n", $article->get_link, $article->get_dateline);
}
=head1 DESCRIPTION
HTML::Microformats::Format::hNews inherits from HTML::Microformats::Format. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=cut
package HTML::Microformats::Format::hNews;
use base qw(HTML::Microformats::Format::hEntry);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(searchClass);
use HTML::Microformats::Format::hCard;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hNews::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hNews::VERSION = '0.105';
}
sub new
{
my ($class, $element, $context) = @_;
my $cache = $context->cache;
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
};
bless $self, $class;
my $clone = $self->_hentry_parse;
# hNews has a source-org which is probably an hCard.
$self->_source_org_fallback($clone);
$self->{'DATA'}->{'class'} = 'hnews';
$cache->set($context, $element, $class, $self)
if defined $cache;
return $self;
}
sub _source_org_fallback
{
my ($self, $clone) = @_;
unless (@{ $self->{'DATA'}->{'source-org'} })
{
##TODO: Should really only use the nearest-in-parent. post-0.001
my @so_elements = searchClass('source-org', $self->context->document->documentElement);
foreach my $so (@so_elements)
{
next unless $so->getAttribute('class') =~ /\b(vcard)\b/;
push @{ $self->{'DATA'}->{'source-org'} }, HTML::Microformats::Format::hCard->new($so, $self->context);
}
}
}
sub format_signature
{
my $rv = HTML::Microformats::Format::hEntry->format_signature;
$rv->{'root'} = 'hnews';
push @{ $rv->{'classes'} }, (
['source-org', 'm?', {embedded=>'hCard'}],
['dateline', 'M?', {embedded=>'hCard adr'}],
['geo', 'm*', {embedded=>'geo'}],
['item-license', 'ur*'],
['principles', 'ur*'],
);
my $hnews = 'http://ontologi.es/hnews#';
my $iana = 'http://www.iana.org/assignments/relation/';
# $rv->{'rdf:property'}->{'source-org'}->{'resource'} = ["${hnews}source-org"];
# $rv->{'rdf:property'}->{'dateline'}->{'resource'} = ["${hnews}dateline"];
$rv->{'rdf:property'}->{'dateline'}->{'literal'} = ["${hnews}dateline-literal"];
# $rv->{'rdf:property'}->{'geo'}->{'resource'} = ["${hnews}geo"];
$rv->{'rdf:property'}->{'item-license'}->{'resource'} = ["${iana}license", "http://creativecommons.org/ns#license"];
$rv->{'rdf:property'}->{'principles'}->{'resource'} = ["${hnews}principles"];
return $rv;
}
sub add_to_model
{
my $self = shift;
my $model = shift;
my $hnews = 'http://ontologi.es/hnews#';
$self->SUPER::add_to_model($model);
if ($self->_isa($self->data->{'source-org'}, 'HTML::Microformats::Format::hCard'))
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${hnews}source-org"),
$self->data->{'source-org'}->id(1, 'holder'),
));
}
if ($self->_isa($self->data->{'dateline'}, 'HTML::Microformats::Format::hCard'))
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${hnews}dateline"),
$self->data->{'source-org'}->id(1, 'holder'),
));
}
foreach my $geo (@{ $self->data->{'geo'} })
{
if ($self->_isa($geo, 'HTML::Microformats::Format::geo'))
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${hnews}geo"),
$geo->id(1, 'location'),
));
}
}
return $self;
}
sub profiles
{
my $class = shift;
return qw(http://purl.org/uF/hNews/0.1/);
}
1;
=head1 MICROFORMAT
HTML::Microformats::Format::hNews supports hNews as described at
L.
=head1 RDF OUTPUT
hNews is an extension of hAtom; data is returned using the same vocabularies as hAtom,
with additional news-specific terms from L.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L,
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/RelLicense.pm 0000644 0000764 0000764 00000006155 11775403507 022664 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::RelLicense - the rel-license microformat
=head1 SYNOPSIS
my @licences = HTML::Microformats::Format::RelLicense->extract_all(
$doc->documentElement, $context);
foreach my $licence (@licences)
{
print $licence->get_href . "\n";
}
=head1 DESCRIPTION
HTML::Microformats::Format::RelLicense inherits from HTML::Microformats::Format_Rel. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=cut
package HTML::Microformats::Format::RelLicense;
use base qw(HTML::Microformats::Format_Rel);
use strict qw(subs vars); no warnings;
use 5.010;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::RelLicense::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::RelLicense::VERSION = '0.105';
}
sub format_signature
{
return {
'rel' => 'license' ,
'classes' => [
['href', '1#'] ,
['label', '1#'] ,
['title', '1#'] ,
] ,
'rdf:type' => [] ,
'rdf:property' => {} ,
}
}
sub profiles
{
return qw(http://microformats.org/profile/rel-license
http://ufs.cc/x/rel-license
http://microformats.org/profile/specs
http://ufs.cc/x/specs
http://purl.org/uF/rel-license/1.0/
http://purl.org/uF/2008/03/);
}
sub add_to_model
{
my $self = shift;
my $model = shift;
$model->add_statement(RDF::Trine::Statement->new(
RDF::Trine::Node::Resource->new($self->context->document_uri),
RDF::Trine::Node::Resource->new("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
RDF::Trine::Node::Resource->new("http://creativecommons.org/ns#Work"),
));
$model->add_statement(RDF::Trine::Statement->new(
RDF::Trine::Node::Resource->new($self->data->{'href'}),
RDF::Trine::Node::Resource->new("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
RDF::Trine::Node::Resource->new("http://creativecommons.org/ns#License"),
));
foreach my $uri (qw(http://creativecommons.org/ns#license
http://www.w3.org/1999/xhtml/vocab#license
http://purl.org/dc/terms/license))
{
$model->add_statement(RDF::Trine::Statement->new(
RDF::Trine::Node::Resource->new($self->context->document_uri),
RDF::Trine::Node::Resource->new($uri),
RDF::Trine::Node::Resource->new($self->data->{'href'}),
));
}
return $self;
}
1;
=head1 MICROFORMAT
HTML::Microformats::Format::RelLicense supports rel-license as described at
L.
=head1 RDF OUTPUT
Data is returned using the Creative Commons vocabulary
(L) and occasional other terms.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hCard/ 0000755 0000764 0000764 00000000000 11775404022 021304 5 ustar tai tai HTML-Microformats-0.105/lib/HTML/Microformats/Format/hCard/n.pm 0000644 0000764 0000764 00000005144 11775403507 022112 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hCard::n - helper for hCards; handles the n property
=head1 DESCRIPTION
Technically, this inherits from HTML::Microformats::Format, so can be used in the
same way as any of the other microformat module, though I don't know why you'd
want to.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
package HTML::Microformats::Format::hCard::n;
use base qw(HTML::Microformats::Format HTML::Microformats::Mixin::Parser);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Format::hCard;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hCard::n::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hCard::n::VERSION = '0.105';
}
sub new
{
my ($class, $element, $context) = @_;
my $cache = $context->cache;
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
};
bless $self, $class;
my $clone = $element->cloneNode(1);
$self->_expand_patterns($clone);
$self->_simple_parse($clone);
return $self;
}
sub format_signature
{
my $self = shift;
my $vcard = 'http://www.w3.org/2006/vcard/ns#';
my $vx = 'http://buzzword.org.uk/rdf/vcardx#';
return {
'root' => 'n',
'classes' => [
['additional-name', '*'],
['family-name', '*'],
['given-name', '*'],
['honorific-prefix', '*'],
['honorific-suffix', '*'],
['initial', '*'], # extension
],
'options' => {
'no-destroy' => ['adr', 'geo']
},
'rdf:type' => ["${vcard}Name"] ,
'rdf:property' => {
'additional-name' => { 'literal' => ["${vcard}additional-name"] } ,
'family-name' => { 'literal' => ["${vcard}family-name"] } ,
'given-name' => { 'literal' => ["${vcard}given-name"] } ,
'honorific-prefix' => { 'literal' => ["${vcard}honorific-prefix"] } ,
'honorific-suffix' => { 'literal' => ["${vcard}honorific-suffix"] } ,
'honorific-initial' => { 'literal' => ["${vx}initial"] } ,
},
};
}
sub profiles
{
return HTML::Microformats::Format::hCard::profiles(@_);
}
1;
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hCard/impp.pm 0000644 0000764 0000764 00000002344 11775403507 022621 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hCard::impp - helper for hCards; handles the impp property
=head1 DESCRIPTION
Technically, this inherits from HTML::Microformats::Format::hCard::TypedField, so can be used in the
same way as any of the other microformat module, though I don't know why you'd
want to.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
package HTML::Microformats::Format::hCard::impp;
use base qw(HTML::Microformats::Format::hCard::TypedField);
use strict qw(subs vars); no warnings;
use 5.010;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hCard::impp::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hCard::impp::VERSION = '0.105';
}
1;
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hCard/TypedField.pm 0000644 0000764 0000764 00000010124 11775403507 023700 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hCard::TypedField - helper for hCards; handles value plus type properties
=head1 DESCRIPTION
Technically, this inherits from HTML::Microformats::Format, so can be used in the
same way as any of the other microformat module, though I don't know why you'd
want to.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
package HTML::Microformats::Format::hCard::TypedField;
use base qw(HTML::Microformats::Format HTML::Microformats::Mixin::Parser);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Format::hCard;
use HTML::Microformats::Utilities qw(searchClass stringify);
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hCard::TypedField::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hCard::TypedField::VERSION = '0.105';
}
sub new
{
my ($class, $element, $context) = @_;
my $cache = $context->cache;
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
};
bless $self, $class;
my $hclass = 'tel';
$hclass = $1 if $class =~ /::([^:]+)$/;
my $clone = $element->cloneNode(1);
$self->_expand_patterns($clone);
$self->_simple_parse($clone);
unless (length $self->{'DATA'}->{'value'} or $hclass eq 'label')
{
if ($element->hasAttribute('href'))
{
$self->{'DATA'}->{'value'} = $self->context->uri( $element->getAttribute('href') );
}
elsif ($element->hasAttribute('src'))
{
$self->{'DATA'}->{'value'} = $self->context->uri( $element->getAttribute('src') );
}
}
unless (length $self->{'DATA'}->{'value'})
{
my @types = searchClass('type', $clone);
foreach my $type (@types)
{
$type->parentNode->removeChild($type);
}
$self->{'DATA'}->{'value'} = stringify($clone, {'value-title'=>'allow'});
$self->{'DATA'}->{'value'} =~ s/(^\s+|\s+$)//g;
}
$self->_fix_value_uri;
return $self;
}
sub _fix_value_uri
{
my $self = shift;
# no-op. override in descendent classes.
}
sub format_signature
{
my $self = shift;
my $vcard = 'http://www.w3.org/2006/vcard/ns#';
my $vx = 'http://buzzword.org.uk/rdf/vcardx#';
my $package = $self;
$package = ref $package if ref $package;
my $hclass = 'tel';
$hclass = $1 if $package =~ /::([^:]+)$/;
my $u = $hclass =~ m'^(tel|email)$'i ? 'u' : '';
return {
'root' => $hclass,
'classes' => [
['type', '*', {'value-title'=>'allow'}],
['value', '&v'.$u, {'value-title'=>($hclass eq 'tel' ? 'allow' : undef)}],
],
'options' => {
'no-destroy' => ['adr', 'geo']
},
'rdf:type' => [ (($hclass =~ /^(tel|email|label)$/) ? $vcard : $vx).ucfirst $hclass ] ,
'rdf:property' => {
'type' => { 'literal' => ["${vx}usage"] } ,
'value' => { 'literal' => ["http://www.w3.org/1999/02/22-rdf-syntax-ns#value"] , 'resource' => ["http://www.w3.org/1999/02/22-rdf-syntax-ns#value"] } ,
},
};
}
sub add_to_model
{
my $self = shift;
my $model = shift;
$self->_simple_rdf($model);
my @types;
foreach my $type (@{ $self->data->{'type'} })
{
if ($type =~ /^(dom|home|intl|parcel|postal|pref|work|video|x400|voice|PCS|pager|msg|modem|ISDN|internet|fax|cell|car|BBS)$/i)
{
my $canon = ucfirst lc $1;
$canon = uc $canon if $canon=~ /(pcs|bbs|isdn)/i;
push @types, {
'value' => 'http://www.w3.org/2006/vcard/ns#'.$canon,
'type' => 'uri',
};
}
}
if (@types)
{
$model->add_hashref({
$self->id =>
{ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' => \@types }
});
}
return $self;
}
sub profiles
{
return HTML::Microformats::Format::hCard::profiles(@_);
}
1;
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hCard/tel.pm 0000644 0000764 0000764 00000003706 11775403507 022443 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hCard::tel - helper for hCards; handles the tel property
=head1 DESCRIPTION
Technically, this inherits from HTML::Microformats::Format::hCard::TypedField, so can be used in the
same way as any of the other microformat module, though I don't know why you'd
want to.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
package HTML::Microformats::Format::hCard::tel;
use base qw(HTML::Microformats::Format::hCard::TypedField);
use strict qw(subs vars); no warnings;
use 5.010;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hCard::tel::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hCard::tel::VERSION = '0.105';
}
sub _fix_value_uri
{
my $self = shift;
my $uri;
return if $self->{'DATA'}->{'value'} =~ /^(tel|modem|fax):\S+$/i;
my $number = $self->{'DATA'}->{'value'};
$number =~ s/[^\+\*\#x0-9]//gi;
($number, my $extension) = split /x/i, $number, 2;
if ($number =~ /^\+/ and $number !~ /[\*\#]/) # global number
{
if (length $extension)
{
$uri = sprintf('tel:%s;ext=%s', $number, $extension);
}
else
{
$uri = sprintf('tel:%s', $number);
}
}
else #local number
{
if (length $extension)
{
$uri = sprintf('tel:%s;ext=%s;phone-context=localhost.localdomain', $number, $extension);
}
else
{
$uri = sprintf('tel:%s;phone-context=localhost.localdomain', $number);
}
}
$self->{'DATA'}->{'value'} = $uri;
}
1;
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hCard/email.pm 0000644 0000764 0000764 00000003133 11775403507 022740 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hCard::email - helper for hCards; handles the email property
=head1 DESCRIPTION
Technically, this inherits from HTML::Microformats::Format::hCard::TypedField, so can be used in the
same way as any of the other microformat module, though I don't know why you'd
want to.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
package HTML::Microformats::Format::hCard::email;
use base qw(HTML::Microformats::Format::hCard::TypedField);
use strict qw(subs vars); no warnings;
use 5.010;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hCard::email::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hCard::email::VERSION = '0.105';
}
sub _fix_value_uri
{
my $self = shift;
return if $self->{'DATA'}->{'value'} =~ /^(mailto):\S+\@\S+$/i;
# I only know how to fix SMTP addresses...
return unless $self->{'DATA'}->{'value'} =~ /.+\@.+/i;
my $email = $self->{'DATA'}->{'value'};
$email =~ s/\s//g;
$email = "mailto:$email" unless $email =~ /^mailto:/i;
$self->{'DATA'}->{'value'} = $email;
}
1;
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hCard/org.pm 0000644 0000764 0000764 00000006240 11775403507 022442 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hCard::org - helper for hCards; handles the org property
=head1 DESCRIPTION
Technically, this inherits from HTML::Microformats::Format, so can be used in the
same way as any of the other microformat module, though I don't know why you'd
want to.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
package HTML::Microformats::Format::hCard::org;
use base qw(HTML::Microformats::Format HTML::Microformats::Mixin::Parser);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Format::hCard;
use HTML::Microformats::Utilities qw(stringify);
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hCard::org::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hCard::org::VERSION = '0.105';
}
sub new
{
my ($class, $element, $context) = @_;
my $cache = $context->cache;
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
};
bless $self, $class;
my $clone = $element->cloneNode(1);
$self->_expand_patterns($clone);
$self->_simple_parse($clone);
if ($self->element->getAttribute('class') =~ /\b(org)\b/)
{
unless (defined $self->data->{'organization-name'}
or defined $self->data->{'organization-unit'}
or defined $self->data->{'x-vat-number'}
or defined $self->data->{'x-charity-number'}
or defined $self->data->{'x-company-number'})
{
$self->{'DATA'}->{'organization-name'} = stringify($clone, 'value');
}
}
return $self;
}
sub format_signature
{
my $self = shift;
my $vcard = 'http://www.w3.org/2006/vcard/ns#';
my $vx = 'http://buzzword.org.uk/rdf/vcardx#';
return {
'root' => 'org',
'classes' => [
['organization-name', '?'],
['organization-unit', '*'],
['x-vat-number', '?'],
['x-charity-number', '?'],
['x-company-number', '?'],
['vat-number', '?', {'use-key'=>'x-vat-number'}],
['charity-number', '?', {'use-key'=>'x-charity-number'}],
['company-number', '?', {'use-key'=>'x-company-number'}],
],
'options' => {
'no-destroy' => ['adr', 'geo']
},
'rdf:type' => ["${vcard}Organization"] ,
'rdf:property' => {
'organization-name' => { 'literal' => ["${vcard}organization-name"] } ,
'organization-unit' => { 'literal' => ["${vcard}organization-unit"] } ,
'x-vat-number' => { 'literal' => ["${vx}x-vat-number"] } ,
'x-charity-number' => { 'literal' => ["${vx}x-charity-number"] } ,
'x-company-number' => { 'literal' => ["${vx}x-company-number"] } ,
},
};
}
sub profiles
{
return HTML::Microformats::Format::hCard::profiles(@_);
}
1;
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hCard/label.pm 0000644 0000764 0000764 00000002351 11775403507 022731 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hCard::label - helper for hCards; handles the label property
=head1 DESCRIPTION
Technically, this inherits from HTML::Microformats::Format::hCard::TypedField, so can be used in the
same way as any of the other microformat module, though I don't know why you'd
want to.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
package HTML::Microformats::Format::hCard::label;
use base qw(HTML::Microformats::Format::hCard::TypedField);
use strict qw(subs vars); no warnings;
use 5.010;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hCard::label::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hCard::label::VERSION = '0.105';
}
1;
HTML-Microformats-0.105/lib/HTML/Microformats/Format/XOXO.pm 0000644 0000764 0000764 00000027253 11775403507 021436 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::XOXO - the XOXO microformat
=head1 SYNOPSIS
use HTML::Microformats::DocumentContext;
use HTML::Microformats::Format::XOXO;
my $context = HTML::Microformats::DocumentContext->new($dom, $uri);
my @objects = HTML::Microformats::Format::XOXO->extract_all(
$dom->documentElement, $context);
my $list = $objects[0];
# Let's assume this structure:
#
#
# -
# Toby Inkster
#
# - Eye colour
# - Blue
#
- Hair colour
# - Blonde
#
- Brown
#
#
#
print $list->data->as_array->[0]->get_link_title;
# Toby Inkster
print $list->data->as_array->[0]->get_properties
->get_value('Eye colour')->[0];
# Blue
print join '-', $list->data->as_array->[0]
->get_value('Hair colour');
# Blonde-Brown
=head1 DESCRIPTION
HTML::Microformats::Format::XOXO inherits from HTML::Microformats::Format. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
Unlike most of the modules in the HTML::Microformats suite,
the C method returns an HTML::Microformats::Format::XOXO::UL,
HTML::Microformats::Format::XOXO::OL or HTML::Microformats::Format::XOXO::DL
object, rather than a plain hashref.
=cut
package HTML::Microformats::Format::XOXO;
use base qw(HTML::Microformats::Format);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(stringify xml_stringify);
use JSON qw/to_json/;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::XOXO::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::XOXO::VERSION = '0.105';
}
sub new
{
my ($class, $element, $context) = @_;
my $cache = $context->cache;
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
};
bless $self, $class;
if ($element->hasAttribute('id') && length $element->getAttribute('id'))
{
$self->{'id'} = $context->uri('#' . $element->getAttribute('id'));
}
else
{
$self->{'id'} = $context->make_bnode($element);
}
return undef unless $element->localname =~ /^[DOU]L$/i;
$self->{'DATA'} = $self->_parse_list($element->cloneNode(1));
$cache->set($context, $element, $class, $self)
if defined $cache;
return $self;
}
sub _parse_list
{
my ($self, $e) = @_;
if (lc $e->localname eq 'ul')
{ return HTML::Microformats::Format::XOXO::UL->parse($e, $self); }
elsif (lc $e->localname eq 'ol')
{ return HTML::Microformats::Format::XOXO::OL->parse($e, $self); }
elsif (lc $e->localname eq 'dl')
{ return HTML::Microformats::Format::XOXO::DL->parse($e, $self); }
return undef;
}
sub format_signature
{
return {
'root' => 'xoxo',
'classes' => [],
'options' => {},
'rdf:type' => [] ,
'rdf:property' => {},
};
}
sub add_to_model
{
my $self = shift;
my $model = shift;
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
RDF::Trine::Node::Resource->new('http://purl.org/dc/dcmitype/Dataset'),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new('http://open.vocab.org/terms/json'),
$self->_make_literal( to_json($self, {canonical=>1,convert_blessed=>1}) ),
));
return $self;
}
sub profiles
{
return qw(http://microformats.org/profile/xoxo
http://ufs.org/x/xoxo
http://microformats.org/profile/specs
http://ufs.org/x/specs
http://purl.org/uF/2008/03/);
}
1;
package HTML::Microformats::Format::XOXO::AbstractList;
use strict qw(subs vars); no warnings;
use 5.010;
sub parse
{
my ($class, $e, $xoxo) = @_;
my @items;
foreach my $li ($e->getChildrenByTagName('li'))
{ push @items, HTML::Microformats::Format::XOXO::LI->parse($li, $xoxo); }
bless \@items, $class;
}
sub TO_JSON
{
return [ @{$_[0]} ];
}
sub as_array
{
my ($self) = @_;
return wantarray ? @$self : $self;
}
1;
=head2 HTML::Microformats::Format::XOXO::DL
Represents an HTML DL element.
=over 4
=item C<< $dl->get_values($key) >>
Treating a DL as a key-value structure, returns a list of values for a given key.
Each value is an HTML::Microformats::Format::XOXO::DD object.
=item C<< $dl->as_hash >>
Returns a hash of keys pointing to arrayrefs of values, where each value is an
HTML::Microformats::Format::XOXO::DD object.
=item C<< $dl->as_array >>
Logically what you think get_values("*") might do.
=back
=cut
package HTML::Microformats::Format::XOXO::DL;
use base qw[HTML::Microformats::Format::XOXO::AbstractList];
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(stringify xml_stringify);
sub parse
{
my ($class, $e, $xoxo) = @_;
my $dict = {};
my $term;
foreach my $kid ($e->childNodes)
{
next unless $kid->isa('XML::LibXML::Element');
if ($kid->localname =~ /^DT$/i)
{
$term = stringify($kid);
if ($kid->hasAttribute('id'))
{
$dict->{$term}->{'id'} = $kid->getAttribute('id');
}
}
elsif (defined $term)
{
push @{ $dict->{$term}->{'items'} }, HTML::Microformats::Format::XOXO::DD->parse($kid, $xoxo);
}
}
bless $dict, $class;
}
sub TO_JSON
{
my $self = shift;
my $rv = {};
while (my ($k, $v) = each %$self)
{
$rv->{$k} = $v->{'items'};
}
return $rv;
}
sub get_values
{
my ($self, $key) = @_;
return wantarray ? @{ $self->{$key}->{'items'} } : $self->{$key}->{'items'}
if defined $self->{$key}->{'items'};
}
sub as_hash
{
my ($self) = @_;
return $self->TO_JSON;
}
sub as_array
{
my ($self, $key) = @_;
my @rv;
foreach my $key (sort keys %$self)
{
push @rv, @{ $self->{$key}->{'items'} };
}
return wantarray ? @rv : \@rv;
}
1;
=head2 HTML::Microformats::Format::XOXO::UL
Represents an HTML UL element.
=over 4
=item C<< $ul->as_array >>
Returns an array of values, where each is a HTML::Microformats::Format::XOXO::LI object.
=back
=cut
package HTML::Microformats::Format::XOXO::UL;
use base qw(HTML::Microformats::Format::XOXO::AbstractList);
use strict qw(subs vars); no warnings;
use 5.010;
1;
=head2 HTML::Microformats::Format::XOXO::OL
Represents an HTML OL element.
=over 4
=item C<< $ol->as_array >>
Returns an array of values, where each is a HTML::Microformats::Format::XOXO::LI object.
=back
=cut
package HTML::Microformats::Format::XOXO::OL;
use base qw(HTML::Microformats::Format::XOXO::AbstractList);
use strict qw(subs vars); no warnings;
use 5.010;
1;
package HTML::Microformats::Format::XOXO::AbstractListItem;
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(stringify xml_stringify);
our $for_get_them_not = 'a|dl|li|ol|ul';
sub parse
{
my ($class, $e, $xoxo) = @_;
my $self = bless {}, $class;
my $a = $self->_get_them($e, 'a');
my $dl = $self->_get_them($e, 'dl');
my $l = $self->_get_them($e, 'ol|ul');
if ($a)
{
$self->{'url'} = $xoxo->context->uri($a->getAttribute('href'))
if $a->hasAttribute('href');
$self->{'type'} = $a->getAttribute('type')
if $a->hasAttribute('type');
$self->{'rel'} = $a->getAttribute('rel')
if $a->hasAttribute('rel');
$self->{'title'} = $a->getAttribute('title') || stringify($a);
}
if ($dl)
{
$self->{'properties'} = HTML::Microformats::Format::XOXO::DL->parse($dl, $xoxo);
$dl->parentNode->removeChild($dl);
}
if (defined $l && lc $l->localname eq 'ul')
{
$self->{'children'} = HTML::Microformats::Format::XOXO::UL->parse($l, $xoxo);
$l->parentNode->removeChild($l);
}
elsif (defined $l && lc $l->localname eq 'ol')
{
$self->{'children'} = HTML::Microformats::Format::XOXO::OL->parse($l, $xoxo);
$l->parentNode->removeChild($l);
}
$self->{'text'} = stringify($e);
$self->{'html'} = xml_stringify($e);
return $self;
}
sub _get_them
{
my ($self, $e, $pattern) = @_;
my @rv;
my @check = $e->childNodes;
while (@check)
{
my $elem = shift @check;
next unless $elem->isa('XML::LibXML::Element');
if ($elem->localname =~ /^($pattern)$/i)
{
if (wantarray)
{ push @rv, $elem; }
else
{ return $elem; }
}
if ($elem->localname !~ /^($for_get_them_not)$/i)
{
unshift @check, $elem->childNodes;
}
}
if (wantarray)
{ return @rv; }
else
{ return undef; }
}
sub TO_JSON
{
my %rv = %{$_[0]};
delete $rv{'html'};
return \%rv;
}
sub get_link_href
{
my ($self) = @_;
return $self->{'url'};
}
sub get_link_rel
{
my ($self) = @_;
return $self->{'rel'};
}
sub get_link_type
{
my ($self) = @_;
return $self->{'type'};
}
sub get_link_title
{
my ($self) = @_;
return $self->{'title'};
}
sub get_text
{
my ($self) = @_;
return $self->{'text'};
}
sub get_html
{
my ($self) = @_;
return $self->{'html'};
}
sub get_properties
{
my ($self) = @_;
return $self->{'properties'};
}
sub get_children
{
my ($self) = @_;
return $self->{'children'};
}
sub get_value
{
my ($self, $key) = @_;
return $self->get_properties->get_values($key)
if $self->get_properties;
}
1;
=head2 HTML::Microformats::Format::XOXO::LI
Represents an HTML LI element.
=over 4
=item C<< $li->get_link_href >>
Returns the URL linked to by the B link found within the item.
=item C<< $li->get_link_rel >>
Returns the value of the rel attribute of the first link found within the item.
This is an unparsed string.
=item C<< $li->get_link_type >>
Returns the value of the type attribute of the first link found within the item.
This is an unparsed string.
=item C<< $li->get_link_title >>
Returns the value of the rel attribute of the first link found within the item
if present; the link text otherwise.
=item C<< $li->get_text >>
Returns the value of the text in the LI element B for the first DL
element within the LI, and the first UL or OL element.
=item C<< $li->get_html >>
Returns the HTML code in the LI element B for the first DL
element within the LI, and the first UL or OL element.
=item C<< $li->get_properties >>
Returns an HTML::Microformats::Format::XOXO::DL object representing the first
DL element within the LI.
=item C<< $li->get_children >>
Returns an HTML::Microformats::Format::XOXO::OL or HTML::Microformats::Format::XOXO::UL
object representing the first OL or UL element within the LI.
=item C<< $li->get_value($key) >>
A shortcut for C<< $li->get_properties->get_values($key) >>.
=back
=cut
package HTML::Microformats::Format::XOXO::LI;
use base qw(HTML::Microformats::Format::XOXO::AbstractListItem);
use strict qw(subs vars); no warnings;
use 5.010;
1;
=head2 HTML::Microformats::Format::XOXO::DD
This has an identical interface to HTML::Microformats::Format::XOXO::LI.
=cut
package HTML::Microformats::Format::XOXO::DD;
use base qw(HTML::Microformats::Format::XOXO::AbstractListItem);
use strict qw(subs vars); no warnings;
use 5.010;
1;
=head1 MICROFORMAT
HTML::Microformats::Format::XOXO supports XOXO as described at
L.
=head1 RDF OUTPUT
XOXO does not map especially naturally to RDF, so this module returns
the data as a JSON literal using the property L.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hAtom.pm 0000644 0000764 0000764 00000013323 11775403507 021702 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hAtom - the hAtom microformat
=head1 SYNOPSIS
use Data::Dumper;
use HTML::Microformats::DocumentContext;
use HTML::Microformats::Format::hAtom;
my $context = HTML::Microformats::DocumentContext->new($dom, $uri);
my @feeds = HTML::Microformats::Format::hAtom->extract_all(
$dom->documentElement, $context);
foreach my $feed (@feeds)
{
foreach my $entry ($feed->get_entry)
{
print $entry->get_link . "\n";
}
}
=head1 DESCRIPTION
HTML::Microformats::Format::hAtom inherits from HTML::Microformats::Format. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=head2 Additional Method
=over
=item * C<< to_atom >>
This method exports the data as an XML file containing an Atom .
It requires L to work, and will throw an error at
run-time if it's not available.
=back
=cut
package HTML::Microformats::Format::hAtom;
use base qw(HTML::Microformats::Format HTML::Microformats::Mixin::Parser);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(searchAncestorClass);
use HTML::Microformats::Datatype::String qw(isms);
use HTML::Microformats::Format::hCard;
use HTML::Microformats::Format::hEntry;
use HTML::Microformats::Format::hNews;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hAtom::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hAtom::VERSION = '0.105';
}
our $HAS_ATOM_EXPORT;
BEGIN
{
local $@ = undef;
eval 'use XML::Atom::FromOWL;';
$HAS_ATOM_EXPORT = 1
if XML::Atom::FromOWL->can('new');
}
sub new
{
my ($class, $element, $context) = @_;
my $cache = $context->cache;
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
};
bless $self, $class;
my $clone = $self->{'element'}->cloneNode(1);
$self->_expand_patterns($clone);
$self->_simple_parse($clone);
$cache->set($context, $element, $class, $self)
if defined $cache;
return $self;
}
sub extract_all
{
my ($class, $element, $context) = @_;
my @feeds = HTML::Microformats::Format::extract_all($class, $element, $context);
if ($element->tagName eq 'html' || !@feeds)
{
my @entries = HTML::Microformats::Format::hEntry->extract_all($element, $context);
my $orphans = 0;
foreach my $entry (@entries)
{
$orphans++ unless searchAncestorClass('hfeed', $entry->element);
}
if ($orphans)
{
my $slurpy = $class->new($element, $context);
unshift @feeds, $slurpy;
}
}
return @feeds;
}
sub format_signature
{
my $awol = 'http://bblfish.net/work/atom-owl/2006-06-06/#';
my $ax = 'http://buzzword.org.uk/rdf/atomix#';
my $iana = 'http://www.iana.org/assignments/relation/';
my $rdfs = 'http://www.w3.org/2000/01/rdf-schema#';
return {
'root' => ['hfeed'],
'classes' => [
['hentry', 'm*', {'embedded'=>'hEntry', 'use-key'=>'entry'}],
],
'options' => {
'rel-tag' => 'category',
},
'rdf:type' => ["${awol}Feed"] ,
'rdf:property' => {
'entry' => { resource => ["${awol}entry"] } ,
'category' => { resource => ["${awol}category"] } ,
},
};
}
sub add_to_model
{
my $self = shift;
my $model = shift;
$self->_simple_rdf($model);
my $awol = 'http://bblfish.net/work/atom-owl/2006-06-06/#';
my $ax = 'http://buzzword.org.uk/rdf/atomix#';
my $iana = 'http://www.iana.org/assignments/relation/';
my $rdfs = 'http://www.w3.org/2000/01/rdf-schema#';
my $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
foreach my $author (@{ $self->data->{'author'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${awol}author"),
$author->id(1, 'holder'),
));
$author->add_to_model($model);
}
return $self;
}
sub to_atom
{
my ($self) = @_;
die "Need XML::Atom::FromOWL to export Atom.\n" unless $HAS_ATOM_EXPORT;
my $exporter = XML::Atom::FromOWL->new;
return $exporter->export_feed($self->model, $self->id(1))->as_xml;
}
sub profiles
{
my @p = qw();
push @p, HTML::Microformats::Format::hEntry->profiles;
push @p, HTML::Microformats::Format::hNews->profiles;
return @p;
}
1;
=head1 MICROFORMAT
HTML::Microformats::Format::hAtom supports hAtom as described at
L, with the following additions:
=over 4
=item * Embedded rel-enclosure microformat
hAtom entries may use rel-enclosure to specify entry enclosures.
=item * Threading support
An entry may use rel="in-reply-to" to indicate another entry or a document that
this entry is considered a reply to.
An entry may use class="replies hfeed" to provide an hAtom feed of responses to it.
=back
=head1 RDF OUTPUT
Data is returned using Henry Story's AtomOWL vocabulary
(L), Toby Inkster's
AtomOWL extensions (L) and
the IANA registered relationship URIs (L).
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L,
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/XMDP.pm 0000644 0000764 0000764 00000010372 11775403507 021403 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::XMDP - the XMDP microformat
=head1 SYNOPSIS
use HTML::Microformats;
use LWP::Simple qw[get];
use RDF::TrineShortcuts;
my $uri = 'http://microformats.org/profile/hcard';
my $html = get($uri);
my $doc = HTML::Microformats->new_document($html, $uri);
$doc->assume_all_profiles;
my @xmdp_objects = $doc->objects('XMDP');
foreach my $xo (@xmdp_objects)
{
print $xo->serialise_model(
as => 'Turtle',
namespaces => {
rdfs => 'http://www.w3.org/2000/01/rdf-schema#',
hcard => 'http://microformats.org/profile/hcard#',
},
);
print "########\n\n";
}
=head1 DESCRIPTION
HTML::Microformats::Format::XMDP inherits from HTML::Microformats::Format. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
HTML::Microformats::Format::XMDP also inherits from HTML::Microformats::Format::XOXO, and
the C method returns the same structure.
=cut
package HTML::Microformats::Format::XMDP;
use base qw(HTML::Microformats::Format::XOXO);
use strict qw(subs vars); no warnings;
use 5.010;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::XMDP::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::XMDP::VERSION = '0.105';
}
sub new
{
my $class = shift;
my $self = $class->SUPER::new(@_);
return $self;
}
sub format_signature
{
return {
'root' => ['profile'] ,
'classes' => [] ,
'rdf:type' => [] ,
'rdf:property' => {} ,
}
}
sub profiles
{
return qw(http://gmpg.org/xmdp/1);
}
sub add_to_model
{
my $self = shift;
my $model = shift;
$self->SUPER::add_to_model($model);
while (my ($term, $data) = each %{ $self->data })
{
$self->_add_term_to_model($model, $term, $data);
}
return $self;
}
sub _add_term_to_model
{
my ($self, $model, $term, $data) = @_;
my $rdfs = 'http://www.w3.org/2000/01/rdf-schema#';
my $ident = RDF::Trine::Node::Blank->new(
substr($self->context->make_bnode, 2));
if (defined $data->{'id'})
{
$ident = RDF::Trine::Node::Resource->new(
$self->context->uri('#'.$data->{'id'}));
}
$model->add_statement(RDF::Trine::Statement->new(
$ident,
RDF::Trine::Node::Resource->new("${rdfs}label"),
$self->_make_literal($term),
));
$model->add_statement(RDF::Trine::Statement->new(
$ident,
RDF::Trine::Node::Resource->new("${rdfs}isDefinedBy"),
$self->id(1),
));
foreach my $item (@{$data->{'items'}})
{
$model->add_statement(RDF::Trine::Statement->new(
$ident,
RDF::Trine::Node::Resource->new("${rdfs}comment"),
$self->_make_literal($item->{'text'}),
))
if defined $item->{'text'};
if ($item->{'rel'} =~ /^(help|glossary)$/ && defined $item->{'url'})
{
$model->add_statement(RDF::Trine::Statement->new(
$ident,
RDF::Trine::Node::Resource->new("http://www.w3.org/1999/xhtml/vocab#".lc $1),
RDF::Trine::Node::Resource->new($item->{'url'}),
));
}
while (my ($child_term, $child_data) = each %{ $item->{'properties'} })
{
my $child_ident = $self->_add_term_to_model($model, $child_term, $child_data);
$model->add_statement(RDF::Trine::Statement->new(
$ident,
RDF::Trine::Node::Resource->new("${rdfs}seeAlso"),
$child_ident,
));
}
}
return $ident;
}
1;
=head1 MICROFORMAT
HTML::Microformats::Format::XMDP supports XMDP as described at
L.
=head1 RDF OUTPUT
Data is returned using RDFS.
=head1 BUGS
A limitation is that for any EddE element with
EdlE children, only the first such EdlE
is looked at. This means that the XFN 1.1 profile document
is only partially parsable; most other microformat profile
document can be properly parsed though.
Please report any bugs to L.
=head1 SEE ALSO
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hCard.pm 0000644 0000764 0000764 00000055514 11775403507 021663 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hCard - the hCard microformat
=head1 SYNOPSIS
use HTML::Microformats::DocumentContext;
use HTML::Microformats::Format::hCard;
my $context = HTML::Microformats::DocumentContext->new($dom, $uri);
my @cards = HTML::Microformats::Format::hCard->extract_all(
$dom->documentElement, $context);
foreach my $card (@cards)
{
print $card->get_fn . "\n";
}
=head1 DESCRIPTION
HTML::Microformats::Format::hCard inherits from HTML::Microformats::Format. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=head2 Additional Method
=over
=item * C<< to_vcard >>
This method exports the hCard as a vCard 3.0. It requires L to work,
and will throw an error at run-time if it's not available.
=item * C<< to_vcard4 >>
This method exports the hCard as a vCard 3.0. It requires L to work,
and will throw an error at run-time if it's not available.
=item * C<< to_vcard4_xml >>
This method exports the hCard as a vCard XML. It requires L and
L to work, and will throw an error at run-time if it's not available.
=back
=cut
package HTML::Microformats::Format::hCard;
use base qw(HTML::Microformats::Format HTML::Microformats::Mixin::Parser);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Datatype::String;
use HTML::Microformats::Format::hCard::n;
use HTML::Microformats::Format::hCard::org;
use HTML::Microformats::Format::hCard::tel;
use HTML::Microformats::Format::hCard::email;
use HTML::Microformats::Format::hCard::label;
use HTML::Microformats::Format::hCard::impp;
use HTML::Microformats::Utilities qw(stringify searchClass);
use Scalar::Util qw();
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hCard::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hCard::VERSION = '0.105';
}
our $HAS_VCARD_EXPORT;
our $HAS_VCARD_XML_EXPORT;
BEGIN
{
local $@ = undef;
eval 'use RDF::vCard;';
$HAS_VCARD_EXPORT = 1
if RDF::vCard::Exporter->can('new');
eval {
$HAS_VCARD_XML_EXPORT = 1
if RDF::vCard::Exporter->can('new') && $RDF::vCard::WITH_XML;
};
}
sub new
{
my ($class, $element, $context, %options) = @_;
my $cache = $context->cache;
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
'id.holder' => $context->make_bnode ,
};
$self->{'in_hcalendar'} = $options{'in_hcalendar'};
bless $self, $class;
my $clone = $element->cloneNode(1);
$self->_expand_patterns($clone);
$self->_simple_parse($clone);
# In hCalendar, 'cn' is used instead of 'fn'.
if ($self->{'in_hcalendar'})
{
$self->{'DATA'}->{'fn'} = $self->{'DATA'}->{'cn'}
if defined $self->{'DATA'}->{'cn'}
&& !defined $self->{'DATA'}->{'fn'};
}
# Find more complicated nested structures.
# These can't be handled by _simple_parse.
push @{ $self->{'DATA'}->{'n'} }, HTML::Microformats::Format::hCard::n->extract_all($clone, $context);
push @{ $self->{'DATA'}->{'org'} }, HTML::Microformats::Format::hCard::org->extract_all($clone, $context);
push @{ $self->{'DATA'}->{'tel'} }, HTML::Microformats::Format::hCard::tel->extract_all($clone, $context);
push @{ $self->{'DATA'}->{'email'} }, HTML::Microformats::Format::hCard::email->extract_all($clone, $context);
push @{ $self->{'DATA'}->{'impp'} }, HTML::Microformats::Format::hCard::impp->extract_all($clone, $context);
push @{ $self->{'DATA'}->{'label'} }, HTML::Microformats::Format::hCard::label->extract_all($clone, $context);
foreach my $p (qw(n org tel email impp label adr))
{
delete $self->{'DATA'}->{$p}
unless @{ $self->{'DATA'}->{$p} || [] };
}
# Fallback if no 'org' is found.
# Try looking directly for org-like properties in the hCard.
unless (defined $self->{'DATA'}->{'org'} and @{ $self->{'DATA'}->{'org'} })
{
my $org = HTML::Microformats::Format::hCard::org->new($element, $context);
$org->{'id'} = $context->make_bnode; # don't share ID with $self!!
if ($org->data->{'organization-name'} || $org->data->{'organization-unit'})
{
push @{ $self->{'DATA'}->{'org'} }, $org;
}
}
# Fallback if no 'n' is found.
# Try looking directly for N-like properties in the hCard.
unless (defined $self->{'DATA'}->{'n'} and @{ $self->{'DATA'}->{'n'} })
{
my $n = HTML::Microformats::Format::hCard::n->new($element, $context);
$n->{'id'} = $context->make_bnode; # don't share ID with $self!!
if (@{ $n->data->{'family-name'} }
|| @{ $n->data->{'given-name'} }
|| @{ $n->data->{'additional-name'} }
|| @{ $n->data->{'initial'} }
|| @{ $n->data->{'honorific-prefix'} }
|| @{ $n->data->{'honorific-suffix'} })
{
push @{ $self->{'DATA'}->{'n'} }, $n;
}
}
# Detect kind ('individual', 'org', etc)
$self->_detect_kind;
# Perform N-optimisation.
$self->_n_optimisation
if lc $self->data->{'kind'} eq 'individual';
$cache->set($context, $element, $class, $self)
if defined $cache;
return $self;
}
sub new_fallback
{
my ($class, $element, $context, %options) = @_;
my $cache = $context->cache;
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
'id.holder' => $context->make_bnode ,
};
bless $self, $class;
$self->{'DATA'}->{'fn'} = stringify($element);
if ($element->getAttribute('href') =~ /^mailto\:/i)
{
push @{$self->{'DATA'}->{'email'}}, HTML::Microformats::Format::hCard::email->new($element, $context);
}
elsif ($element->getAttribute('href') =~ /^(tel|fax|modem)\:/i)
{
push @{$self->{'DATA'}->{'tel'}}, HTML::Microformats::Format::hCard::email->new($element, $context);
}
elsif ($element->hasAttribute('href'))
{
push @{$self->{'DATA'}->{'url'}}, $context->uri( $element->getAttribute('href') );
}
elsif ($element->tagName eq 'img' and $element->hasAttribute('src'))
{
push @{$self->{'DATA'}->{'photo'}}, $context->uri( $element->getAttribute('src') );
}
return $self;
}
sub _n_optimisation
{
my $self = shift;
if ($self->data->{'kind'} eq 'individual')
{
my $fnIsNick = (defined $self->{'DATA_'}->{'fn'}) && ($self->{'DATA_'}->{'fn'} =~ /\b(nickname)\b/);
unless (@{ $self->data->{'n'} } || $fnIsNick)
{
my $fn = $self->data->{'fn'};
$fn =~ s/(^\s|\s$)//g;
$fn =~ s/\s+/ /g;
my @words = split / /, $fn;
if (scalar @words == 1)
{
push @{ $self->data->{'nickname'} }, ms($words[0], $self->{'DATA_'}->{'fn'}) ;
}
elsif (scalar @words)
{
if (($words[0] =~ /^.*\,$/ || $words[1] =~ /^.\.?$/) && !defined $words[2])
{
$words[0] =~ s/[\.\,]$//;
$words[1] =~ s/[\.\,]$//;
push @{ $self->{'DATA'}->{'n'} },
(bless {
'DATA' => {
'given-name' => [ ms($words[1], $self->{'DATA_'}->{'fn'}) ],
'family-name' => [ ms($words[0], $self->{'DATA_'}->{'fn'}) ],
},
'element' => $self->{'DATA_'}->{'fn'},
'context' => $self->context,
'cache' => $self->cache,
'id' => $self->context->make_bnode($self->{'DATA_'}->{'fn'}),
},
'HTML::Microformats::Format::hCard::n');
}
elsif (!defined $words[2])
{
push @{ $self->{'DATA'}->{'n'} },
(bless {
'DATA' => {
'given-name' => [ ms($words[0], $self->{'DATA_'}->{'fn'}) ],
'family-name' => [ ms($words[1], $self->{'DATA_'}->{'fn'}) ],
},
'element' => $self->{'DATA_'}->{'fn'},
'context' => $self->context,
'cache' => $self->cache,
'id' => $self->context->make_bnode($self->{'DATA_'}->{'fn'}),
},
'HTML::Microformats::Format::hCard::n');
}
}
}
}
}
sub _detect_kind
{
my $self = shift;
my $rv = $self->{'DATA'};
# If 'kind' class provided explicitly, trust it.
if (length $rv->{'kind'})
{
# With canonicalisation though.
$rv->{'kind'} =~ s/(^\s|\s+$)//g;
$rv->{'kind'} = lc $rv->{'kind'};
return;
}
# If an 'fn' has been provided, guess.
if (length $rv->{'fn'})
{
# Assume it's an individual.
$rv->{'kind'} = 'individual';
# But check to see if the fn matches an org name or unit.
ORGLOOP: foreach my $org (@{ $rv->{'org'} })
{
if ("".$org->data->{'organization-name'} eq $rv->{'fn'})
{
$rv->{'kind'} = 'org';
last ORGLOOP;
}
foreach my $ou (@{ $org->data->{'organization-unit'} })
{
if ("$ou" eq $rv->{'fn'})
{
$rv->{'kind'} = 'group';
last ORGLOOP;
}
}
}
# If not, then check to see if the fn matches an address part.
if ($rv->{'kind'} eq 'individual')
{
ADRLOOP: foreach my $adr (@{ $rv->{'adr'} })
{
my $isFirstPart = 1;
foreach my $part (qw(post-office-box extended-address
street-address locality region postal-code country-name))
{
foreach my $line (@{ $adr->data->{$part} })
{
if ("$line" eq $rv->{'fn'})
{
$rv->{'kind'} = 'location';
$self->{'id.holder'} = $adr->id(0, 'place') if $isFirstPart;
last ADRLOOP;
}
$isFirstPart = 0;
}
}
}
}
return;
}
# Final assumption.
$rv->{'kind'} = 'individual';
}
sub format_signature
{
my $self = shift;
my $vcard = 'http://www.w3.org/2006/vcard/ns#';
my $vx = 'http://buzzword.org.uk/rdf/vcardx#';
my $ical = 'http://www.w3.org/2002/12/cal/icaltzd#';
my $ix = 'http://buzzword.org.uk/rdf/icaltzdx#';
my $geo = 'http://www.w3.org/2003/01/geo/wgs84_pos#';
# vCard 4.0 introduces CLIENTPIDMAP - best to ignore?
my $rv = {
'root' => 'vcard',
'classes' => [
['adr', 'm*', {'embedded'=>'adr'}],
['agent', 'MM*', {'embedded'=>'hCard'}],
['anniversary', 'd?'], #extension
['bday', 'd?'],
['biota', 'm*', {'embedded'=>'species', 'use-key'=>'species'}], #extension
['birth', 'M?', {'embedded'=>'hCard adr geo'}], #extension
['caladruri', 'u*'], #extension
['caluri', 'MMu*', {'embedded'=>'hCalendar'}], #extension
['category', '*'],
['class', '?', {'value-title'=>'allow'}],
['dday', 'd?'], #extension
['death', 'M?', {'embedded'=>'hCard adr geo'}], #extension
['email', '*#'],
['fn', '1<'],
['fburl', 'MMu*', {'embedded'=>'hCalendar'}], #extension
['gender', '?'], #extension
['geo', 'm*', {'embedded'=>'geo'}],
['impp', '*#'], #extension
['kind', '?', {'value-title'=>'allow'}], #extension
['key', 'u*'],
['label', '*#'],
['lang', '*', {'value-title'=>'allow'}], #extension
['logo', 'u*'],
['mailer', '*'],
['n', '*#'],
['nickname', '*'],
['note', '*'],
['org', '*#'],
['photo', 'u*'],
['rev', 'd*'],
['role', '*'],
['sex', 'n?'], #extension (0=?,1=M,2=F,9=na)
['sort-string', '?'],
['sound', 'u*'],
['tel', '*#'],
['title', '*'],
['tz', '?', {'value-title'=>'allow'}],
['uid', 'U?'],
['url', 'u*'],
],
'options' => {
'rel-me' => '_has_relme',
'rel-tag' => 'category',
'hmeasure' => 'measures', #extension
'no-destroy' => ['adr', 'geo'],
},
'rdf:type' => ["${vcard}VCard"] ,
'rdf:property' => {
'adr' => { 'resource' => ["${vcard}adr"] } ,
'agent' => { 'resource' => ["${vcard}agent"] , 'literal' => ["${vx}agent-literal"] } ,
'anniversary' => { 'literal' => ["${vx}anniversary"] },
'bday' => { 'literal' => ["${vcard}bday"] },
'birth' => { 'resource' => ["${vx}birth"] , 'literal' => ["${vx}birth-literal"] },
'caladruri' => { 'resource' => ["${vx}caladruri"] },
'caluri' => { 'resource' => ["${vx}caluri"] },
'category' => { 'resource' => ["${vx}category", 'http://www.holygoat.co.uk/owl/redwood/0.1/tags/taggedWithTag'] , 'literal' => ["${vcard}category"]},
'class' => { 'literal' => ["${vcard}class"] },
'dday' => { 'literal' => ["${vx}dday"] },
'death' => { 'resource' => ["${vx}death"] , 'literal' => ["${vx}death-literal"] },
'email' => { 'resource' => ["${vcard}email"] },
'fn' => { 'literal' => ["${vcard}fn", "http://www.w3.org/2000/01/rdf-schema#label"] },
'fburl' => { 'resource' => ["${vx}fburl"] },
'gender' => { 'literal' => ["${vx}gender"] },
'geo' => { 'resource' => ["${vcard}geo"] } ,
'impp' => { 'resource' => ["${vx}impp"] },
'kind' => { 'literal' => ["${vx}kind"] },
'key' => { 'resource' => ["${vcard}key"] },
'label' => { 'resource' => ["${vcard}label"] },
'lang' => { 'literal' => ["${vx}lang"] },
'logo' => { 'resource' => ["${vcard}logo"] },
'mailer' => { 'literal' => ["${vcard}mailer"] },
'n' => { 'resource' => ["${vcard}n"] },
'nickname' => { 'literal' => ["${vcard}nickname"] },
'note' => { 'literal' => ["${vcard}note"] },
'org' => { 'resource' => ["${vcard}org"] },
'photo' => { 'resource' => ["${vcard}photo"] },
'rev' => { 'literal' => ["${vcard}rev"] },
'role' => { 'literal' => ["${vcard}role"] },
'sex' => { 'literal' => ["${vx}sex"] },
'sort-string' => { 'literal' => ["${vcard}sort-string"] },
'sound' => { 'resource' => ["${vcard}sound"] },
'species' => { 'resource' => ["${vx}x-species"] },
'tel' => { 'resource' => ["${vcard}tel"] },
'title' => { 'literal' => ["${vcard}title"] },
'tz' => { 'literal' => ["${vcard}tz"] },
'uid' => { 'resource' => ["${vcard}uid"], 'literal' => ["${vcard}uid"] },
'url' => { 'resource' => ["${vcard}url"] },
'cn' => { 'literal' => ["${ical}cn"] },
'cutype' => { 'literal' => ["${ical}cutype"] },
'rsvp' => { 'literal' => ["${ical}rsvp"] },
'delegated-from' => { 'resource' => ["${ix}delegatedFrom"] , 'literal' => ["${ical}delegatedFrom"] },
'sent-by' => { 'resource' => ["${ix}sentBy"] , 'literal' => ["${ical}sentBy"] },
},
};
if (ref $self and $self->{'in_hcalendar'})
{
push @{ $rv->{'classes'} }, ( # these are ALL extensions
['cn', '?'],
['cutype', '?'],
['member', '?'],
['rsvp', '?'],
['delegated-from', 'Mu*',{'embedded'=>'hCard'}],
['sent-by', 'Mu*', {'embedded'=>'hCard'}],
);
$rv->{'rdf:property'}->{'member'} = { 'resource' => ["${ix}member"] , 'literal' => ["${ix}member"] };
}
else
{
push @{ $rv->{'classes'} }, (
['member', 'Mu*', {'embedded'=>'hCard'}], #extension
);
$rv->{'rdf:property'}->{'member'} = { 'resource' => ["${vx}member"] , 'literal' => ["${vx}member"] };
}
return $rv;
}
sub add_to_model
{
my $self = shift;
my $model = shift;
$self->_simple_rdf($model);
foreach my $property (qw(n org adr geo agent tel email label impp birth caluri death fburl delegated-from sent-by member species))
{
foreach my $value (@{ $self->data->{$property} })
{
if (Scalar::Util::blessed($value) and $value->can('add_to_model'))
{
$value->add_to_model($model);
}
}
}
# From the vCard we can infer data about its holder.
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new('http://purl.org/uF/hCard/terms/hasCard'),
$self->id(1),
));
if (lc $self->data->{'kind'} eq 'individual')
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/Person'),
));
}
elsif (lc $self->data->{'kind'} eq 'org')
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/Organization'),
));
}
elsif (lc $self->data->{'kind'} eq 'group')
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/Group'),
));
}
elsif (lc $self->data->{'kind'} eq 'location')
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
RDF::Trine::Node::Resource->new('http://www.w3.org/2003/01/geo/wgs84_pos#SpatialThing'),
));
}
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/name'),
$self->_make_literal($self->data->{'fn'}),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/gender'),
$self->_make_literal($self->data->{'gender'}),
))
if defined $self->data->{'gender'};
foreach my $url (@{ $self->data->{'url'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/page'),
RDF::Trine::Node::Resource->new($url),
));
}
foreach my $tel (@{ $self->data->{'tel'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/phone'),
RDF::Trine::Node::Resource->new($tel->get_value),
))
if $tel->get_value =~ /^(tel|fax|modem):\S+$/i;
}
foreach my $e (@{ $self->data->{'email'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/mbox'),
RDF::Trine::Node::Resource->new($e->get_value),
))
if $e->get_value =~ /^(mailto):\S+$/i;
}
foreach my $photo (@{ $self->data->{'photo'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/depiction'),
RDF::Trine::Node::Resource->new($photo),
));
}
foreach my $geo (@{ $self->data->{'geo'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/based_near'),
$geo->id(1, 'location'),
));
}
foreach my $species (@{ $self->data->{'species'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new('http://purl.org/NET/biol/ns#hasTaxonomy'),
$species->id(1),
));
}
}
$self->context->representative_hcard;
if ($self->{'representative'})
{
$model->add_statement(RDF::Trine::Statement->new(
RDF::Trine::Node::Resource->new($self->context->document_uri),
RDF::Trine::Node::Resource->new('http://purl.org/uF/hCard/terms/representative'),
$self->id(1),
));
}
$self->context->contact_hcard;
if ($self->{'contact'})
{
$model->add_statement(RDF::Trine::Statement->new(
RDF::Trine::Node::Resource->new($self->context->document_uri),
RDF::Trine::Node::Resource->new('http://purl.org/uF/hCard/terms/contact'),
$self->id(1),
));
}
return $self;
}
sub to_vcard
{
my ($self) = @_;
die "Need RDF::vCard to export vCard.\n" unless $HAS_VCARD_EXPORT;
my $exporter = RDF::vCard::Exporter->new();
return $exporter->export_card($self->model, $self->id(1))->to_string;
}
sub to_vcard4
{
my ($self) = @_;
die "Need RDF::vCard to export vCard.\n" unless $HAS_VCARD_EXPORT;
my $exporter = RDF::vCard::Exporter->new( vcard_version => 4 );
return $exporter->export_card($self->model, $self->id(1))->to_string;
}
sub to_vcard4_xml
{
my ($self) = @_;
die "Need RDF::vCard and XML::LibXML to export vCard.\n" unless $HAS_VCARD_XML_EXPORT;
my $exporter = RDF::vCard::Exporter->new( vcard_version => 4 );
return $exporter->export_card($self->model, $self->id(1))->to_xml;
}
sub profiles
{
my $class = shift;
return qw(http://microformats.org/profile/hcard
http://ufs.cc/x/hcard
http://microformats.org/profile/specs
http://ufs.cc/x/specs
http://www.w3.org/2006/03/hcard
http://purl.org/uF/hCard/1.0/
http://purl.org/uF/2008/03/);
}
1;
=head1 MICROFORMAT
HTML::Microformats::Format::hCard supports hCard as described at
L, with the following additions:
=over 4
=item * vCard 4.0 terms
This module includes additional property terms taken from the latest
vCard 4.0 drafts. For example the property 'impp' may be used to mark up
instant messaging addresses for a contact.
The vCard 4.0 property 'kind' is used to record the kind of contact described
by the hCard (an individual, an organisation, etc). In many cases this is
automatically inferred.
=item * Embedded species microformat
If the species microformat (see L) is found
embedded within an hCard, then this is taken to be the species of a contact.
=item * Embedded hMeasure
If the hMeasure microformat (see L) is
found embedded within an hCard, and no 'item' property is provided, then
the measurement is taken to pertain to the contact described by the hCard.
=back
=head1 RDF OUTPUT
Data is returned using the W3C's vCard vocabulary
(L) with some supplemental
terms from Toby Inkster's vCard extensions vocabulary
(L) and occasional other terms.
After long deliberation on the "has-a/is-a issue", the author of this
module decided that the holder of a vCard and the vCard itself should
be modelled as two separate resources, and this is how the data is
returned. Some information about the holder of the vCard can be inferred
from information about the vCard; for instance, the vCard's fn property
can be used to determin the holder's foaf:name. This module uses FOAF
(L) to represent information about the holder
of the vCard.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/figure.pm 0000644 0000764 0000764 00000020247 11775403507 022116 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::figure - the figure microformat
=head1 SYNOPSIS
use HTML::Microformats::DocumentContext;
use HTML::Microformats::Format::figure;
use Scalar::Util qw(blessed);
my $context = HTML::Microformats::DocumentContext->new($dom, $uri);
my @objects = HTML::Microformats::Format::figure->extract_all(
$dom->documentElement, $context);
foreach my $fig (@objects)
{
printf("<%s> %s\n", $fig->get_image, $fig->get_legend->[0]);
foreach my $maker ($p->get_credit)
{
if (blessed($maker))
{
printf(" - by %s\n", $maker->get_fn);
}
else
{
printf(" - by %s\n", $maker);
}
}
}
=head1 DESCRIPTION
HTML::Microformats::Format::figure inherits from HTML::Microformats::Format. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=cut
package HTML::Microformats::Format::figure;
use base qw(HTML::Microformats::Format HTML::Microformats::Mixin::Parser);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(searchClass searchID stringify);
use HTML::Microformats::Datatype::String qw(ms);
use Locale::Country qw(country2code LOCALE_CODE_ALPHA_2);
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::figure::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::figure::VERSION = '0.105';
}
sub new
{
my ($class, $element, $context) = @_;
my $cache = $context->cache;
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
};
bless $self, $class;
my $clone = $element->cloneNode(1);
$self->_expand_patterns($clone);
$self->_figure_parse($clone);
if (defined $self->{'DATA'}->{'image'})
{
$self->{'id'} = $self->{'DATA'}->{'image'};
}
else
{
return undef;
}
$cache->set($context, $element, $class, $self)
if defined $cache;
return $self;
}
sub _figure_parse
{
my ($self, $elem) = @_;
my ($desc_node, $image_node);
if ($elem->localname eq 'img' && $elem->getAttribute('class')=~/\b(image)\b/)
{
$image_node = $elem;
}
else
{
my @images = searchClass('image', $elem);
@images = $elem->getElementsByTagName('img') unless @images;
$image_node = $images[0] if @images;
}
if ($elem->localname eq 'img')
{
$image_node ||= $elem;
}
if ($image_node)
{
$self->{'DATA'}->{'image'} = $self->context->uri($image_node->getAttribute('src'));
$self->{'DATA'}->{'alt'} = ms($image_node->getAttribute('alt'), $image_node)
if $image_node->hasAttribute('alt');
$self->{'DATA'}->{'title'} = ms($image_node->getAttribute('title'), $image_node)
if $image_node->hasAttribute('title');
if ($image_node->getAttribute('longdesc') =~ m'^#(.+)$')
{
$desc_node = searchID($1, $self->context->dom->documentElement);
my $dnp = $desc_node->getAttribute('data-cpan-html-microformats-nodepath');
my $rnp = $elem->getAttribute('data-cpan-html-microformats-nodepath');
unless ($rnp eq substr $dnp, 0, length $rnp)
{
$elem->addChild($desc_node->clone(1));
}
}
}
# Just does class=credit, class=subject and rel=tag.
$self->_simple_parse($elem);
my @legends;
push @legends, $elem if $elem->getAttribute('class')=~/\b(legend)\b/;
push @legends, searchClass('legend', $elem);
foreach my $l ($elem->getElementsByTagName('legend'))
{
push @legends, $l
unless $l->getAttribute('class')=~/\b(legend)\b/; # avoid duplicates
}
foreach my $legend_node (@legends)
{
my $legend;
if ($legend_node == $image_node)
{
$legend = ms($legend_node->getAttribute('title'), $legend_node)
if $legend_node->hasAttribute('title');
}
else
{
$legend = stringify($legend_node, 'value');
}
push @{ $self->{'DATA'}->{'legend'} }, $legend if defined $legend;
}
}
sub extract_all
{
my ($class, $dom, $context, %options) = @_;
my @rv;
my @elements = searchClass('figure', $dom);
foreach my $f ($dom->getElementsByTagName('figure'))
{
push @elements, $f
unless $f->getAttribute('class')=~/\b(figure)\b/;
}
foreach my $e (@elements)
{
my $object = $class->new($e, $context, %options);
next unless $object;
next if grep { $_->id eq $object->id } @rv; # avoid duplicates
push @rv, $object if ref $object;
}
return @rv;
}
sub format_signature
{
my $vcard = 'http://www.w3.org/2006/vcard/ns#';
my $geo = 'http://www.w3.org/2003/01/geo/wgs84_pos#';
my $foaf = 'http://xmlns.com/foaf/0.1/';
return {
'root' => 'figure',
'classes' => [
['image', '1u#'],
['legend', '+#'],
['credit', 'M*', {embedded=>'hCard'}],
['subject', 'M*', {embedded=>'hCard adr geo hEvent'}],
],
'options' => {
'rel-tag' => 'category',
},
'rdf:type' => ["${foaf}Image"] ,
'rdf:property' => {
'legend' => { literal => ['http://purl.org/dc/terms/description'] },
'category' => { resource => ['http://www.holygoat.co.uk/owl/redwood/0.1/tags/taggedWithTag'] },
},
};
}
sub add_to_model
{
my $self = shift;
my $model = shift;
$self->_simple_rdf($model);
my $i = 0;
foreach my $subject (@{ $self->{'DATA'}->{'subject'} })
{
if ($self->_isa($subject, 'HTML::Microformats::Format::hCard'))
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/depicts'),
$subject->id(1, 'holder'),
));
}
elsif ($self->_isa($subject, 'HTML::Microformats::Format::adr'))
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/depicts'),
$subject->id(1, 'place'),
));
}
elsif ($self->_isa($subject, 'HTML::Microformats::Format::geo'))
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/depicts'),
$subject->id(1, 'location'),
));
}
elsif ($self->_isa($subject, 'HTML::Microformats::Format::hEvent'))
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/depicts'),
$subject->id(1, 'event'),
));
}
else
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/depicts'),
$self->id(1, "subject.${i}"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, "subject.${i}"),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/name'),
$self->_make_literal($subject)));
}
$i++;
}
$i = 0;
foreach my $credit (@{ $self->{'DATA'}->{'credit'} })
{
if ($self->_isa($credit, 'HTML::Microformats::Format::hCard'))
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new('http://purl.org/dc/terms/contributor'),
$credit->id(1, 'holder'),
));
}
else
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new('http://purl.org/dc/terms/contributor'),
$self->id(1, "credit.${i}"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, "credit.${i}"),
RDF::Trine::Node::Resource->new('http://xmlns.com/foaf/0.1/name'),
$self->_make_literal($credit)));
}
$i++;
}
return $self;
}
sub profiles
{
my $class = shift;
return qw(http://purl.org/uF/figure/draft);
}
1;
=head1 MICROFORMAT
HTML::Microformats::Format::figure supports figure as described at
L.
=head1 RDF OUTPUT
Data is returned using Dublin Core and FOAF.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hEvent.pm 0000644 0000764 0000764 00000034050 11775403507 022063 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hEvent - an hCalendar event component
=head1 SYNOPSIS
use Data::Dumper;
use HTML::Microformats::DocumentContext;
use HTML::Microformats::Format::hCalendar;
my $context = HTML::Microformats::DocumentContext->new($dom, $uri);
my @cals = HTML::Microformats::Format::hCalendar->extract_all(
$dom->documentElement, $context);
foreach my $cal (@cals)
{
foreach my $ev ($cal->get_vevent)
{
printf("%s: %s\n", $ev->get_dtstart, $ev->get_summary);
}
}
=head1 DESCRIPTION
HTML::Microformats::Format::hEvent is a helper module for HTML::Microformats::Format::hCalendar.
This class is used to represent event components within calendars. Generally speaking,
you want to use HTML::Microformats::Format::hCalendar instead.
HTML::Microformats::Format::hEvent inherits from HTML::Microformats::Format. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=head2 Additional Method
=over
=item * C<< to_icalendar >>
This method exports the data in iCalendar format. It requires
L to work, and will throw an error at run-time
if it's not available.
=back
=cut
package HTML::Microformats::Format::hEvent;
use base qw(HTML::Microformats::Format HTML::Microformats::Mixin::Parser);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(searchClass searchRel stringify);
use HTML::Microformats::Format::species;
use Scalar::Util qw[blessed];
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hEvent::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hEvent::VERSION = '0.105';
}
sub new
{
my ($class, $element, $context) = @_;
my $cache = $context->cache;
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
};
bless $self, $class;
my $clone = $element->cloneNode(1);
$self->_expand_patterns($clone);
# Embedded species - too tricky for _simple_parse().
my @nested = searchClass(HTML::Microformats::Format::species->format_signature->{'root'}, $clone);
foreach my $h (@nested)
{
if ($h->getAttribute('class') =~ / (^|\s) (attendee) (\s|$) /x)
{
push @{ $self->{'DATA'}->{'x-sighting-of'} }, HTML::Microformats::Format::species->new($h, $context);
}
my $newClass = $h->getAttribute('class');
$newClass =~ s/\b(attendee|x.sighting.of)\b//g;
$h->setAttribute('class', $newClass);
}
$self->_simple_parse($clone);
$self->_parse_related($clone);
$cache->set($context, $element, $class, $self)
if defined $cache;
return $self;
}
sub _parse_related
{
my ($self, $element) = @_;
# Related-to - too tricky for simple_parse()
my @relations = searchClass('related-to', $element);
foreach my $r (@relations)
{
if ($r->tagName !~ /^(a|area|link)$/i)
{
push @{$self->{'DATA'}->{'sibling'}}, stringify($r, 'value');
}
elsif ($r->getAttribute('rel') =~ /vcalendar-parent/i && !defined $self->{'DATA'}->{'parent'})
{
$self->{'DATA'}->{'parent'} = $self->context->uri($r->getAttribute('href'));
}
elsif ($r->getAttribute('rel') =~ /vcalendar-child/i)
{
push @{$self->{'DATA'}->{'child'}}, $self->context->uri($r->getAttribute('href'));
}
else
{
push @{$self->{'DATA'}->{'sibling'}}, $self->context->uri($r->getAttribute('href'));
}
}
# If no parent, then try to find a link with rel="vcalendar-parent" but no
# class="related-to".
unless ($self->{'DATA'}->{'parent'})
{
@relations = searchRel('vcalendar-parent', $element);
my $r = shift @relations;
$self->{'DATA'}->{'parent'} = $self->context->uri($r->getAttribute('href')) if ($r);
}
# Find additional siblings.
@relations = searchRel('vcalendar-sibling', $element);
foreach my $r (@relations)
{
push @{$self->{'DATA'}->{'sibling'}}, $self->context->uri($r->getAttribute('href'))
unless $r->getAttribute('class') =~ /\b(related-to)\b/;
}
# Find additional children.
@relations = searchRel('vcalendar-child', $element);
foreach my $r (@relations)
{
push @{$self->{'DATA'}->{'child'}}, $self->context->uri($r->getAttribute('href'))
unless $r->getAttribute('class') =~ /\b(related-to)\b/;
}
return $self;
}
sub format_signature
{
my $ical = 'http://www.w3.org/2002/12/cal/icaltzd#';
my $icalx = 'http://buzzword.org.uk/rdf/icaltzdx#';
return {
'root' => 'vevent',
'classes' => [
['attach', 'u*'],
['attendee', 'M*', {embedded=>'hCard !person', 'is-in-cal'=>1}],
['categories', '*'],
['category', '*', {'use-key'=>'categories'}],
['class', '?', {'value-title'=>'allow'}],
['comment', '*'],
#['completed', 'd?'],
['contact', 'M*', {embedded=>'hCard !person', 'is-in-cal'=>1}],
['created', 'd?'],
['description', '?'],
['dtstamp', 'd?'],
['dtstart', 'd1'],
['dtend', 'd?', {'datetime-feedthrough' => 'dtstart'}],
#['due', 'd?'],
['duration', 'D?'],
['exdate', 'd*'],
['exrule', 'e*'],
['geo', 'M*', {embedded=>'geo'}],
['last-modified', 'd?'],
['location', 'M*', {embedded=>'hCard adr geo'}],
['organizer', 'M*', {embedded=>'hCard !person', 'is-in-cal'=>1}],
#['percent-complete', '?'],
['priority', '?', {'value-title'=>'allow'}],
['rdate', 'd*'],
['recurrance-id', 'U?'],
['resource', '*', {'use-key'=>'resources'}],
['resources', '*'],
['rrule', 'e*'],
['sequence', 'n?', {'value-title'=>'allow'}],
['status', '?', {'value-title'=>'allow'}],
['summary', '1'],
['transp', '?', {'value-title'=>'allow'}],
['uid', 'U?'],
['url', 'U?'],
['valarm', 'M*', {embedded=>'hAlarm'}],
['x-sighting-of', 'M*', {embedded=>'species'}] #extension
],
'options' => {
'rel-tag' => 'categories',
'rel-enclosure' => 'attach',
'hmeasure' => 'measures'
},
'rdf:type' => ["${ical}Vevent"] ,
'rdf:property' => {
# 'attach' => { 'resource' => ["${ical}attach"] } ,
'attendee' => { 'resource' => ["${ical}attendee"], 'literal' => ["${icalx}attendee-literal"] } ,
'categories' => { 'resource' => ["${icalx}category"], 'literal' => ["${ical}category"] },
'class' => { 'literal' => ["${ical}class"] , 'literal_datatype' => 'string'} ,
'comment' => { 'literal' => ["${ical}comment"] } ,
'contact' => { 'resource' => ["${icalx}contact"], 'literal' => ["${ical}contact"] } ,
'created' => { 'literal' => ["${ical}created"] } ,
'description' => { 'literal' => ["${ical}description"] } ,
'dtend' => { 'literal' => ["${ical}dtend"] } ,
'dtstamp' => { 'literal' => ["${ical}dtstamp"] } ,
'dtstart' => { 'literal' => ["${ical}dtstart"] } ,
'duration' => { 'literal' => ["${ical}duration"] } ,
'exdate' => { 'literal' => ["${ical}exdate"] } ,
'geo' => { 'literal' => ["${icalx}geo"] } ,
'last-modified' => { 'literal' => ["${ical}lastModified"] } ,
'location' => { 'resource' => ["${icalx}location"], 'literal' => ["${ical}location"] } ,
'organizer' => { 'resource' => ["${ical}organizer"], 'literal' => ["${icalx}organizer-literal"] } ,
'priority' => { 'literal' => ["${ical}priority"] } ,
'rdate' => { 'literal' => ["${ical}rdate"] } ,
'recurrance-id' => { 'resource' => ["${ical}recurranceId"] , 'literal' => ["${ical}recurranceId"] , 'literal_datatype' => 'string' } ,
'resources' => { 'literal' => ["${ical}resources"] } ,
'sequence' => { 'literal' => ["${ical}sequence"] , 'literal_datatype' => 'integer' } ,
'status' => { 'literal' => ["${ical}status"] , 'literal_datatype' => 'string' } ,
'summary' => { 'literal' => ["${ical}summary"] } ,
'transp' => { 'literal' => ["${ical}transp"] , 'literal_datatype' => 'string' } ,
'uid' => { 'resource' => ["${ical}uid"] , 'literal' => ["${ical}uid"] , 'literal_datatype' => 'string' } ,
'url' => { 'resource' => ["${ical}url"] } ,
'valarm' => { 'resource' => ["${ical}valarm"] } ,
'x-sighting-of' => { 'resource' => ["${ical}x-sighting-of"] } ,
},
};
}
sub add_to_model
{
my $self = shift;
my $model = shift;
my $ical = 'http://www.w3.org/2002/12/cal/icaltzd#';
$self->_simple_rdf($model);
_add_to_model_geo($self, $model);
_add_to_model_related($self, $model);
foreach my $prop (qw(exrule rrule))
{
foreach my $val ( @{ $self->data->{$prop} } )
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${ical}${prop}"),
RDF::Trine::Node::Blank->new(substr($val->{'_id'},2)),
));
$val->add_to_model($model);
}
}
foreach my $val ( @{ $self->data->{attach} } )
{
if (blessed($val) and $val->can('add_to_model'))
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${ical}attach"),
RDF::Trine::Node::Resource->new($val->data->{href}),
));
$val->add_to_model($model);
}
else
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${ical}attach"),
RDF::Trine::Node::Resource->new($val),
));
}
}
return $self;
}
sub _add_to_model_geo
{
my ($self, $model) = @_;
my $ical = 'http://www.w3.org/2002/12/cal/icaltzd#';
# GEO is an rdf:List of floating point numbers :-(
foreach my $geo (@{ $self->data->{'geo'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${ical}geo"),
$geo->id(1, 'ical-list.0'),
));
$model->add_statement(RDF::Trine::Statement->new(
$geo->id(1, 'ical-list.0'),
RDF::Trine::Node::Resource->new("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
RDF::Trine::Node::Resource->new("http://www.w3.org/1999/02/22-rdf-syntax-ns#List"),
));
$model->add_statement(RDF::Trine::Statement->new(
$geo->id(1, 'ical-list.0'),
RDF::Trine::Node::Resource->new("http://www.w3.org/1999/02/22-rdf-syntax-ns#first"),
RDF::Trine::Node::Literal->new($geo->data->{'latitude'}, undef, 'http://www.w3.org/2001/XMLSchema#float'),
));
$model->add_statement(RDF::Trine::Statement->new(
$geo->id(1, 'ical-list.0'),
RDF::Trine::Node::Resource->new("http://www.w3.org/1999/02/22-rdf-syntax-ns#next"),
$geo->id(1, 'ical-list.1'),
));
$model->add_statement(RDF::Trine::Statement->new(
$geo->id(1, 'ical-list.1'),
RDF::Trine::Node::Resource->new("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
RDF::Trine::Node::Resource->new("http://www.w3.org/1999/02/22-rdf-syntax-ns#List"),
));
$model->add_statement(RDF::Trine::Statement->new(
$geo->id(1, 'ical-list.1'),
RDF::Trine::Node::Resource->new("http://www.w3.org/1999/02/22-rdf-syntax-ns#first"),
RDF::Trine::Node::Literal->new($geo->data->{'longitude'}, undef, 'http://www.w3.org/2001/XMLSchema#float'),
));
$model->add_statement(RDF::Trine::Statement->new(
$geo->id(1, 'ical-list.1'),
RDF::Trine::Node::Resource->new("http://www.w3.org/1999/02/22-rdf-syntax-ns#next"),
RDF::Trine::Node::Resource->new("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil"),
));
}
}
sub _add_to_model_related
{
my ($self, $model) = @_;
my $ical = 'http://www.w3.org/2002/12/cal/icaltzd#';
foreach my $relationship (qw(parent child sibling other))
{
my @uids;
if (ref $self->data->{$relationship} eq 'ARRAY')
{
@uids = @{$self->data->{$relationship}};
}
else
{
push @uids, $self->data->{$relationship};
}
for (my $i=0; defined $uids[$i]; $i++)
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${ical}relatedTo"),
$self->id(1, "relationship.${relationship}.${i}"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, "relationship.${relationship}.${i}"),
RDF::Trine::Node::Resource->new("${ical}reltype"),
RDF::Trine::Node::Literal->new($relationship, undef, 'http://www.w3.org/2001/XMLSchema#string'),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, "relationship.${relationship}.${i}"),
RDF::Trine::Node::Resource->new("http://buzzword.org.uk/rdf/icaltzdx#related-component-uid"),
RDF::Trine::Node::Literal->new($uids[$i]),
));
}
my @objects;
if (ref $self->{'related'}->{$relationship} eq 'ARRAY')
{
@objects = @{$self->{'related'}->{$relationship}};
}
else
{
push @objects, $self->{'related'}->{$relationship};
}
for (my $i=0; defined $objects[$i]; $i++)
{
next unless ref $objects[$i];
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("http://buzzword.org.uk/rdf/icaltzdx#${relationship}-component"),
$objects[$i]->id(1),
));
}
}
}
sub profiles
{
return HTML::Microformats::Format::hCalendar::profiles(@_);
}
sub to_icalendar
{
my ($self) = @_;
die "Need RDF::iCalendar to export iCalendar data.\n"
unless $HTML::Microformats::Format::hCalendar::HAS_ICAL_EXPORT;
my $exporter = RDF::iCalendar::Exporter->new;
return $exporter->export_component($self->model, $self->id(1))->to_string;
}
1;
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/RelEnclosure.pm 0000644 0000764 0000764 00000007754 11775403507 023247 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::RelEnclosure - the rel-enclosure microformat
=head1 SYNOPSIS
my @enclosures = HTML::Microformats::Format::RelEnclosure->extract_all(
$doc->documentElement, $context);
foreach my $e (@enclosures)
{
my $type = $l->get_type || 'unknown';
printf("%s (%s)\n"), $l->get_href, $type);
}
=head1 DESCRIPTION
HTML::Microformats::Format::RelEnclosure inherits from HTML::Microformats::Format_Rel. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=head2 Additional Method
=over 4
=item C<< $relenc->get_type() >>
Returns the media type (Content-Type) of the resource being linked to. This
is taken from the HTML 'type' attribute, so if that's not present, returns undef.
=back
=cut
package HTML::Microformats::Format::RelEnclosure;
use base qw(HTML::Microformats::Format_Rel);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Datatype::String qw(isms);
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::RelEnclosure::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::RelEnclosure::VERSION = '0.105';
}
sub new
{
my $class = shift;
my $self = $class->SUPER::new(@_);
$self->{'DATA'}->{'type'} = $self->{'element'}->getAttribute('type')
if $self->{'element'}->hasAttribute('type');
return $self;
}
sub format_signature
{
return {
'rel' => 'enclosure' ,
'classes' => [
['type', '?#'] ,
['href', '1#'] ,
['label', '1#'] ,
['title', '1#'] ,
] ,
'rdf:type' => [] ,
'rdf:property' => {} ,
}
}
sub profiles
{
return qw(http://purl.org/uF/rel-enclosure/0.1/);
}
sub add_to_model
{
my $self = shift;
my $model = shift;
my $enc = 'http://purl.oclc.org/net/rss_2.0/enc#';
$model->add_statement(RDF::Trine::Statement->new(
RDF::Trine::Node::Resource->new($self->context->document_uri),
RDF::Trine::Node::Resource->new("${enc}enclosure"),
RDF::Trine::Node::Resource->new($self->data->{'href'}),
));
$model->add_statement(RDF::Trine::Statement->new(
RDF::Trine::Node::Resource->new($self->data->{'href'}),
RDF::Trine::Node::Resource->new("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
RDF::Trine::Node::Resource->new("${enc}Enclosure"),
));
$model->add_statement(RDF::Trine::Statement->new(
RDF::Trine::Node::Resource->new($self->data->{'href'}),
RDF::Trine::Node::Resource->new("${enc}type"),
RDF::Trine::Node::Literal->new(''.$self->data->{'type'}),
))
if defined $self->data->{'type'};
$model->add_statement(RDF::Trine::Statement->new(
RDF::Trine::Node::Resource->new($self->data->{'href'}),
RDF::Trine::Node::Resource->new("http://www.w3.org/2000/01/rdf-schema#label"),
$self->_make_literal($self->data->{'label'}),
));
$model->add_statement(RDF::Trine::Statement->new(
RDF::Trine::Node::Resource->new($self->data->{'href'}),
RDF::Trine::Node::Resource->new("http://purl.org/dc/terms/title"),
$self->_make_literal($self->data->{'title'}),
));
return $self;
}
1;
=head1 MICROFORMAT
HTML::Microformats::Format::RelEnclosure supports rel-enclosure as described at
L.
The "title" attribute on the link, and the linked text are taken to be significant.
=head1 RDF OUTPUT
Data is returned using the RSS Enclosures vocabulary
(L) and occasional other terms.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/geo.pm 0000644 0000764 0000764 00000021441 11775403507 021404 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::geo - the geo microformat
=head1 SYNOPSIS
use Data::Dumper;
use HTML::Microformats::DocumentContext;
use HTML::Microformats::Format::geo;
my $context = HTML::Microformats::DocumentContext->new($dom, $uri);
my @geos = HTML::Microformats::Format::geo->extract_all(
$dom->documentElement, $context);
foreach my $geo (@geos)
{
printf("%s;%s\n", $geo->get_latitude, $geo->get_longitude);
}
=head1 DESCRIPTION
HTML::Microformats::Format::geo inherits from HTML::Microformats::Format. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=head2 Additional Method
=over
=item * C<< to_kml >>
This method exports the geo object as KML. It requires L to work,
and will throw an error at run-time if it's not available.
=back
=cut
package HTML::Microformats::Format::geo;
use base qw(HTML::Microformats::Format HTML::Microformats::Mixin::Parser);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(stringify);
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::geo::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::geo::VERSION = '0.105';
}
our $HAS_KML_EXPORT;
BEGIN
{
local $@ = undef;
eval 'use RDF::KML::Exporter;';
$HAS_KML_EXPORT = 1
if RDF::KML::Exporter->can('new');
}
sub new
{
my ($class, $element, $context) = @_;
my $cache = $context->cache;
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
};
bless $self, $class;
my $clone = $element->cloneNode(1);
$self->_expand_patterns($clone);
$self->_simple_parse($clone);
if (!defined($self->{'DATA'}->{'longitude'}) || !defined($self->{'DATA'}->{'latitude'}))
{
my $str = stringify($clone, {
'excerpt-class' => 'value',
'value-title' => 'allow',
'abbr-pattern' => 1,
});
if ($str =~ / ^\s* \+?(\-?[0-9\.]+) \s* [\,\;] \s* \+?(\-?[0-9\.]+) \s*$ /x)
{
$self->{'DATA'}->{'latitude'} = $1;
$self->{'DATA'}->{'longitude'} = $2;
}
# Last ditch attempt!!
elsif ($clone->toString =~ / \s* \+?(\-?[0-9\.]+) \s* [\,\;] \s* \+?(\-?[0-9\.]+) \s* /x)
{
$self->{'DATA'}->{'latitude'} = $1;
$self->{'DATA'}->{'longitude'} = $2;
}
}
if (defined $self->data->{'body'}
or (defined $self->data->{'reference-frame'} && $self->data->{'reference-frame'}!~ /wgs[-\s]?84/i))
{
$self->{'id.location'} = $context->make_bnode;
}
elsif (defined $self->data->{'altitude'}
and (!ref $self->data->{'altitude'} || $self->data->{'altitude'}->can('to_string')))
{
$self->{'id.location'} = sprintf('geo:%s,%s,%s',
$self->data->{'latitude'},
$self->data->{'longitude'},
$self->data->{'altitude'},
);
}
else
{
$self->{'id.location'} = sprintf('geo:%s,%s',
$self->data->{'latitude'},
$self->data->{'longitude'},
);
}
$cache->set($context, $element, $class, $self)
if defined $cache;
return $self;
}
sub format_signature
{
my $vcard = 'http://www.w3.org/2006/vcard/ns#';
my $vx = 'http://buzzword.org.uk/rdf/vcardx#';
return {
'root' => 'geo',
'classes' => [
['longitude', 'n?', {'value-title'=>'allow'}],
['latitude', 'n?', {'value-title'=>'allow'}],
['body', '?'], # extension
['reference-frame', '?'], # extension
['altitude', 'M?', {embedded=>'hMeasure'}] # extension
],
'options' => {
},
'rdf:type' => ["${vcard}Location"] ,
'rdf:property' => {
'latitude' => { 'literal' => ["${vcard}latitude"] } ,
'longitude' => { 'literal' => ["${vcard}longitude"] } ,
'altitude' => { 'literal' => ["${vx}altitude"] } ,
},
};
}
sub add_to_model
{
my $self = shift;
my $model = shift;
if (defined $self->data->{'body'}
or (defined $self->data->{'reference-frame'} && $self->data->{'reference-frame'}!~ /wgs[-\s]?84/i))
{
my $rdf = {
$self->id(0,'location') =>
{
'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' =>
[{ 'value'=>'http://buzzword.org.uk/rdf/ungeo#Point' , 'type'=>'uri' }]
}
};
foreach my $p (qw(altitude longitude latitude))
{
if (defined $self->data->{$p})
{
$rdf->{$self->id(0,'location')}->{'http://buzzword.org.uk/rdf/ungeo#'.$p} =
[{ 'value'=>$self->data->{$p}, 'type'=>'literal' }];
}
}
$rdf->{$self->id(0,'location')}->{'http://buzzword.org.uk/rdf/ungeo#system'} =
[{ 'value'=>$self->id(0,'system'), 'type'=>'bnode' }];
$rdf->{$self->id(0,'system')}->{'http://www.w3.org/1999/02/22-rdf-syntax-ns#type'} =
[{ 'value'=>'http://buzzword.org.uk/rdf/ungeo#ReferenceSystem', 'type'=>'uri' }];
$rdf->{$self->id(0,'system')}->{'http://www.w3.org/2000/01/rdf-schema#label'} =
[{ 'value'=>$self->data->{'reference-frame'}, 'type'=>'literal' }]
if defined $self->data->{'reference-frame'};
$rdf->{$self->id(0,'system')}->{'http://buzzword.org.uk/rdf/ungeo#body'} =
[{ 'value'=>$self->data->{'body'}, 'type'=>'literal' }]
if defined $self->data->{'body'};
$model->add_hashref($rdf);
}
else
{
$self->_simple_rdf($model);
my $geo = 'http://www.w3.org/2003/01/geo/wgs84_pos#';
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'location'),
RDF::Trine::Node::Resource->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'),
RDF::Trine::Node::Resource->new("${geo}Point"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'location'),
RDF::Trine::Node::Resource->new("${geo}lat"),
$self->_make_literal($self->data->{'latitude'}, 'decimal'),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'location'),
RDF::Trine::Node::Resource->new("${geo}long"),
$self->_make_literal($self->data->{'longitude'}, 'decimal'),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'location'),
RDF::Trine::Node::Resource->new("${geo}alt"),
$self->_make_literal($self->data->{'altitude'}, 'decimal'),
))
if (defined $self->data->{'altitude'}
and (!ref $self->data->{'altitude'} || $self->data->{'altitude'}->can('to_string')));
}
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new('http://buzzword.org.uk/rdf/vcardx#represents-location'),
$self->id(1, 'location'),
));
return $self;
}
sub to_kml
{
my ($self) = @_;
die "Need RDF::KML::Exporter to export KML.\n" unless $HAS_KML_EXPORT;
my $exporter = RDF::KML::Exporter->new;
return $exporter->export_kml($self->model)->render;
}
sub profiles
{
my $class = shift;
return qw(http://purl.org/uF/geo/0.9/
http://microformats.org/profile/hcard
http://ufs.cc/x/hcard
http://microformats.org/profile/specs
http://ufs.cc/x/specs
http://www.w3.org/2006/03/hcard
http://purl.org/uF/hCard/1.0/
http://purl.org/uF/2008/03/ );
}
1;
=head1 MICROFORMAT
HTML::Microformats::Format::geo supports geo as described at
L, with the following additions:
=over 4
=item * 'altitude' property
You may provide an altitude as either a number (taken to be metres above sea level)
or an embedded hMeasure. e.g.:
lat: 12.34,
long: 56.78,
alt: 90 metres.
lat: 12.34,
long: 56.78,
alt:
90
m
.
=item * 'body' and 'reference-frame'
The geo microformat is normally only defined for WGS84 co-ordinates on
Earth. Using 'body' and 'reference-frame' properties (each of which take
string values), you may give co-ordinates on other planets, asteroids,
moons, etc; or on Earth but using a non-WGS84 system.
=back
=head1 RDF OUTPUT
Data is returned using the W3C's vCard vocabulary
(L) and the W3C's
WGS84 vocabulary (L).
For non-WGS84 co-ordinates, UNGEO (L)
is used instead.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hEntry.pm 0000644 0000764 0000764 00000047103 11775403507 022106 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hEntry - an hAtom entry
=head1 SYNOPSIS
use Data::Dumper;
use HTML::Microformats::DocumentContext;
use HTML::Microformats::Format::hAtom;
my $context = HTML::Microformats::DocumentContext->new($dom, $uri);
my @feeds = HTML::Microformats::Format::hAtom->extract_all(
$dom->documentElement, $context);
foreach my $feed (@feeds)
{
foreach my $entry ($feed->get_entry)
{
print $entry->get_link . "\n";
}
}
=head1 DESCRIPTION
HTML::Microformats::Format::hEntry is a helper module for HTML::Microformats::Format::hAtom.
This class is used to represent entries within feeds. Generally speaking, you want to
use HTML::Microformats::Format::hAtom instead.
HTML::Microformats::Format::hEntry inherits from HTML::Microformats::Format. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=head2 Additional Method
=over
=item * C<< to_atom >>
This method exports the data as an XML file containing an Atom .
It requires L to work, and will throw an error at
run-time if it's not available.
=item * C<< to_icalendar >>
This method exports the data in iCalendar format (as a VJOURNAL). It
requires L to work, and will throw an error at run-time
if it's not available.
=back
=cut
package HTML::Microformats::Format::hEntry;
use base qw(HTML::Microformats::Format HTML::Microformats::Mixin::Parser);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(searchClass searchAncestorClass stringify);
use HTML::Microformats::Datatype::String qw(isms);
use HTML::Microformats::Format::hCard;
use HTML::Microformats::Format::hEvent;
use HTML::Microformats::Format::hNews;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hEntry::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hEntry::VERSION = '0.105';
}
our $HAS_ATOM_EXPORT;
BEGIN
{
local $@ = undef;
eval 'use XML::Atom::FromOWL;';
$HAS_ATOM_EXPORT = 1
if XML::Atom::FromOWL->can('new');
}
sub new
{
my ($class, $element, $context) = @_;
my $cache = $context->cache;
# Use hNews if more appropriate.
if ($element->getAttribute('class') =~ /\b(hnews)\b/)
{
return HTML::Microformats::Format::hNews->new($element, $context)
if $context->has_profile( HTML::Microformats::Format::hNews->profiles );
}
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
};
bless $self, $class;
$self->_hentry_parse;
$cache->set($context, $element, $class, $self)
if defined $cache;
return $self;
}
sub _hentry_parse
{
my ($self) = @_;
my $clone = $self->{'element'}->cloneNode(1);
$self->_expand_patterns($clone);
# Because of element handling, process 'author' outside of
# _simple_parse.
$self->_author_parse($clone);
# Parse other properties.
$self->_simple_parse($clone);
# Fallback for title - use the first element
# or (if there's no hfeed) the page title.
$self->_title_fallback($clone);
# Fallback for permalink - use id attribute or page URI.
$self->_link_fallback($self->{'element'});
# Handle replies hAtom feed
$self->_reply_handler;
if ($self->context->has_profile( HTML::Microformats::Format::VoteLinks->profiles ))
{
my @vls = HTML::Microformats::Format::VoteLinks->extract_all($clone, $self->context);
foreach my $votelink (@vls)
{
next if defined $votelink->data->{'voter'};
my $ancestor = searchAncestorClass('hentry', $votelink->element)
|| searchAncestorClass('hnews', $votelink->element)
|| searchAncestorClass('hslice', $votelink->element);
next unless defined $ancestor;
next unless $ancestor->getAttribute('data-cpan-html-microformats-nodepath')
eq $self->element->getAttribute('data-cpan-html-microformats-nodepath');
$votelink->data->{'voter'} = $self->data->{'author'};
}
}
return $clone;
}
sub _author_parse
{
my ($self, $clone) = @_;
my @vcard_elements = searchClass('vcard', $clone);
foreach my $ve (@vcard_elements)
{
next unless $ve->getAttribute('class') =~ /\b(author)\b/;
next unless $clone->getAttribute('data-cpan-html-microformats-nodepath') eq searchAncestorClass('hentry', $ve)->getAttribute('data-cpan-html-microformats-nodepath');
push @{ $self->{'DATA'}->{'author'} }, HTML::Microformats::Format::hCard->new($ve, $self->context);
}
unless (@{ $self->{'DATA'}->{'author'} })
{
foreach my $ve (@vcard_elements)
{
next unless $ve->tagName eq 'address';
next unless $clone->getAttribute('data-cpan-html-microformats-nodepath') eq searchAncestorClass('hentry', $ve)->getAttribute('data-cpan-html-microformats-nodepath');
push @{ $self->{'DATA'}->{'author'} }, HTML::Microformats::Format::hCard->new($ve, $self->context);
}
}
unless (@{ $self->{'DATA'}->{'author'} })
{
##TODO: Should really only use the nearest-in-parent. post-0.001
my @address_elements = $self->context->document->getElementsByTagName('address');
foreach my $address (@address_elements)
{
next unless $address->getAttribute('class') =~ /\b(author)\b/;
next unless $address->getAttribute('class') =~ /\b(vcard)\b/;
push @{ $self->{'DATA'}->{'author'} }, HTML::Microformats::Format::hCard->new($address, $self->context);
}
}
}
sub _title_fallback
{
my ($self, $element) = @_;
unless (defined $self->data->{'title'})
{
ELEM: foreach my $tag ($element->getElementsByTagName('*'))
{
if ($tag->tagName =~ /^h[1-9]?$/i)
{
$self->data->{'title'} = stringify($tag, 'value');
last ELEM;
}
}
}
unless (defined $self->data->{'title'}
or searchAncestorClass('hfeed', $element))
{
TITLE: foreach my $tag ($self->context->document->getElementsByTagName('title'))
{
my $str = stringify($tag, 'value');
$self->data->{'title'} = $str;
last TITLE if length $str;
}
}
}
sub _link_fallback
{
my ($self, $element) = @_;
unless (defined $self->data->{'link'})
{
if ($element->hasAttribute('id'))
{
$self->data->{'link'} = $self->context->uri('#'.$element->getAttribute('id'));
}
else
{
$self->data->{'link'} = $self->context->document_uri;
}
}
}
sub _reply_handler
{
my ($self) = @_;
FEED: foreach my $feed (@{$self->data->{'replies'}})
{
ENTRY: foreach my $entry (@{$feed->data->{'entry'}})
{
push @{ $entry->data->{'in-reply-to'} }, $self->data->{'link'},
if defined $self->data->{'link'}
&& !defined $entry->data->{'in-reply-to'};
}
}
}
sub format_signature
{
my $awol = 'http://bblfish.net/work/atom-owl/2006-06-06/#';
my $ax = 'http://buzzword.org.uk/rdf/atomix#';
my $iana = 'http://www.iana.org/assignments/relation/';
my $rdfs = 'http://www.w3.org/2000/01/rdf-schema#';
return {
'root' => ['hentry','hslice','hnews'],
'classes' => [
['bookmark', 'ru?', {'use-key'=>'link'}],
['entry-content', 'H&', {'use-key'=>'content'}],
['entry-summary', 'H&', {'use-key'=>'summary'}],
['entry-title', '?', {'use-key'=>'title'}],
['in-reply-to', 'Ru*'], #extension
['published', 'd?'],
['replies', 'm*', {'embedded'=>'hAtom'}], #extension
['updated', 'd*', {'datetime-feedthrough' => 'published'}],
['author', '#*'],
],
'options' => {
'rel-tag' => 'category',
'rel-enclosure' => 'enclosure', #extension
# 'rel-license' => 'license', #extension
},
'rdf:type' => ["${awol}Entry"] ,
'rdf:property' => {
'link' => { resource => ["${iana}self"] } ,
'title' => { literal => ["${rdfs}label"] } ,
'in-reply-to' => { resource => ["${ax}in-reply-to"] } ,
'published' => { literal => ["${awol}published"] } ,
'updated' => { literal => ["${awol}updated"] } ,
'category' => { resource => ["${awol}category"] } ,
# 'enclosure' => { resource => ["${iana}enclosure"] } ,
},
};
}
sub add_to_model
{
my $self = shift;
my $model = shift;
$self->_simple_rdf($model);
my $awol = 'http://bblfish.net/work/atom-owl/2006-06-06/#';
my $ax = 'http://buzzword.org.uk/rdf/atomix#';
my $iana = 'http://www.iana.org/assignments/relation/';
my $rdfs = 'http://www.w3.org/2000/01/rdf-schema#';
my $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
foreach my $field (qw(title summary))
{
next unless length $self->data->{"html_$field"};
$self->{'id.'.$field} = $self->context->make_bnode
unless defined $self->{'id.'.$field};
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${awol}${field}"),
$self->id(1, $field),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field),
RDF::Trine::Node::Resource->new("${rdf}type"),
RDF::Trine::Node::Resource->new("${awol}TextContent"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field),
RDF::Trine::Node::Resource->new("${awol}xhtml"),
RDF::Trine::Node::Literal->new($self->data->{"html_$field"}, undef, "${rdf}XMLLiteral"),
));
if (isms($self->data->{$field}))
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field),
RDF::Trine::Node::Resource->new("${awol}text"),
RDF::Trine::Node::Literal->new($self->data->{$field}->to_string, $self->data->{$field}->lang),
))
}
elsif (defined $self->data->{$field})
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field),
RDF::Trine::Node::Resource->new("${awol}text"),
RDF::Trine::Node::Literal->new($self->data->{$field}),
))
}
}
foreach my $field (qw(content))
{
next unless length $self->data->{"html_$field"};
$self->{'id.'.$field} = $self->context->make_bnode
unless defined $self->{'id.'.$field};
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${awol}${field}"),
$self->id(1, $field),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field),
RDF::Trine::Node::Resource->new("${rdf}type"),
RDF::Trine::Node::Resource->new("${awol}Content"),
));
if (defined $self->data->{"html_$field"})
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field),
RDF::Trine::Node::Resource->new("${awol}type"),
RDF::Trine::Node::Literal->new("application/xhtml+xml"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field),
RDF::Trine::Node::Resource->new("${awol}body"),
RDF::Trine::Node::Literal->new($self->data->{"html_$field"}, undef, "${rdf}XMLLiteral"),
));
}
else
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field),
RDF::Trine::Node::Resource->new("${awol}type"),
RDF::Trine::Node::Literal->new("text/plain"),
));
if (isms($self->data->{$field}))
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field),
RDF::Trine::Node::Resource->new("${awol}body"),
RDF::Trine::Node::Literal->new($self->data->{$field}->to_string, $self->data->{$field}->lang),
));
}
elsif (defined $self->data->{$field})
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field),
RDF::Trine::Node::Resource->new("${awol}body"),
RDF::Trine::Node::Literal->new($self->data->{$field}),
));
}
}
}
foreach my $author (@{ $self->data->{'author'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${awol}author"),
$author->id(1, 'holder'),
));
$model->add_statement(RDF::Trine::Statement->new(
$author->id(1, 'holder'),
RDF::Trine::Node::Resource->new("${rdf}type"),
RDF::Trine::Node::Resource->new("${awol}Person"),
));
$model->add_statement(RDF::Trine::Statement->new(
$author->id(1, 'holder'),
RDF::Trine::Node::Resource->new("${awol}name"),
$self->_make_literal($author->data->{fn})
)) if $author->data->{fn};
foreach my $u (@{ $author->data->{'url'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$author->id(1, 'holder'),
RDF::Trine::Node::Resource->new("${awol}uri"),
RDF::Trine::Node::Resource->new($u),
));
}
foreach my $e (@{ $author->data->{'email'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new("${awol}email"),
RDF::Trine::Node::Resource->new($e->get_value),
))
if $e->get_value =~ /^(mailto):\S+$/i;
}
$author->add_to_model($model);
}
foreach my $field (qw(link))
{
$self->{'id.'.$field} = $self->context->make_bnode
unless defined $self->{'id.'.$field};
$self->{'id.'.$field.'-dest'} = $self->context->make_bnode
unless defined $self->{'id.'.$field.'-dest'};
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${awol}link"),
$self->id(1, $field),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field),
RDF::Trine::Node::Resource->new("${rdf}type"),
RDF::Trine::Node::Resource->new("${awol}Link"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field),
RDF::Trine::Node::Resource->new("${awol}rel"),
RDF::Trine::Node::Resource->new($iana . ($field eq 'link' ? 'self' : $field)),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field),
RDF::Trine::Node::Resource->new("${awol}to"),
$self->id(1, "${field}-dest"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, "${field}-dest"),
RDF::Trine::Node::Resource->new("${rdf}type"),
RDF::Trine::Node::Resource->new("${awol}Content"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, "${field}-dest"),
RDF::Trine::Node::Resource->new("${awol}src"),
RDF::Trine::Node::Resource->new($self->data->{$field}),
));
}
foreach my $field (qw(enclosure))
{
for (my $i=0; defined $self->data->{$field}->[$i]; $i++)
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${iana}enclosure"),
RDF::Trine::Node::Resource->new($self->data->{$field}->[$i]->data->{href}),
));
$self->{'id.'.$field.'.'.$i} = $self->context->make_bnode
unless defined $self->{'id.'.$field.'.'.$i};
$self->{'id.'.$field.'-dest.'.$i} = $self->context->make_bnode
unless defined $self->{'id.'.$field.'-dest.'.$i};
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${awol}link"),
$self->id(1, $field.'.'.$i),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field.'.'.$i),
RDF::Trine::Node::Resource->new("${rdf}type"),
RDF::Trine::Node::Resource->new("${awol}Link"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field.'.'.$i),
RDF::Trine::Node::Resource->new("${awol}rel"),
RDF::Trine::Node::Resource->new($iana . ($field eq 'link' ? 'self' : $field)),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, $field.'.'.$i),
RDF::Trine::Node::Resource->new("${awol}to"),
$self->id(1, "${field}-dest.${i}"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, "${field}-dest.${i}"),
RDF::Trine::Node::Resource->new("${rdf}type"),
RDF::Trine::Node::Resource->new("${awol}Content"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, "${field}-dest.${i}"),
RDF::Trine::Node::Resource->new("${awol}src"),
RDF::Trine::Node::Resource->new($self->data->{$field}->[$i]),
));
}
}
return $self;
}
sub get_uid
{
my $self = shift;
return defined $self->data->{link} ? $self->data->{link} : undef;
}
sub add_to_model_ical
{
my $self = shift;
my $model = shift;
my $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
my $rdfs = 'http://www.w3.org/2000/01/rdf-schema#';
my $ical = 'http://www.w3.org/2002/12/cal/icaltzd#';
my $icalx= 'http://buzzword.org.uk/rdf/icaltzdx#';
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${rdf}type"),
RDF::Trine::Node::Resource->new("${ical}Vjournal"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${ical}summary"),
$self->_make_literal($self->data->{title}),
))
if $self->data->{title};
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${ical}comment"),
$self->_make_literal($self->data->{summary}),
))
if $self->data->{summary};
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${ical}description"),
$self->_make_literal($self->data->{content}),
))
if $self->data->{content};
foreach my $author (@{ $self->data->{'author'} })
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${icalx}organizer"),
$author->id(1),
));
$author->add_to_model($model);
}
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${ical}uid"),
$self->_make_literal($self->data->{link} => 'anyURI'),
))
if $self->data->{link};
foreach my $field (qw(enclosure))
{
for (my $i=0; defined $self->data->{$field}->[$i]; $i++)
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${ical}attach"),
RDF::Trine::Node::Resource->new($self->data->{$field}->[$i]->data->{href}),
));
}
}
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${ical}created"),
$self->_make_literal($self->data->{published}),
))
if $self->data->{published};
if ($self->data->{updated})
{
foreach my $u (@{ $self->data->{updated} })
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${ical}dtstamp"),
$self->_make_literal($u),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${ical}last-modified"),
$self->_make_literal($u),
));
}
}
# todo - CATEGORIES
HTML::Microformats::Format::hEvent::_add_to_model_related($self, $model);
return $self;
}
sub to_atom
{
my ($self) = @_;
die "Need XML::Atom::FromOWL to export Atom.\n" unless $HAS_ATOM_EXPORT;
my $exporter = XML::Atom::FromOWL->new;
return $exporter->export_entry($self->model, $self->id(1))->as_xml;
}
sub to_icalendar
{
my ($self) = @_;
die "Need RDF::iCalendar to export iCalendar data.\n"
unless $HTML::Microformats::Format::hCalendar::HAS_ICAL_EXPORT;
my $model = $self->model;
$self->add_to_model_ical($model);
my $exporter = RDF::iCalendar::Exporter->new;
return $exporter->export_component($model, $self->id(1))->to_string;
}
sub profiles
{
my @p = qw(http://microformats.org/profile/hatom
http://ufs.cc/x/hatom
http://purl.org/uF/hAtom/0.1/);
push @p, HTML::Microformats::Format::hNews->profiles;
return @p;
}
1;
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L,
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hReview/ 0000755 0000764 0000764 00000000000 11775404022 021674 5 ustar tai tai HTML-Microformats-0.105/lib/HTML/Microformats/Format/hReview/rating.pm 0000644 0000764 0000764 00000007732 11775403507 023536 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hReview::rating - helper for hReviews; handles the rating property
=head1 DESCRIPTION
Technically, this inherits from HTML::Microformats::Format, so can be used in the
same way as any of the other microformat module, though I don't know why you'd
want to.
It does not implement the include pattern, instead relying on the hReview implementation
to do so.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
package HTML::Microformats::Format::hReview::rating;
use base qw(HTML::Microformats::Format HTML::Microformats::Mixin::Parser);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(stringify searchClass);
use XML::LibXML qw(:libxml);
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hReview::rating::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hReview::rating::VERSION = '0.105';
}
sub new
{
my ($class, $element, $context, %options) = @_;
my $cache = $context->cache;
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
'id.holder' => $context->make_bnode ,
};
bless $self, $class;
# Find value - that's the easy part.
$self->{'DATA'}->{'value'} = stringify($element, 'value');
# If element is a descendent of something with rel=tag,
# then ascend the tree to find that.
my $parent = $element;
while (defined $parent && ref $parent && $parent->nodeType == XML_ELEMENT_NODE)
{
last if $parent->getAttribute('rel') =~ /\b(tag)\b/i;
$parent = $parent->parentNode;
}
$parent = undef
unless $parent->nodeType == XML_ELEMENT_NODE
&& $parent->getAttribute('rel') =~ /\b(tag)\b/i;
# Search for class=best|worst within $element,
# or in higher rel=tag element.
my $root_node = $parent || $element;
foreach my $limit (qw(best worst))
{
my @elems = searchClass($limit, $root_node);
$self->{'DATA'}->{$limit} = stringify($elems[0], {'abbr-pattern'=>1});
}
# Default them to 0.0 and 5.0.
$self->{'DATA'}->{'worst'} = '0.0'
unless defined $self->{'DATA'}->{'worst'};
$self->{'DATA'}->{'best'} = '5.0'
unless defined $self->{'DATA'}->{'best'};
if ($parent) # only defined if $element has a rel=tag ancestor
{
$self->{'DATA'}->{'tag'} =
[ HTML::Microformats::Format::RelTag->new($parent, $context) ];
}
else
{
$self->{'DATA'}->{'tag'} =
[ HTML::Microformats::Format::RelTag->extract_all($element, $context) ];
}
$cache->set($context, $element, $class, $self)
if defined $cache;
return $self;
}
sub format_signature
{
my $self = shift;
my $rev = 'http://www.purl.org/stuff/rev#';
my $hreview = 'http://ontologi.es/hreview#';
my $rv = {
'root' => 'rating',
'classes' => [
['value', 'n?v#'],
['best', 'n?v#'],
['worst', 'n?v#'],
],
'options' => {
'rel-tag' => 'tag',
},
'rdf:type' => ["${hreview}Rating"] ,
'rdf:property' => {
'value' => { 'literal' => ["http://www.w3.org/1999/02/22-rdf-syntax-ns#value"] , 'literal_datatype' => 'decimal' },
'best' => { 'literal' => ["${hreview}best"] , 'literal_datatype' => 'decimal' },
'worst' => { 'literal' => ["${hreview}worst"] , 'literal_datatype' => 'decimal' },
'tag' => { 'resource' => ["${hreview}rated-on"] },
},
};
return $rv;
}
1;
HTML-Microformats-0.105/lib/HTML/Microformats/Format/XFN.pm 0000644 0000764 0000764 00000033762 11775403507 021276 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::XFN - the XFN microformat
=head1 SYNOPSIS
use Data::Dumper;
use HTML::Microformats::DocumentContext;
use HTML::Microformats::Format::XFN;
my $context = HTML::Microformats::DocumentContext->new($dom, $uri);
my @links = HTML::Microformats::Format::XFN->extract_all(
$dom->documentElement, $context);
foreach my $link (@links)
{
printf("<%s> %s\n", $link->get_href, join(" ", $link->get_rel));
}
=head1 DESCRIPTION
HTML::Microformats::Format::XFN inherits from HTML::Microformats::Format. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=cut
package HTML::Microformats::Format::XFN;
use base qw(HTML::Microformats::Format);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(stringify searchAncestorClass);
use HTML::Microformats::Format::hCard;
use RDF::Trine;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::XFN::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::XFN::VERSION = '0.105';
}
sub new
{
my ($class, $element, $context) = @_;
my $cache = $context->cache;
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = bless {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
}, $class;
# Extract XFN-related @rel values.
$self->_extract_xfn_relationships;
# If none, then just return undef.
return undef
unless @{ $self->{'DATA'}->{'rel'} }
|| @{ $self->{'DATA'}->{'rev'} };
$self->{'DATA'}->{'href'} = $context->uri( $element->getAttribute('href') );
$self->{'DATA'}->{'label'} = stringify($element, 'value');
$self->{'DATA'}->{'title'} = $element->hasAttribute('title')
? $element->getAttribute('title')
: $self->{'DATA'}->{'label'};
$self->{'id'} = $self->{'DATA'}->{'href'};
$self->{'id.person'} = $context->make_bnode;
my $hcard_element = searchAncestorClass('vcard', $element, 0);
if ($hcard_element)
{
$self->{'hcard'} = HTML::Microformats::Format::hCard->new($hcard_element, $context);
if ($self->{'hcard'})
{
$self->{'id.person'} = $self->{'hcard'}->id(0, 'holder');
}
}
$self->context->representative_hcard;
$cache->set($context, $element, $class, $self)
if defined $cache;
return $self;
}
sub extract_all
{
my ($class, $dom, $context) = @_;
my @links = $dom->getElementsByTagName('link');
push @links, $dom->getElementsByTagName('a');
push @links, $dom->getElementsByTagName('area');
my @rv;
foreach my $link (@links)
{
my $xfn = $class->new($link, $context);
push @rv, $xfn if defined $xfn;
}
return @rv;
}
sub _extract_xfn_relationships
{
my ($self) = @_;
my $R = $self->_xfn_relationship_types;
my $regexp = join '|', keys %$R;
$regexp = "($regexp)";
DIR: foreach my $direction (qw(rel rev))
{
if ($self->{'element'}->hasAttribute($direction))
{
my @matches =
grep { $_ =~ /^($regexp)$/ }
split /\s+/, $self->{'element'}->getAttribute($direction);
next DIR unless @matches;
$self->{'DATA'}->{$direction} = [ map { lc $_ } @matches ];
}
}
}
sub add_to_model
{
my ($self, $model) = @_;
my $R = $self->_xfn_relationship_types;
foreach my $r (@{ $self->data->{'rel'} })
{
next if lc $r eq 'me';
my ($page_link, $person_link);
my ($flags, $other) = split /\:/, $R->{$r}, 2;
if ($flags =~ /E/i)
{
$page_link = "http://buzzword.org.uk/rdf/xen#${r}-hyperlink";
$person_link = "http://buzzword.org.uk/rdf/xen#${r}";
}
elsif ($flags =~ /R/i)
{
$page_link = "http://vocab.sindice.com/xfn#human-relationship-hyperlink";
$person_link = "http://purl.org/vocab/relationship/${r}";
}
else
{
$page_link = "http://vocab.sindice.com/xfn#${r}-hyperlink";
$person_link = "http://vocab.sindice.com/xfn#${r}";
}
$model->add_statement(RDF::Trine::Statement->new(
RDF::Trine::Node::Resource->new( $self->context->document_uri ),
RDF::Trine::Node::Resource->new( $page_link ),
RDF::Trine::Node::Resource->new( $self->data->{'href'} ),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->context->representative_person_id(1),
RDF::Trine::Node::Resource->new( $person_link ),
$self->id(1, 'person'),
));
if ($flags =~ /K/i)
{
$model->add_statement(RDF::Trine::Statement->new(
$self->context->representative_person_id(1),
RDF::Trine::Node::Resource->new( 'http://xmlns.com/foaf/0.1/knows' ),
$self->id(1, 'person'),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'person'),
RDF::Trine::Node::Resource->new( 'http://xmlns.com/foaf/0.1/knows' ),
$self->context->representative_person_id(1),
))
if $flags =~ /S/i;
}
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'person'),
RDF::Trine::Node::Resource->new( $person_link ),
$self->context->representative_person_id(1),
))
if $flags =~ /S/i;
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'person'),
RDF::Trine::Node::Resource->new($other),
$self->context->representative_person_id(1),
))
if $flags =~ /I/i && length $other;
}
foreach my $r (@{ $self->data->{'rev'} })
{
next if lc $r eq 'me';
my $person_link;
my ($flags, $other) = split /\:/, $R->{$r}, 2;
if ($flags =~ /E/i)
{
$person_link = "http://buzzword.org.uk/rdf/xen#${r}";
}
elsif ($flags =~ /R/i)
{
$person_link = "http://purl.org/vocab/relationship/${r}";
}
else
{
$person_link = "http://vocab.sindice.com/xfn#${r}";
}
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'person'),
RDF::Trine::Node::Resource->new( $person_link ),
$self->context->representative_person_id(1),
));
if ($flags =~ /K/i)
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'person'),
RDF::Trine::Node::Resource->new( 'http://xmlns.com/foaf/0.1/knows' ),
$self->context->representative_person_id(1),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->context->representative_person_id(1),
RDF::Trine::Node::Resource->new( 'http://xmlns.com/foaf/0.1/knows' ),
$self->id(1, 'person'),
))
if $flags =~ /S/i;
}
$model->add_statement(RDF::Trine::Statement->new(
$self->context->representative_person_id(1),
RDF::Trine::Node::Resource->new( $person_link ),
$self->id(1, 'person'),
))
if $flags =~ /S/i;
$model->add_statement(RDF::Trine::Statement->new(
$self->context->representative_person_id(1),
RDF::Trine::Node::Resource->new($other),
$self->id(1, 'person'),
))
if $flags =~ /I/i && length $other;
}
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'person'),
RDF::Trine::Node::Resource->new( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' ),
RDF::Trine::Node::Resource->new( 'http://xmlns.com/foaf/0.1/Person' ),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'person'),
RDF::Trine::Node::Resource->new( 'http://xmlns.com/foaf/0.1/'.($self->data->{'href'} =~ /^mailto:/i ? 'mbox' : 'page') ),
RDF::Trine::Node::Resource->new( $self->data->{'href'} ),
));
$model->add_statement(RDF::Trine::Statement->new(
RDF::Trine::Node::Resource->new( $self->data->{'href'} ),
RDF::Trine::Node::Resource->new( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' ),
RDF::Trine::Node::Resource->new( 'http://xmlns.com/foaf/0.1/Document' ),
))
unless $self->data->{'href'} =~ /^mailto:/i;
if (grep /^me$/i, @{ $self->data->{'rel'} })
{
$model->add_statement(RDF::Trine::Statement->new(
RDF::Trine::Node::Resource->new( $self->context->document_uri ),
RDF::Trine::Node::Resource->new( 'http://vocab.sindice.com/xfn#me-hyperlink' ),
RDF::Trine::Node::Resource->new( $self->data->{'href'} ),
));
}
if (grep /^me$/i, @{ $self->data->{'rev'} })
{
$model->add_statement(RDF::Trine::Statement->new(
RDF::Trine::Node::Resource->new( $self->data->{'href'} ),
RDF::Trine::Node::Resource->new( 'http://vocab.sindice.com/xfn#me-hyperlink' ),
RDF::Trine::Node::Resource->new( $self->context->document_uri ),
));
}
}
sub profiles
{
my $class = shift;
return qw(http://gmpg.org/xfn/11
http://purl.org/uF/2008/03/
http://gmpg.org/xfn/1
http://microformats.org/profile/specs
http://ufs.cc/x/specs
http://xen.adactio.com/
http://purl.org/vocab/relationship/);
}
sub id
{
my ($self, $trine, $relation) = @_;
if ($relation eq 'person')
{
if (grep /^me$/i, @{ $self->data->{'rel'} }
or grep /^me$/i, @{ $self->data->{'rev'} })
{
return $self->context->representative_person_id($trine);
}
}
$self->SUPER::id($trine, $relation);
}
sub _xfn_relationship_types
{
my ($self) = @_;
# FLAGS
# =====
#
# S = symmetric
# K = foaf:knows
# I = has inverse
# T = transitive
# E = enemies vocab
# R = relationship vocab
#
my %xfn11 = (
'contact' => ':',
'acquaintance' => 'K:',
'friend' => 'K:',
'met' => 'SK:',
'co-worker' => 'S:',
'colleague' => 'S:',
'co-resident' => 'SKT:',
'neighbor' => 'S:',
'child' => 'I:http://vocab.sindice.com/xfn#parent',
'parent' => 'I:http://vocab.sindice.com/xfn#child',
'sibling' => 'S:',
'spouse' => 'SK:',
'kin' => 'S:',
'muse' => ':',
'crush' => 'K:',
'date' => 'SK:',
'sweetheart' => 'SK:',
'me' => 'S:',
);
my %R; # relationship types
if ($self->context->has_profile('http://gmpg.org/xfn/11',
'http://purl.org/uF/2008/03/'))
{
%R = %xfn11;
}
elsif ($self->context->has_profile('http://gmpg.org/xfn/1'))
{
%R = (
'acquaintance' => 'K:',
'friend' => 'K:',
'met' => 'SK:',
'co-worker' => 'S:',
'colleague' => 'S:',
'co-resident' => 'SKT:',
'neighbor' => 'S:',
'child' => 'I:http://vocab.sindice.com/xfn#parent',
'parent' => 'I:http://vocab.sindice.com/xfn#child',
'sibling' => 'S:',
'spouse' => 'SK:',
'muse' => ':',
'crush' => 'K:',
'date' => 'SK:',
'sweetheart' => 'SK:',
);
}
if ($self->context->has_profile('http://xen.adactio.com/'))
{
$R{'nemesis'} = 'SKE:';
$R{'enemy'} = 'KE:';
$R{'nuisance'} = 'KE:';
$R{'evil-twin'} = 'SE:';
$R{'rival'} = 'KE:';
$R{'fury'} = 'E:';
$R{'creep'} = 'E:';
}
if ($self->context->has_profile('http://purl.org/vocab/relationship/'))
{
$R{'acquaintanceOf'} = 'KR:';
$R{'ambivalentOf'} = 'R:';
$R{'ancestorOf'} = 'RI:http://purl.org/vocab/relationship/descendantOf';
$R{'antagonistOf'} = 'KR:';
$R{'apprenticeTo'} = 'KR:';
$R{'childOf'} = 'KRI:http://purl.org/vocab/relationship/parentOf';
$R{'closeFriendOf'} = 'KR:';
$R{'collaboratesWith'} = 'SKR:';
$R{'colleagueOf'} = 'SKR:';
$R{'descendantOf'} = 'RI:http://purl.org/vocab/relationship/ancestorOf';
$R{'employedBy'} = 'KRI:http://purl.org/vocab/relationship/employerOf';
$R{'employerOf'} = 'KRI:http://purl.org/vocab/relationship/employedBy';
$R{'enemyOf'} = 'KR:';
$R{'engagedTo'} = 'SKR:';
$R{'friendOf'} = 'KR:';
$R{'grandchildOf'} = 'KRI:http://purl.org/vocab/relationship/grandparentOf';
$R{'grandparentOf'} = 'KRI:http://purl.org/vocab/relationship/grandchildOf';
$R{'hasMet'} = 'SKR:';
$R{'influencedBy'} = 'R:';
$R{'knowsByReputation'} = 'R:';
$R{'knowsInPassing'} = 'KR:';
$R{'knowsOf'} = 'R:';
$R{'lifePartnerOf'} = 'SKR:';
$R{'livesWith'} = 'SKR:';
$R{'lostContactWith'} = 'KR:';
$R{'mentorOf'} = 'KR:';
$R{'neighborOf'} = 'SKR:';
$R{'parentOf'} = 'KRI:http://purl.org/vocab/relationship/childOf';
$R{'siblingOf'} = 'SKR:';
$R{'spouseOf'} = 'SKR:';
$R{'worksWith'} = 'SKR:';
$R{'wouldLikeToKnow'} = 'R:';
}
return \%R if %R;
return \%xfn11;
}
=head2 Additional Public Methods
=over 4
=item C<< $xfn->subject_hcard >>
Returns the hCard for the subject of the relationship. e.g. if Mary has parent Sue, then
Mary is the subject.
If the subject could not be determined, may return undef.
=cut
sub subject_hcard
{
my $self = shift;
return $self->context->representative_hcard;
}
=item C<< $xfn->object_hcard >>
Returns the hCard for the object of the relationship. e.g. if Mary has parent Sue, then
Sue is the object.
The person that is the object of the relationship may not have an hCard on this page,
or the parser may not be able to determine the correct hCard, in which case, may return
undef.
=back
=cut
sub object_hcard
{
my $self = shift;
return $self->{'hcard'};
}
1;
=head1 MICROFORMAT
HTML::Microformats::Format::XFN supports XHTML Friends Network 1.0 and 1.1
as described at L and L; plus the
relationship profile described at L;
and XHTML Enemies Network 1.0 as described at L.
By default, only XFN 1.1 is parsed, but if the context has profiles matching the
other URIs above, then the other vocabularies are supported.
=head1 RDF OUTPUT
Data is returned using the DERI's XFN vocabulary
(L) and when appropriate, Ian Davis'
RDF relationship vocab (L)
and Toby Inkster's XEN vocab (L).
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hResume.pm 0000644 0000764 0000764 00000024041 11775403507 022241 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hResume - the hResume microformat
=head1 SYNOPSIS
use HTML::Microformats::DocumentContext;
use HTML::Microformats::Format::hResume;
my $context = HTML::Microformats::DocumentContext->new($dom, $uri);
my @resumes = HTML::Microformats::Format::hResume->extract_all(
$dom->documentElement, $context);
foreach my $resume (@resumes)
{
print $resume->get_contact->get_fn . "\n";
}
=head1 DESCRIPTION
HTML::Microformats::Format::hResume inherits from HTML::Microformats::Format. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=cut
package HTML::Microformats::Format::hResume;
use base qw(HTML::Microformats::Format HTML::Microformats::Mixin::Parser);
use strict qw(subs vars); no warnings;
use 5.010;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hResume::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hResume::VERSION = '0.105';
}
sub new
{
my ($class, $element, $context, %options) = @_;
my $cache = $context->cache;
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
};
bless $self, $class;
my $clone = $element->cloneNode(1);
$self->_expand_patterns($clone);
$self->_simple_parse($clone);
$self->{'DATA'}->{'contact'} = $self->{'DATA'}->{'address'}
unless defined $self->{'DATA'}->{'contact'};
if (defined $self->{'DATA'}->{'contact'})
{
$self->{'id.holder'} = $self->{'DATA'}->{'contact'}->id(0, 'holder');
}
else
{
$self->{'id.holder'} = $context->make_bnode;
}
# # Create links between hCard and hCalendar events found within!
# foreach my $prop (qw(education experience))
# {
# foreach my $e ( @{$self->{'DATA'}->{$prop}} )
# {
# foreach my $ehc ( @{$self->{'DATA'}->{$prop.'-hcard'}} )
# {
# my $ehcxp = $ehc->{'parent_property_node'}->getAttribute('data-cpan-html-microformats-nodepath');
# if ($ehcxp eq $e->{'parent_property_node'}->getAttribute('data-cpan-html-microformats-nodepath'))
# {
# $e -> {'associated_hcard'} = $ehc;
# $ehc -> {'associated_hevent'} = $e;
# }
# }
# }
#
# foreach my $card ( @{$self->{'DATA'}->{$prop.'-hcard'}} )
# {
# $card->{'id.holder'} = $self->id(0, 'holder');
# }
#
# delete $self->{'DATA'}->{$prop.'-hcard'};
# }
$cache->set($context, $element, $class, $self)
if defined $cache;
return $self;
}
sub format_signature
{
my $self = shift;
my $cv = "http://purl.org/captsolo/resume-rdf/0.2/cv#";
my $cvx = "http://ontologi.es/hresume#";
# parsing hCards seems to do more harm than good!
my $rv = {
'root' => 'hresume',
'classes' => [
['summary', '?'],
['contact', 'm?', {'embedded'=>'hCard'}],
['address', 'tm?', {'embedded'=>'hCard'}],
['education', 'm*', {'embedded'=>'hEvent', 'allow-interleaved' => ['vcalendar']}], #}],, 'again-again'=>1}],
#['education', 'm*', {'embedded'=>'hCard', 'allow-interleaved' => ['vcalendar', 'vevent'], 'use-key'=>'education-hcard'}],
['experience', 'm*', {'embedded'=>'hEvent', 'allow-interleaved' => ['vcalendar']}], #}],, 'again-again'=>1}],
#['experience', 'm*', {'embedded'=>'hCard', 'allow-interleaved' => ['vcalendar', 'vevent'], 'use-key'=>'experience-hcard'}],
['skill', '*'],
['affiliation', 'M*', {'embedded'=>'hCard'}],
['cite', 't', {'use-key'=>'publication'}]
],
'options' => {
},
'rdf:type' => ["${cv}CV"] ,
'rdf:property' => {
'summary' => { 'literal' => ["${cv}cvDescription"] },
'experience' => { 'resource' => ["${cvx}experience"] },
'education' => { 'resource' => ["${cvx}education"] },
'contact' => { 'resource' => ["${cvx}contact"] },
'affiliation' => { 'resource' => ["${cvx}affiliation"] },
'publication' => { 'literal' => ["${cvx}publication"] },
'skill' => { 'literal' => ["${cvx}skill"] },
},
};
return $rv;
}
sub add_to_model
{
my $self = shift;
my $model = shift;
$self->_simple_rdf($model);
my $cv = "http://purl.org/captsolo/resume-rdf/0.2/cv#";
my $rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
my $cvx = "http://ontologi.es/hresume#";
if (defined $self->data->{'contact'})
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${cv}aboutPerson"),
$self->id(1, 'holder'),
));
$self->data->{'contact'}->add_to_model($model);
}
foreach my $experience (@{$self->data->{'experience'}})
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${cv}hasWorkHistory"),
$experience->id(1, 'experience'),
));
$model->add_statement(RDF::Trine::Statement->new(
$experience->id(1, 'experience'),
RDF::Trine::Node::Resource->new("${rdf}type"),
RDF::Trine::Node::Resource->new("${cv}WorkHistory"),
));
$model->add_statement(RDF::Trine::Statement->new(
$experience->id(1, 'experience'),
RDF::Trine::Node::Resource->new("${cvx}ical-component"),
$experience->id(1),
));
$model->add_statement(RDF::Trine::Statement->new(
$experience->id(1, 'experience'),
RDF::Trine::Node::Resource->new("${cvx}business-card"),
$experience->{'associated_vcard'}->id(1),
))
if defined $experience->{'associated_vcard'};
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new("http://purl.org/uF/hCard/terms/hasHistoricCard"),
$experience->{'associated_vcard'}->id(1),
))
if defined $experience->{'associated_vcard'};
$model->add_statement(RDF::Trine::Statement->new(
$experience->id(1, 'experience'),
RDF::Trine::Node::Resource->new("${cv}startDate"),
$self->_make_literal($experience->data->{'dtstart'}, 'dateTime'),
))
if defined $experience->data->{'dtstart'};
$model->add_statement(RDF::Trine::Statement->new(
$experience->id(1, 'experience'),
RDF::Trine::Node::Resource->new("${cv}endDate"),
$self->_make_literal($experience->data->{'dtend'}, 'dateTime'),
))
if defined $experience->data->{'dtend'};
if (defined $experience->{'associated_hcard'}
&& defined $experience->{'associated_hcard'}->data->{'title'})
{
$model->add_statement(RDF::Trine::Statement->new(
$experience->id(1, 'experience'),
RDF::Trine::Node::Resource->new("${cv}jobTitle"),
$self->_make_literal($experience->{'associated_hcard'}->data->{'title'}),
));
}
$experience->add_to_model($model);
$experience->{'associated_hcard'}->add_to_model($model)
if defined $experience->{'associated_hcard'};
}
foreach my $edu (@{$self->data->{'education'}})
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${cv}hasEducation"),
$edu->id(1, 'education'),
));
$model->add_statement(RDF::Trine::Statement->new(
$edu->id(1, 'education'),
RDF::Trine::Node::Resource->new("${rdf}type"),
RDF::Trine::Node::Resource->new("${cv}Education"),
));
$model->add_statement(RDF::Trine::Statement->new(
$edu->id(1, 'education'),
RDF::Trine::Node::Resource->new("${cvx}ical-component"),
$edu->id(1),
));
$model->add_statement(RDF::Trine::Statement->new(
$edu->id(1, 'education'),
RDF::Trine::Node::Resource->new("${cvx}business-card"),
$edu->{'associated_vcard'}->id(1),
))
if defined $edu->{'associated_vcard'};
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'holder'),
RDF::Trine::Node::Resource->new("http://purl.org/uF/hCard/terms/hasHistoricCard"),
$edu->{'associated_vcard'}->id(1),
))
if defined $edu->{'associated_vcard'};
$model->add_statement(RDF::Trine::Statement->new(
$edu->id(1, 'education'),
RDF::Trine::Node::Resource->new("${cv}eduStartDate"),
$self->_make_literal($edu->data->{'dtstart'}, 'dateTime'),
))
if defined $edu->data->{'dtstart'};
$model->add_statement(RDF::Trine::Statement->new(
$edu->id(1, 'education'),
RDF::Trine::Node::Resource->new("${cv}eduGradDate"),
$self->_make_literal($edu->data->{'dtend'}, 'dateTime'),
))
if defined $edu->data->{'dtend'};
$edu->add_to_model($model);
$edu->{'associated_hcard'}->add_to_model($model)
if defined $edu->{'associated_hcard'};
}
foreach my $skill (@{$self->data->{'skill'}})
{
my $skill_bnode = $self->id(1, 'skill.'.$skill);
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${cv}hasSkill"),
$skill_bnode,
));
$model->add_statement(RDF::Trine::Statement->new(
$skill_bnode,
RDF::Trine::Node::Resource->new("${rdf}type"),
RDF::Trine::Node::Resource->new("${cv}Skill"),
));
$model->add_statement(RDF::Trine::Statement->new(
$skill_bnode,
RDF::Trine::Node::Resource->new("${cv}skillName"),
$self->_make_literal($skill),
));
}
return $self;
}
sub profiles
{
my $class = shift;
return qw(http://microformats.org/profile/hresume
http://ufs.cc/x/hresume
http://purl.org/uF/hResume/0.1/);
}
1;
=head1 MICROFORMAT
HTML::Microformats::Format::hResume supports hResume as described at
L.
=head1 RDF OUTPUT
The RDF output is modelled on Uldis Bojars' ResumeRDF Ontology
L, with some additional
terms from Toby Inkster's hResume vocab .
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L,
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hAudio.pm 0000644 0000764 0000764 00000021041 11775403507 022037 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hAudio - the hAudio microformat
=head1 SYNOPSIS
use Data::Dumper;
use HTML::Microformats::DocumentContext;
use HTML::Microformats::Format::hAudio;
my $context = HTML::Microformats::DocumentContext->new($dom, $uri);
my @haudios = HTML::Microformats::Format::hAudio->extract_all(
$dom->documentElement, $context);
foreach my $haudio (@haudios)
{
print $haudio->get_fn . "\n";
}
=head1 DESCRIPTION
HTML::Microformats::Format::hAudio inherits from HTML::Microformats::Format. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=cut
package HTML::Microformats::Format::hAudio;
use base qw(HTML::Microformats::Format HTML::Microformats::Mixin::Parser);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(searchClass stringify);
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hAudio::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hAudio::VERSION = '0.105';
}
sub new
{
my ($class, $element, $context) = @_;
my $cache = $context->cache;
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
};
bless $self, $class;
my $clone = $element->cloneNode(1);
$self->_expand_patterns($clone);
# Items - too tricky for simple_parse() to handle!
my ($this_item, $last_item);
my @items = searchClass('item', $clone);
foreach my $i (@items)
{
# Deal with ".haudio .item .item", etc! This shuld work...
if (length $last_item)
{
$this_item = $i->getAttribute('data-cpan-html-microformats-nodepath');
next if substr($this_item, 0, length $last_item) eq $last_item;
}
$last_item = $i->getAttribute('data-cpan-html-microformats-nodepath');
my $I = $class->new($i, $context);
$I->{'DATA'}->{'title'} = stringify($i, 'value')
unless defined $I->{'DATA'}->{'fn'} || defined $I->{'DATA'}->{'album'};
$I->{'related'}->{'parent'} = $self;
push @{ $self->{'DATA'}->{'item'} }, $I;
$self->_destroy_element($i);
}
$self->_simple_parse($clone);
# Does this represent an album or a track?
# http://microformats.org/wiki/haudio#More_Semantic_Equivalents
if (defined $self->{'DATA'}->{'fn'} && defined $self->{'DATA'}->{'album'})
{ $self->{'DATA'}->{'type'} = 'track'; }
elsif (defined $self->{'DATA'}->{'album'})
{ $self->{'DATA'}->{'type'} = 'album'; }
else
{ $self->{'DATA'}->{'type'} = 'track'; }
$self->_do_inheritance;
$cache->set($context, $element, $class, $self)
if defined $cache;
return $self;
}
sub _do_inheritance
{
my $self = shift;
ITEM: foreach my $item (@{ $self->{'DATA'}->{'item'} })
{
PROPERTY: foreach my $property (qw(album contributor category published photo))
{
next PROPERTY if defined $item->{'DATA'}->{$property};
$item->{'DATA'}->{$property} = $self->{'DATA'}->{$property};
}
# Recursion.
$item->_do_inheritance;
}
return $self;
}
sub format_signature
{
my $media = 'http://purl.org/media#';
my $audio = 'http://purl.org/media/audio#';
my $comm = 'http://purl.org/commerce#';
my $dc = 'http://purl.org/dc/terms/';
my $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
return {
'root' => 'haudio',
'classes' => [
['album', '?'],
['category', '*'],
['contributor', 'M*', {embedded=>'hCard'}],
['description', '&'],
['duration', 'D?'],
['enclosure', 'ru*'],
['fn', '?'],
['item', '*#'],
['payment', 'ru*'],
['position', 'n?'],
['photo', 'u*'],
['price', 'M?', {embedded=>'hMeasure'}],
['published', 'd*'],
['publisher', 'M*', {embedded=>'hCard'}], # extension
['sample', 'ru*'],
['title', '?', {'use-key'=>'fn'}], # fallback (historical)
['type', '?#'], # always inferred
['url', 'u*']
],
'options' => {
'rel-tag' => 'category',
},
'rdf:type' => [] ,
'rdf:property' => {
'category' => { resource => ["{$dc}type"] , literal => ["{$dc}type"] } ,
'contributor' => { resource => ["{$dc}contributor"] } ,
'description' => { literal => ["{$dc}description"] } ,
'duration' => { literal => ["{$media}duration"] } ,
'enclosure' => { resource => ["{$media}download"] } ,
'item' => { resource => ["{$media}contains"] } ,
'payment' => { resource => ["{$comm}payment"] } ,
'photo' => { resource => ["{$media}depiction"] } ,
'price' => { literal => ["{$comm}costs"] , resource => ['http://buzzword.org.uk/rdf/measure-aux#hasMeasurement'] } ,
'publisher' => { resource => ["{$dc}publisher"] } ,
'published' => { literal => ["{$dc}published"] } ,
'sample' => { resource => ["{$media}sample"] } ,
'url' => { resource => ['http://xmlns.com/foaf/0.1/page'] },
},
};
}
sub add_to_model
{
my $self = shift;
my $model = shift;
$self->_simple_rdf($model);
my $media = 'http://purl.org/media#';
my $audio = 'http://purl.org/media/audio#';
my $comm = 'http://purl.org/commerce#';
my $dc = 'http://purl.org/dc/terms/';
my $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
my $rdfs = 'http://www.w3.org/2000/01/rdf-schema#';
if ($self->get_type eq 'album')
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${rdf}type"),
RDF::Trine::Node::Resource->new("${audio}Album"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${rdfs}label"),
$self->_make_literal($self->get_album),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${dc}title"),
$self->_make_literal($self->get_album),
));
}
elsif ($self->get_type eq 'track')
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${rdf}type"),
RDF::Trine::Node::Resource->new("${audio}Recording"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${rdfs}label"),
$self->_make_literal($self->get_fn),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1),
RDF::Trine::Node::Resource->new("${dc}title"),
$self->_make_literal($self->get_fn),
));
if (defined $self->get_album
&& (!defined $self->{'related'}->{'parent'} || $self->{'related'}->{'parent'}->get_album ne $self->get_album))
{
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'album'),
RDF::Trine::Node::Resource->new("${rdf}type"),
RDF::Trine::Node::Resource->new("${audio}Album"),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'album'),
RDF::Trine::Node::Resource->new("${rdfs}label"),
$self->_make_literal($self->get_album),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'album'),
RDF::Trine::Node::Resource->new("${dc}title"),
$self->_make_literal($self->get_album),
));
$model->add_statement(RDF::Trine::Statement->new(
$self->id(1, 'album'),
RDF::Trine::Node::Resource->new("${media}contains"),
$self->id(1),
));
}
}
return $self;
}
sub profiles
{
my $class = shift;
return qw(http://purl.org/uF/hAudio/0.9/
http://purl.org/NET/haudio);
}
1;
=head1 MICROFORMAT
HTML::Microformats::Format::hAudio supports hAudio 0.91 as described at
L, plus:
=over 4
=item * 'publisher' property
A 'publisher' property with an embedded hCard can be used to indicate the
publisher of the audio item (e.g. record label).
=item * 'title' property
In earlier drafts pf hAudio, the 'fn' property was called 'title'. This module supports
the older class name for backwards compatibility. When both are provided, only
'fn' will be used.
=back
=head1 RDF OUTPUT
RDF output uses Manu Sporny's audio vocabulary L.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/RelTag.pm 0000644 0000764 0000764 00000007401 11775403507 022010 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::RelTag - the rel-tag microformat
=head1 SYNOPSIS
my @tags = HTML::Microformats::Format::RelTag->extract_all(
$doc->documentElement, $context);
foreach my $tag (@tags)
{
print $tag->get_href . "\n";
}
=head1 DESCRIPTION
HTML::Microformats::Format::RelTag inherits from HTML::Microformats::Format_Rel. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=head2 Additional Methods
=over 4
=item C<< $reltag->get_tag() >>
Returns the tag being linked to. Given the following link:
http://example.com/foo/bar?baz=quux#xyzzy
the tag is "bar".
=item C<< $reltag->get_tagspace() >>
Returns the tagspace of the tag being linked to. Given the following link:
http://example.com/foo/bar?baz=quux#xyzzy
the tagspace is "http://example.com/foo/".
=back
=cut
package HTML::Microformats::Format::RelTag;
use base qw(HTML::Microformats::Format_Rel);
use strict qw(subs vars); no warnings;
use 5.010;
use CGI::Util qw(unescape);
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::RelTag::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::RelTag::VERSION = '0.105';
}
sub new
{
my $class = shift;
my $self = $class->SUPER::new(@_);
my $tag = $self->{'DATA'}->{'href'};
$tag =~ s/\#.*$//;
$tag =~ s/\?.*$//;
$tag =~ s/\/$//;
if ($tag =~ m{^(.*/)([^/]+)$})
{
$self->{'DATA'}->{'tagspace'} = $1;
$self->{'DATA'}->{'tag'} = unescape($2);
}
return $self;
}
sub format_signature
{
my $t = 'http://www.holygoat.co.uk/owl/redwood/0.1/tags/';
my $awol = 'http://bblfish.net/work/atom-owl/2006-06-06/#';
return {
'rel' => 'tag' ,
'classes' => [
['tag', '1#'] ,
['tagspace', '1#'] ,
['href', '1#'] ,
['label', '1#'] ,
['title', '1#'] ,
] ,
'rdf:type' => ["${t}Tag","${awol}Category"] ,
'rdf:property' => {
'tag' => { 'literal' => ["${awol}term", "${t}name", "http://www.w3.org/2000/01/rdf-schema#label"] },
'tagspace' => { 'resource' => ["${awol}scheme"] },
'href' => { 'resource' => ["http://xmlns.com/foaf/0.1/page"] },
} ,
}
}
sub profiles
{
return qw(http://microformats.org/profile/rel-tag
http://ufs.cc/x/rel-tag
http://microformats.org/profile/specs
http://ufs.cc/x/specs
http://purl.org/uF/rel-tag/1.0/
http://purl.org/uF/2008/03/);
}
sub add_to_model
{
my $self = shift;
my $model = shift;
$self->_simple_rdf($model);
$model->add_statement(RDF::Trine::Statement->new(
RDF::Trine::Node::Resource->new($self->context->document_uri),
RDF::Trine::Node::Resource->new('http://www.holygoat.co.uk/owl/redwood/0.1/tags/taggedWithTag'),
$self->id(1),
));
return $self;
}
1;
=head1 MICROFORMAT
HTML::Microformats::Format::RelTag supports rel-tag as described at
L.
The "title" attribute on the link, and the linked text are taken to be significant.
=head1 RDF OUTPUT
Data is returned using the Richard Newman's tag vocabulary
(L),
the Atom OWL vocabulary (L)
and occasional other terms.
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hTodo.pm 0000644 0000764 0000764 00000023107 11775403507 021710 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hTodo - an hCalendar todo component
=head1 SYNOPSIS
use Data::Dumper;
use HTML::Microformats::DocumentContext;
use HTML::Microformats::Format::hCalendar;
my $context = HTML::Microformats::DocumentContext->new($dom, $uri);
my @cals = HTML::Microformats::Format::hCalendar->extract_all(
$dom->documentElement, $context);
foreach my $cal (@cals)
{
foreach my $todo ($cal->get_vtodo)
{
printf("%s: %s\n", $todo->get_due, $todo->get_summary);
}
}
=head1 DESCRIPTION
HTML::Microformats::Format::hTodo is a helper module for HTML::Microformats::Format::hCalendar.
This class is used to represent todo components within calendars. Generally speaking,
you want to use HTML::Microformats::Format::hCalendar instead.
HTML::Microformats::Format::hTodo inherits from HTML::Microformats::Format. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=head2 Additional Method
=over
=item * C<< to_icalendar >>
This method exports the data in iCalendar format. It requires
L to work, and will throw an error at run-time
if it's not available.
=back
=cut
package HTML::Microformats::Format::hTodo;
use base qw(HTML::Microformats::Format HTML::Microformats::Mixin::Parser);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(stringify searchClass);
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hTodo::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hTodo::VERSION = '0.105';
}
sub new
{
my ($class, $element, $context) = @_;
my $cache = $context->cache;
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
};
bless $self, $class;
my $clone = $element->cloneNode(1);
$self->_expand_patterns($clone);
$self->_simple_parse($clone);
$self->_parse_related($clone);
$cache->set($context, $element, $class, $self)
if defined $cache;
return $self;
}
sub _parse_related
{
HTML::Microformats::Format::hEvent::_parse_related(@_);
}
sub extract_all
{
my ($class, $element, $context) = @_;
my @todos = HTML::Microformats::Format::extract_all($class, $element, $context);
foreach my $list (searchClass('vtodo-list', $element))
{
push @todos, $class->extract_all_xoxo($list, $context);
}
return @todos;
}
sub format_signature
{
my $ical = 'http://www.w3.org/2002/12/cal/icaltzd#';
my $icalx = 'http://buzzword.org.uk/rdf/icaltzdx#';
return {
'root' => 'vtodo',
'classes' => [
['attach', 'u*'],
['attendee', 'M*', {embedded=>'hCard !person', 'is-in-cal'=>1}],
['categories', '*'],
['category', '*', {'use-key'=>'categories'}],
['class', '?', {'value-title'=>'allow'}],
['comment', '*'],
['completed', 'd?'],
['contact', 'M*', {embedded=>'hCard !person', 'is-in-cal'=>1}],
['created', 'd?'],
['description', '?'],
#['dtend', 'd?'],
['dtstamp', 'd?'],
['dtstart', 'd1'],
['due', 'd?'],
['duration', 'D?'],
['exdate', 'd*'],
['exrule', 'e*'],
['geo', 'M*', {embedded=>'geo'}],
['last-modified', 'd?'],
['location', 'M*', {embedded=>'hCard adr geo'}],
['organizer', 'M*', {embedded=>'hCard !person', 'is-in-cal'=>1}],
['percent-complete', '?'],
['priority', '?', {'value-title'=>'allow'}],
['rdate', 'd*'],
['recurrance-id', 'U?'],
['resource', '*', {'use-key'=>'resources'}],
['resources', '*'],
['rrule', 'e*'],
['sequence', 'n?', {'value-title'=>'allow'}],
['status', '?', {'value-title'=>'allow'}],
['summary', '1'],
#['transp', '?'],
['uid', 'U?'],
['url', 'U?'],
['valarm', 'M*', {embedded=>'hAlarm'}],
['x-sighting-of', 'M*', {embedded=>'species'}] #extension
],
'options' => {
'rel-tag' => 'categories',
'rel-enclosure' => 'attach',
'hmeasure' => 'measures'
},
'rdf:type' => ["${ical}Vtodo"] ,
'rdf:property' => {
# 'attach' => { 'resource' => ["${ical}attach"] } ,
'attendee' => { 'resource' => ["${ical}attendee"], 'literal' => ["${icalx}attendee-literal"] } ,
'categories' => { 'resource' => ["${icalx}category"], 'literal' => ["${ical}category"] },
'class' => { 'literal' => ["${ical}class"] , 'literal_datatype' => 'string'} ,
'comment' => { 'literal' => ["${ical}comment"] } ,
'completed' => { 'literal' => ["${ical}completed"] } ,
'contact' => { 'resource' => ["${icalx}contact"], 'literal' => ["${ical}contact"] } ,
'created' => { 'literal' => ["${ical}created"] } ,
'description' => { 'literal' => ["${ical}description"] } ,
'dtend' => { 'literal' => ["${ical}dtend"] } ,
'dtstamp' => { 'literal' => ["${ical}dtstamp"] } ,
'dtstart' => { 'literal' => ["${ical}dtstart"] } ,
'due' => { 'literal' => ["${ical}due"] } ,
'duration' => { 'literal' => ["${ical}duration"] } ,
'exdate' => { 'literal' => ["${ical}exdate"] } ,
'geo' => { 'literal' => ["${icalx}geo"] } ,
'last-modified' => { 'literal' => ["${ical}lastModified"] } ,
'location' => { 'resource' => ["${icalx}location"], 'literal' => ["${ical}location"] } ,
'organizer' => { 'resource' => ["${ical}organizer"], 'literal' => ["${icalx}organizer-literal"] } ,
'percent-complete' => { 'literal' => ["${ical}percentComplete"] , 'literal_datatype' => 'integer' } ,
'priority' => { 'literal' => ["${ical}priority"] } ,
'rdate' => { 'literal' => ["${ical}rdate"] } ,
'recurrance-id' => { 'resource' => ["${ical}recurranceId"] , 'literal' => ["${ical}recurranceId"] , 'literal_datatype' => 'string' } ,
'resources' => { 'literal' => ["${ical}resources"] } ,
'sequence' => { 'literal' => ["${ical}sequence"] , 'literal_datatype' => 'integer' } ,
'status' => { 'literal' => ["${ical}status"] , 'literal_datatype' => 'string' } ,
'summary' => { 'literal' => ["${ical}summary"] } ,
'transp' => { 'literal' => ["${ical}transp"] , 'literal_datatype' => 'string' } ,
'uid' => { 'resource' => ["${ical}uid"] , 'literal' => ["${ical}uid"] , 'literal_datatype' => 'string' } ,
'url' => { 'resource' => ["${ical}url"] } ,
'valarm' => { 'resource' => ["${ical}valarm"] } ,
'x-sighting-of' => { 'resource' => ["${ical}x-sighting-of"] } ,
},
};
}
sub add_to_model
{
# essentially the same...
return HTML::Microformats::Format::hEvent::add_to_model(@_);
}
sub profiles
{
return HTML::Microformats::Format::hCalendar::profiles(@_);
}
sub extract_all_xoxo
{
my ($class, $element, $context) = @_;
return qw() unless $element->tagName =~ /^(ul|ol)$/i;
my @all_items;
foreach my $li ($element->getChildrenByTagName('li'))
{
my @these_items = $class->extract_all_xoxo_item($li, $context);
push @all_items, @these_items;
}
return @all_items;
}
sub extract_all_xoxo_item
{
my ($class, $element, $context) = @_;
return qw() unless $element->tagName eq 'li';
my $clone = $element->cloneNode(1);
# Find any child XOXO-style lists. Parse then discard.
my @child_items;
foreach my $list ($clone->getChildrenByTagName('ol'))
{
my @these_items = $class->extract_all_xoxo($list, $context);
push @child_items, @these_items;
$clone->removeChild($list);
}
foreach my $list ($clone->getChildrenByTagName('ul'))
{
my @these_items = $class->extract_all_xoxo($list, $context);
push @child_items, @these_items;
$clone->removeChild($list);
}
my $self = $class->new($clone, $context);
unless (length $self->data->{'summary'})
{
$self->data->{'summary'} = stringify($clone);
}
my @rv = ($self);
CHILD: foreach my $child (@child_items)
{
if (defined $child->{'related'}->{'parent'}
or defined $child->{'DATA'}->{'parent'})
{
push @{$child->{'related'}->{'other'}}, $self;
push @{$self->{'related'}->{'other'}}, $child;
}
else
{
$child->{'related'}->{'parent'} = $self;
push @{$self->{'related'}->{'child'}}, $child;
}
OTHERCHILD: foreach my $other_child (@child_items)
{
next OTHERCHILD if $child == $other_child;
push @{$child->{'related'}->{'sibling'}}, $other_child;
}
push @rv, $child;
}
return @rv;
}
sub to_icalendar
{
my ($self) = @_;
die "Need RDF::iCalendar to export iCalendar data.\n"
unless $HTML::Microformats::Format::hCalendar::HAS_ICAL_EXPORT;
my $exporter = RDF::iCalendar::Exporter->new;
return $exporter->export_component($self->model, $self->id(1))->to_string;
}
1;
=head1 BUGS
Please report any bugs to L.
=head1 SEE ALSO
L,
L,
L.
=head1 AUTHOR
Toby Inkster Etobyink@cpan.orgE.
=head1 COPYRIGHT AND LICENCE
Copyright 2008-2012 Toby Inkster
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
=cut
HTML-Microformats-0.105/lib/HTML/Microformats/Format/hCalendar.pm 0000644 0000764 0000764 00000021236 11775403507 022515 0 ustar tai tai =head1 NAME
HTML::Microformats::Format::hCalendar - the hCalendar microformat
=head1 SYNOPSIS
use HTML::Microformats::DocumentContext;
use HTML::Microformats::Format::hCalendar;
my $context = HTML::Microformats::DocumentContext->new($dom, $uri);
my @cals = HTML::Microformats::Format::hCalendar->extract_all(
$dom->documentElement, $context);
foreach my $cal (@cals)
{
foreach my $event ($cal->get_vevent)
{
printf("%s: %s\n", $ev->get_dtstart, $ev->get_summary);
}
}
=head1 DESCRIPTION
HTML::Microformats::Format::hCalendar inherits from HTML::Microformats::Format. See the
base class definition for a description of property getter/setter methods,
constructors, etc.
=head2 Additional Method
=over
=item * C<< to_icalendar >>
This method exports the data in iCalendar format. It requires
L to work, and will throw an error at run-time
if it's not available.
=back
=cut
package HTML::Microformats::Format::hCalendar;
use base qw(HTML::Microformats::Format HTML::Microformats::Mixin::Parser);
use strict qw(subs vars); no warnings;
use 5.010;
use HTML::Microformats::Utilities qw(searchClass searchAncestorClass);
use HTML::Microformats::Format::hEntry;
use HTML::Microformats::Format::hEvent;
use HTML::Microformats::Format::hTodo;
use HTML::Microformats::Format::hAlarm;
use HTML::Microformats::Format::hFreebusy;
use Object::AUTHORITY;
BEGIN {
$HTML::Microformats::Format::hCalendar::AUTHORITY = 'cpan:TOBYINK';
$HTML::Microformats::Format::hCalendar::VERSION = '0.105';
}
our $HAS_ICAL_EXPORT;
BEGIN
{
local $@ = undef;
eval 'use RDF::iCalendar;';
$HAS_ICAL_EXPORT = 1
if RDF::iCalendar::Exporter->can('new');
}
sub new
{
my ($class, $element, $context) = @_;
my $cache = $context->cache;
return $cache->get($context, $element, $class)
if defined $cache && $cache->get($context, $element, $class);
my $self = {
'element' => $element ,
'context' => $context ,
'cache' => $cache ,
'id' => $context->make_bnode($element) ,
};
bless $self, $class;
my $clone = $element->cloneNode(1);
$self->_expand_patterns($clone);
$self->_simple_parse($clone);
foreach my $todolist (searchClass('vtodo-list', $element))
{
my $holder_calendar = searchAncestorClass('vcalendar', $todolist);
if (!defined $holder_calendar or
$element->getAttribute('data-cpan-html-microformats-nodepath') eq $holder_calendar->getAttribute('data-cpan-html-microformats-nodepath'))
{
push @{$self->{'DATA'}->{'vtodo'}},
HTML::Microformats::Format::hTodo->extract_all_xoxo($todolist, $context);
}
}
$self->_calculate_relationships;
$self->_cement_relationships;
$cache->set($context, $element, $class, $self)
if defined $cache;
return $self;
}
sub _calculate_relationships
{
my $self = shift;
my %xpath;
foreach my $component (qw(vevent vtodo vjournal))
{
foreach my $object (@{ $self->data->{$component} })
{
my $xp = $object->element->getAttribute('data-cpan-html-microformats-nodepath');
$xpath{$xp} = $object;
}
}
my @xpaths = keys %xpath;
foreach my $xp (@xpaths)
{
unless (defined $xpath{$xp}->{'related'}->{'parent'}
or defined $xpath{$xp}->data->{'parent'})
{
my $parent = __findParent($xp, @xpaths);
if ($parent)
{
$xpath{$xp}->{'related'}->{'parent'} = $xpath{$parent};
push @{ $xpath{$parent}->{'related'}->{'child'} }, $xpath{$xp};
}
}
}
}
sub __findParent
{
my $x = shift;
my $longest = '';
foreach my $potential (@_)
{
if (__ancestorOf($potential, $x))
{
$longest = $potential
if (length($potential) > length($longest));
}
}
return $longest;
}
sub __ancestorOf
{
my ($a, $b) = @_;
return if ($a eq $b);
return (substr($b, 0, length($a)) eq $a);
}
sub _cement_relationships
{
my $self = shift;
my @objects;
foreach my $component (qw(vevent vtodo vjournal))
{
push @objects, @{ $self->data->{$component} };
}
foreach my $object (@objects)
{
# Share parent data between $obj->{'DATA'} and $obj->{'related'}.
if (defined $object->{'related'}->{'parent'}
and !defined $object->{'DATA'}->{'parent'})
{
$object->{'DATA'}->{'parent'} = $object->{'related'}->{'parent'}->get_uid;
}
elsif (!defined $object->{'related'}->{'parent'}
and defined $object->{'DATA'}->{'parent'})
{
$object->{'related'}->{'parent'} =
grep {$_->get_uid eq $object->{'DATA'}->{'parent'}} @objects;
}
# Share other data similarly.
foreach my $relationship (qw(sibling other child))
{
foreach my $related (@{ $object->{'related'}->{$relationship} })
{
next unless defined $related->get_uid;
push @{$object->{'DATA'}->{$relationship}},
$related->get_uid
unless grep { $_ eq $related->get_uid } @{$object->{'DATA'}->{$relationship}};
$object->{'DATA'}->{$relationship} = undef
unless @{ $object->{'DATA'}->{$relationship} };
}
foreach my $related (@{ $object->{'DATA'}->{$relationship} })
{
push @{$object->{'related'}->{$relationship}},
(grep { $_->get_uid eq $related } @objects);
$object->{'related'}->{$relationship} = undef
unless @{$object->{'related'}->{$relationship}};
}
}
}
return $self;
}
sub extract_all
{
my ($class, $element, $context) = @_;
my @cals = HTML::Microformats::Format::extract_all($class, $element, $context);
if ($element->tagName eq 'html' || !@cals)
{
my @components = HTML::Microformats::Format::hEvent->extract_all($element, $context);
push @components, HTML::Microformats::Format::hTodo->extract_all($element, $context);
push @components, HTML::Microformats::Format::hFreebusy->extract_all($element, $context);
push @components, HTML::Microformats::Format::hEntry->extract_all($element, $context);
my $orphans = 0;
foreach my $c (@components)
{
$orphans++ unless searchAncestorClass('hcalendar', $c->element);
}
if ($orphans)
{
my $slurpy = $class->new($element, $context);
unshift @cals, $slurpy;
}
}
return @cals;
}
sub format_signature
{
my $ical = 'http://www.w3.org/2002/12/cal/icaltzd#';
return {
'root' => 'vcalendar',
'classes' => [
['vevent', 'M*', {embedded=>'hEvent'}],
['vtodo', 'M*', {embedded=>'hTodo'}],
['hentry', 'M*', {embedded=>'hEntry', 'use-key'=>'vjournal'}],
['vfreebusy', 'M*', {embedded=>'hFreebusy'}],
['calscale', '?'],
['method', '?'],
],
'options' => {
},
'rdf:type' => ["${ical}Vcalendar"] ,
'rdf:property' => {
'vevent' => { 'resource' => ["${ical}component"] } ,
'vtodo' => { 'resource' => ["${ical}component"] } ,
'vfreebusy' => { 'resource' => ["${ical}component"] } ,
'vjournal' => { 'resource' => ["${ical}component"] } ,
'calscale' => { 'literal' => ["${ical}calscale"] , 'literal_datatype' => 'string'} ,
'method' => { 'literal' => ["${ical}method"] , 'literal_datatype' => 'string'} ,
},
};
}
sub add_to_model
{
my $self = shift;
my $model = shift;
$self->_simple_rdf($model);
foreach my $journal (@{ $self->data->{vjournal} })
{
$journal->add_to_model_ical($model);
}
return $self;
}
sub profiles
{
return qw(http://purl.org/uF/hCalendar/1.1/
http://microformats.org/profile/hcalendar
http://ufs.cc/x/hcalendar
http://microformats.org/profile/specs
http://ufs.cc/x/specs
http://dannyayers.com/microformats/hcalendar-profile
http://www.w3.org/2002/12/cal/hcal
http://purl.org/uF/hCalendar/1.0/
http://purl.org/uF/2008/03/);
}
sub to_icalendar
{
my ($self) = @_;
die "Need RDF::iCalendar to export iCalendar data.\n" unless $HAS_ICAL_EXPORT;
my $exporter = RDF::iCalendar::Exporter->new;
return $exporter->export_calendar($self->model, $self->id(1))->to_string;
}
1;
=head1 MICROFORMAT
HTML::Microformats::Format::hCalendar supports hCalendar as described at
L.
=head1 RDF OUTPUT
Data is returned using the W3C's revised iCalendar vocabulary
(L) with some supplemental
terms from Toby Inkster's revised iCalendar extensions vocabulary
(L) and occasional other terms.
=head1 BUGS
Please report any bugs to L