package RDF::RDFa::Generator::HTML::Pretty; use 5.008; use base qw'RDF::RDFa::Generator::HTML::Hidden'; use common::sense; use constant XHTML_NS => 'http://www.w3.org/1999/xhtml'; use Encode qw'encode_utf8'; use Icon::FamFamFam::Silk; use RDF::RDFa::Generator::HTML::Pretty::Note; use XML::LibXML qw':all'; our $VERSION = '0.102'; sub create_document { my ($proto, $model, %opts) = @_; my $self = (ref $proto) ? $proto : $proto->new; my $html = sprintf(<{'version'}||'1.0'), ($self->{'title'} || 'RDFa Document'), ref $self); %2\$s

%2\$s

Generated by %3\$s.

HTML return $proto->inject_document($html, $model, %opts); } sub nodes { my ($proto, $model, %opts) = @_; my $self = (ref $proto) ? $proto : $proto->new; my $stream = $self->_get_stream($model); my @nodes; my $root_node = XML::LibXML::Element->new('div'); $root_node->setNamespace(XHTML_NS, undef, 1); my $prefixes = RDF::Prefixes->new($self->{namespaces}); my $subjects = {}; while (my $st = $stream->next) { my $s = $st->subject->is_resource ? $st->subject->uri : ('_:'.$st->subject->blank_identifier); push @{ $subjects->{$s} }, $st; } foreach my $s (sort keys %$subjects) { my $subject_node = $root_node->addNewChild(XHTML_NS, 'div'); my $id = _make_id($s, $opts{'id_prefix'}); $subject_node->setAttribute('id', $id) if defined $id; $self->_process_subject($subjects->{$s}->[0], $subject_node, $prefixes); $self->_resource_heading($subjects->{$s}->[0]->subject, $subject_node, $subjects->{$s}, $prefixes); $self->_resource_classes($subjects->{$s}->[0]->subject, $subject_node, $subjects->{$s}, $prefixes); $self->_resource_statements($subjects->{$s}->[0]->subject, $subject_node, $subjects->{$s}, $prefixes, $opts{'interlink'}||0, $opts{'id_prefix'}, $model); $self->_resource_notes($subjects->{$s}->[0]->subject, $subject_node, $model, $opts{'notes_heading'}||'Notes', $opts{'notes'}) if defined $opts{'notes'}; } use Data::Dumper; Dumper($prefixes); if ($self->{'version'} == 1.1 and $self->{'prefix_attr'}) { $root_node->setAttribute('prefix', $prefixes->rdfa) if %$prefixes; } else { while (my ($p,$u) = each(%{$prefixes->to_hashref})) { $root_node->setNamespace($u, $p, 0); } } push @nodes, $root_node; return @nodes if wantarray; my $nodelist = XML::LibXML::NodeList->new; $nodelist->push(@nodes); return $nodelist; } sub _make_id { my ($ident, $prefix) = @_; if ($prefix =~ /^[A-Za-z][A-Za-z0-9\_\:\.\-]*$/) { $ident =~ s/([^A-Za-z0-9\_\:\.])/sprintf('-%x-',ord($1))/ge; return $prefix . $ident; } return undef; } sub _resource_heading { my ($self, $subject, $node, $statements, $prefixes) = @_; my $heading = $node->addNewChild(XHTML_NS, 'h3'); $heading->appendTextNode( $subject->is_resource ? $subject->uri : ('_:'.$subject->blank_identifier) ); $heading->setAttribute('class', $subject->is_resource ? 'resource' : 'blank' ); return $self; } sub _resource_classes { my ($self, $subject, $node, $statements, $prefixes) = @_; my @statements = sort { $a->predicate->uri cmp $b->predicate->uri or $a->object->uri cmp $b->object->uri } grep { $_->predicate->uri eq 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' and $_->object->is_resource } @$statements; return unless @statements; my $SPAN = $node->addNewChild(XHTML_NS, 'span'); $SPAN->setAttribute('class', 'rdf-type'); $SPAN->setAttribute('rel', $self->_make_curie('http://www.w3.org/1999/02/22-rdf-syntax-ns#type', $prefixes)); foreach my $st (@statements) { my $IMG = $SPAN->addNewChild(XHTML_NS, 'img'); $IMG->setAttribute('about', $st->object->uri); $IMG->setAttribute('alt', $st->object->uri); $IMG->setAttribute('src', $self->_img($st->object->uri)); $IMG->setAttribute('title', $st->object->uri); } return $self; } sub _resource_statements { my ($self, $subject, $node, $statements, $prefixes, $interlink, $id_prefix, $model) = @_; my @statements = sort { $a->predicate->uri cmp $b->predicate->uri or $a->object->as_ntriples cmp $b->object->as_ntriples } grep { $_->predicate->uri ne 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' or !$_->object->is_resource } @$statements; return unless @statements; my $DL = $node->addNewChild(XHTML_NS, 'dl'); my $current_property = undef; foreach my $st (@statements) { unless ($st->predicate->uri eq $current_property) { my $DT = $DL->addNewChild(XHTML_NS, 'dt'); $DT->setAttribute('title', $st->predicate->uri); $DT->appendTextNode($self->_make_curie($st->predicate->uri, $prefixes)); } $current_property = $st->predicate->uri; my $DD = $DL->addNewChild(XHTML_NS, 'dd'); if ($st->object->is_resource && $st->object->uri =~ /^javascript:/i) { $DD->setAttribute('class', 'resource'); my $A = $DD->addNewChild(XHTML_NS, 'span'); $A->setAttribute('rel', $self->_make_curie($st->predicate->uri, $prefixes)); $A->setAttribute('resource', $st->object->uri); $A->appendTextNode($st->object->uri); } elsif ($st->object->is_resource) { $DD->setAttribute('class', 'resource'); my $A = $DD->addNewChild(XHTML_NS, 'a'); $A->setAttribute('rel', $self->_make_curie($st->predicate->uri, $prefixes)); $A->setAttribute('href', $st->object->uri); $A->appendTextNode($st->object->uri); } elsif ($st->object->is_blank) { $DD->setAttribute('class', 'blank'); my $A = $DD->addNewChild(XHTML_NS, 'span'); $A->setAttribute('rel', $self->_make_curie($st->predicate->uri, $prefixes)); $A->setAttribute('resource', '[_:'.$st->object->blank_identifier.']'); $A->appendTextNode('_:'.$st->object->blank_identifier); } elsif ($st->object->is_literal && !$st->object->has_datatype) { $DD->setAttribute('property', $self->_make_curie($st->predicate->uri, $prefixes)); $DD->setAttribute('class', 'plain-literal'); $DD->setAttribute('xml:lang', $st->object->literal_value_language); $DD->appendTextNode(encode_utf8($st->object->literal_value)); } elsif ($self->{'safe_xml_literals'} && $st->object->is_literal && $st->object->has_datatype && $st->object->literal_datatype eq 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral') { $DD->setAttribute('property', $self->_make_curie($st->predicate->uri, $prefixes)); $DD->setAttribute('class', 'typed-literal datatype-xmlliteral'); $DD->setAttribute('datatype', $self->_make_curie($st->object->literal_datatype, $prefixes)); $DD->setAttribute('content', encode_utf8($st->object->literal_value)); $DD->addNewChild(XHTML_NS, 'pre')->addNewChild(XHTML_NS, 'code')->appendTextNode(encode_utf8($st->object->literal_value)); } elsif ($st->object->is_literal && $st->object->has_datatype && $st->object->literal_datatype eq 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral') { $DD->setAttribute('property', $self->_make_curie($st->predicate->uri, $prefixes)); $DD->setAttribute('class', 'typed-literal datatype-xmlliteral'); $DD->setAttribute('datatype', $self->_make_curie($st->object->literal_datatype, $prefixes)); $DD->appendWellBalancedChunk(encode_utf8($st->object->literal_value)); } elsif ($st->object->is_literal && $st->object->has_datatype) { $DD->setAttribute('property', $self->_make_curie($st->predicate->uri, $prefixes)); $DD->setAttribute('class', 'typed-literal'); $DD->setAttribute('datatype', $self->_make_curie($st->object->literal_datatype, $prefixes)); $DD->appendTextNode(encode_utf8($st->object->literal_value)); } if ($interlink && !$st->object->is_literal) { if ($model->count_statements($st->object, undef, undef)) { $DD->appendTextNode(' '); my $seealso = $DD->addNewChild(XHTML_NS, 'a'); $seealso->setAttribute('about', $st->object->is_resource ? $st->object->uri : '[_:'.$st->object->blank_identifier.']'); $seealso->setAttribute('rel', 'seeAlso'); $seealso->setAttribute('href', '#'._make_id($st->object->is_resource ? $st->object->uri : '_:'.$st->object->blank_identifier, $id_prefix)); $seealso->appendTextNode($interlink); } } } if ($interlink) { my $iter = $model->get_statements(undef, undef, $subject); if ($iter->peek) { my $seealsoDT = $DL->addNewChild(XHTML_NS, 'dt'); $seealsoDT->setAttribute('class', 'seeAlso'); $seealsoDT->appendTextNode($interlink); my $sadata = {}; while (my $sast = $iter->next) { my $sas = $sast->subject->is_resource ? $sast->subject->uri : '_:'.$sast->subject->blank_identifier; my $p = $self->_make_curie($sast->predicate->uri, $prefixes); $sadata->{$sas}->{$p} = $sast->predicate->uri; } my $seealso = $DL->addNewChild(XHTML_NS, 'dd'); $seealso->setAttribute('class', 'seeAlso'); my @keys = sort keys %$sadata; foreach my $sas (@keys) { my $span = $seealso->addNewChild(XHTML_NS, 'span'); $span->appendTextNode('is '); my @pkeys = sort keys %{$sadata->{$sas}}; foreach my $curie (@pkeys) { my $i = $span->addNewChild(XHTML_NS, 'i'); $i->appendTextNode($curie); $i->setAttribute(title => $sadata->{$sas}->{$curie}); $span->appendTextNode( $curie eq $pkeys[-1] ? '' : ', ' ); } $span->appendTextNode(' of '); my $a = $span->addNewChild(XHTML_NS, 'a'); $a->setAttribute('about', $sas !~ /^_:/ ? $sas : '[_:'.$sas.']'); $a->setAttribute('rel', 'seeAlso'); $a->setAttribute('href', '#'._make_id($sas, $id_prefix)); $a->appendTextNode($sas); $seealso->appendTextNode( $sas eq $keys[-1] ? '.' : '; ' ); } } } return $self; } sub _resource_notes { my ($self, $subject, $node, $model, $notes_heading, $notes) = @_; my @relevant; foreach my $note (@$notes) { push @relevant, $note if $note->is_relevant_to($subject); } if (@relevant) { my $heading = $node->addNewChild(XHTML_NS, 'h4'); $heading->appendTextNode($notes_heading || 'Notes'); my $list = $node->addNewChild(XHTML_NS, 'ul'); foreach my $note (@relevant) { $list->appendChild( $note->node(XHTML_NS, 'li') ); } } return $self; } sub _img { my ($self, $type) = @_; if ($type eq 'urn:x-rdf-rdfa-linter:internals:OpenGraphProtocolNode') { return 'data:image/png;charset=binary;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oFEBYGBzcdoOEAAALhSURBVCjPJdLfb4trHADw7/d53nbr2661X9ZV29mE/VLMYplwchwnmCziR7iSEHbpQnAj7lxJJBIhJELcSBAh50iErAcJ2wnLRrJstQXdL7Sbtmpv173P3vd9nq8Ln7/hg3/t6BJCAEB9Q/2Na1d8Xt1YmsuaSVsKn7u6Sl/lZjoAIiIAEJG2aJpSyi2dnceOH87I4UfD12fyw7aJ0mIu3fHqZbHa7s4VxwLuECJDRA0Bund3vXz1cmWCjMyzz33uz31e4zsCANcg2Kimtz8Ya32xv+VC1N/BkPM//tzW03MEArN3b/1X6vJ8G+VKYmWUwjEyC8A0TPa7hVjMlsUbKjf7S2r4m//7YVl6sHB56q1uzGJkPYkC1HdQrEulxrAiAkgwMaC5y5ac6kRrdbfm83kfj9yYGtK4BvUdKhFnjENmEhbnubQwEcdwTK3rVh96S0KxkanIG61o56fyQzNDnrU7VfPf0jQwO4luDy1kcVmI5mehba8Mr6Ovw2wuoY83xrW8mHEslf+KP9P4/l+emUQ9QBURUJJsAVzDj694bpqQQW6GZcykJpUgQMeC+TQgQ2GAcjA1BqBAOuDYkE+hJcAyQdoglaWVuYPIHV8l1bVTzRo18pRbJoRalFVEZJCbxtadMhyj3kuat1L5Sqo1f0ltuR6qaTRSH7C2BQpZNGbBsTgiWSYW81j8gQs5MjK44YAT9W9iHF0bQwcbti6kEqzvJrcFlAagrl1tOSq95RQI0qd+9uKqFmpWVVG+KXyIAWBb8FBT0+rYHpGbZv7l5KugQgYKGSzmMdhITduULUDSUlfzmYf34khERJQujj4YPTk+mB154jHm0OUh7oKlAgKDtr2yPCpe34YTPacGBt4hEf1umBMTzycvJr68zk2UZpPMsdBbTsEWq2pF6a7m02ay7uy587Zto1Lqd10AcJSVLo6OZ3u/L35ylPC5qiL+9rbQvn8ePr9z9346lXKk/AUjmnS/afx+BwAAAABJRU5ErkJggg=='; } my $icons = { 'http://bblfish.net/work/atom-owl/2006-06-06/#Entry' => 'page_white_link', 'http://bblfish.net/work/atom-owl/2006-06-06/#Feed' => 'feed', 'http://commontag.org/ns#AuthorTag' => 'tag_green', 'http://commontag.org/ns#AutoTag' => 'tag_red', 'http://commontag.org/ns#ReaderTag' => 'tag_yellow', 'http://commontag.org/ns#Tag' => 'tag_blue', 'http://ontologi.es/doap-bugs#Bug' => 'bug', 'http://purl.org/goodrelations/v1#PriceSpecification' => 'money', 'http://purl.org/NET/book/vocab#Book' => 'book', 'http://purl.org/NET/c4dm/event.owl#Event' => 'date', 'http://purl.org/ontology/bibo/Book' => 'book', 'http://purl.org/rss/1.0/channel' => 'feed', 'http://purl.org/rss/1.0/item' => 'page_white_link' , 'http://purl.org/stuff/rev#Review' => 'award_star_gold_1', 'http://rdf.data-vocabulary.org/#Organization' => 'chart_organisation', 'http://rdf.data-vocabulary.org/#Person' => 'user', 'http://rdf.data-vocabulary.org/#Review-aggregate' => 'award_star_add', 'http://rdf.data-vocabulary.org/#Review' => 'award_star_gold_1', 'http://usefulinc.com/ns/doap#Project' => 'application_double', 'http://usefulinc.com/ns/doap#Version' => 'application_lightning', 'http://www.holygoat.co.uk/owl/redwood/0.1/tags/Tagging' => 'tag_blue_add', 'http://www.holygoat.co.uk/owl/redwood/0.1/tags/Tag' => 'tag_blue', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#Property' => 'arrow_right', 'http://www.w3.org/2000/01/rdf-schema#Class' => 'cog', 'http://www.w3.org/2002/12/cal/ical#Vcalendar' => 'calendar', 'http://www.w3.org/2002/12/cal/ical#Vevent' => 'date', 'http://www.w3.org/2002/07/owl#AnnotationProperty' => 'arrow_right', 'http://www.w3.org/2002/07/owl#AsymmetricProperty' => 'arrow_right', 'http://www.w3.org/2002/07/owl#Class' => 'cog', 'http://www.w3.org/2002/07/owl#DatatypeProperty' => 'arrow_right', 'http://www.w3.org/2002/07/owl#DeprecatedProperty' => 'arrow_right', 'http://www.w3.org/2002/07/owl#FunctionalProperty' => 'arrow_right', 'http://www.w3.org/2002/07/owl#InverseFunctionalProperty' => 'arrow_right', 'http://www.w3.org/2002/07/owl#IrreflexiveProperty' => 'arrow_right', 'http://www.w3.org/2002/07/owl#ObjectProperty' => 'arrow_right', 'http://www.w3.org/2002/07/owl#OntologyProperty' => 'arrow_right', 'http://www.w3.org/2002/07/owl#ReflexiveProperty' => 'arrow_right', 'http://www.w3.org/2002/07/owl#SymmetricProperty' => 'arrow_right', 'http://www.w3.org/2002/07/owl#TransitiveProperty' => 'arrow_right', 'http://www.w3.org/2003/01/geo/wgs84_pos#Point' => 'world', 'http://www.w3.org/2003/01/geo/wgs84_pos#SpatialThing' => 'world', 'http://www.w3.org/2004/02/skos/core#Concept' => 'brick', 'http://www.w3.org/2004/02/skos/core#ConceptScheme' => 'bricks', 'http://www.w3.org/2006/vcard/ns#Address' => 'house', 'http://www.w3.org/2006/vcard/ns#Location' => 'world', 'http://www.w3.org/2006/vcard/ns#Vcard' => 'vcard', 'http://www.w3.org/ns/auth/rsa#RSAPublicKey' => 'key', 'http://xmlns.com/foaf/0.1/Agent' => 'user_gray', 'http://xmlns.com/foaf/0.1/Document' => 'page_white_text', 'http://xmlns.com/foaf/0.1/Group' => 'group', 'http://xmlns.com/foaf/0.1/Image' => 'image', 'http://xmlns.com/foaf/0.1/OnlineAccount' => 'status_online', 'http://xmlns.com/foaf/0.1/Organization' => 'chart_organisation', 'http://xmlns.com/foaf/0.1/Person' => 'user_green', 'http://xmlns.com/foaf/0.1/PersonalProfileDocument' => 'page_green', }; return Icon::FamFamFam::Silk->new($icons->{$type}||'asterisk_yellow')->uri; } 1;