HTML-Microformats

 view release on metacpan or  search on metacpan

lib/HTML/Microformats/Format/hCard.pm  view on Meta::CPAN

This method exports the hCard as a vCard XML. It requires L<RDF::vCard> and
L<XML::LibXML> 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)

lib/HTML/Microformats/Format/hCard.pm  view on Meta::CPAN

			['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'),



( run in 0.520 second using v1.01-cache-2.11-cpan-39bf76dae61 )