1. Toby Inkster
  2. p5-rdf-shortcuts

Commits

Toby Inkster  committed c867316

Parsing - needs cleaning up, but at least it works.

  • Participants
  • Parent commits e1a4572
  • Branches RDF-Shortcuts

Comments (0)

Files changed (4)

File lib/RDF/Shortcuts/Node.pm

View file
 
 use base qw[Exporter];
 use Scalar::Util qw[blessed];
-use Sub::Name qw[subname];
 
 our (@EXPORT, @EXPORT_OK, %EXPORT_TAGS, %GOT);
 BEGIN

File lib/RDF/Shortcuts/Parse.pm

View file
-1;
+package RDF::Shortcuts::Parse;
+
+use 5.010;
+use common::sense;
+use constant { FALSE => 0, TRUE => 1 };
+use utf8;
+
+BEGIN {
+	$RDF::Shortcuts::Parse::AUTHORITY = 'cpan:TOBYINK';
+	$RDF::Shortcuts::Parse::VERSION   = '0.001';
+}
+
+use base qw[Exporter];
+use Scalar::Util qw[blessed];
+
+our (@EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+BEGIN
+{
+	@EXPORT    = qw[];
+	@EXPORT_OK = qw[parse rdf_parse];
+}
+
+use LWP::UserAgent;
+use RDF::RDFa::Parser '1.093';
+use RDF::Shortcuts::Node qw(node);
+use RDF::Trine;
+use URI;
+use URI::file;
+
+our $Has;
+BEGIN
+{
+	$Has = {};
+	foreach my $package (qw(XML::Atom::OWL RDF::TriN3
+		HTTP::Link::Parser XRD::Parser RDF::RDFa::Generator))
+	{
+		$@ = undef;
+		my $r = eval "use $package; ${package}->VERSION;";
+		$Has->{$package} = 1 unless $@;
+		if ($r && $Has->{$package})
+		{
+			$Has->{$package} = $r;
+		}
+	}
+}
+
+sub parse
+{
+	my $input = shift;
+	my %args  = @_;
+
+	my $model   = $args{'model'} || RDF::Trine::Model->temporary_model;
+	my $context = node($args{'context'}, passthrough_undef=>1);
+	my $type    = $args{'type'};
+	my $base    = $args{'base'};
+
+	# If input is undef, return empty model (or provided model if any)
+	return $model unless defined $input;
+
+	# If input is an object with a TO_RDF method, use the output of
+	# that method instead. (This is analagous to the TO_JSON method
+	# used by the JSON module.
+	if (blessed($input) && $input->can('TO_RDF'))
+	{
+		return rdf_parse($input->TO_RDF, %args);
+	}
+
+	# If the input is a hashref, then we'll treat it as an RDF/JSON-like
+	# structure.
+	if (ref $input eq 'HASH')
+	{
+		$model->add_hashref($input);
+		return $model;
+	}
+
+	# If input is a string that conforms to RDF::Trine::Store::new_with_string
+	# then call that constructor and set input to be the store instead.
+	eval
+	{
+		if ($input =~ /^([A-Za-z0-9_:]+)(\;[^\r\n]*)?$/
+			  && "RDF::Trine::Store::$1"->isa("RDF::Trine::Store"))
+		{
+			my $store = RDF::Trine::Store->new_with_string($input);
+			if ($store)
+			{
+				$input = $store;
+			}
+			else
+			{
+				warn "Input looked like a Store connection string, but didn't work.";
+			}
+		}
+	};
+	
+	# If the input is a store, then make a model of it.
+	if (blessed($input) && $input->isa('RDF::Trine::Store'))
+	{
+		$input = RDF::Trine::Model->new($input);
+	}
+
+	# If the input is a model, then make a stream of it.
+	if (blessed($input) && $input->isa('RDF::Trine::Model'))
+	{
+		if ($context)
+		{
+			$input = $input->get_statements(undef,undef,undef);
+		}
+		else
+		{
+			$input = $input->get_statements(undef,undef,undef,undef);
+		}
+	}
+
+	# If the input is a stream, then deal with it and return the
+	# result.
+	if (blessed($input) && $input->isa('RDF::Trine::Iterator'))
+	{
+		while (my $st = $input->next)
+		{
+			$model->add_statement($st, $context);
+		}
+		return $model;
+	}
+
+	# If the input is a filename, then open the file and treat the filehandle as the input
+	if ($input !~ /[\r\n\t]/ and -e $input)
+	{
+		my $fn = $input;
+		$input = undef;
+		$base  = URI::file->new_abs($fn)->as_string;
+		open $input, $fn;
+	}
+
+	# If the input is a file handle, then treat the contents as input
+	if (ref $input eq 'GLOB')
+	{
+		local $/;
+		local $_ = <$input>;
+		$input->close;
+		$input = $_;
+	}
+
+	# If the input is a URI then dereference it to get an HTTP::Message.
+	elsif (blessed($input) && $input->isa('URI')
+	or     $input =~ m'^(https?|ftp|file):\S+$')
+	{
+		my $accept = 'application/rdf+xml, text/turtle, application/x-trig, text/x-nquads, application/json;q=0.1, application/xhtml+xml;q=0.1';
+		$accept .= ', application/atom+xml;q=0.2' if $Has->{'XML::Atom::OWL'};
+		$accept .= ', application/xrd+xml;q=0.2'  if $Has->{'XRD::Parser'};
+		
+		my $ua = LWP::UserAgent->new(parse_head=>0);
+		$ua->agent(sprintf('%s/%s ', __PACKAGE__, __PACKAGE__->VERSION));
+		$ua->default_header("Accept" => $accept);
+
+		$input = $ua->get("$input");
+	}
+
+	# If the input is an HTTP::Message, then use the body as input.
+	if (blessed($input) && $input->isa('HTTP::Message'))
+	{		
+		if ($Has->{'HTTP::Link::Parser'} && !$args{'no_http_links'})
+		{
+			HTTP::Link::Parser::parse_links_into_model($input, $model);
+		}
+		
+		$type ||= $input->content_type;
+		$base ||= $input->base;
+		$input  = $input->decoded_content;
+	}
+
+	# If the type parameter is a real Internet Media Type, then we can
+	# check to see if it's a type supported by RDF::RDFa::Parser,
+	# and if so, parse the input and return the result.
+	if ($type =~ m#/#)
+	{
+		my $host = RDF::RDFa::Parser::Config->host_from_media_type($type);
+		if (defined $host and $host ne 'xml')
+		{
+			my $config = RDF::RDFa::Parser::Config->new($host);
+			my $parser = RDF::RDFa::Parser->new($input, $base, $config, $model->_store);
+			$parser->consume;
+			return $model;
+		}
+	}
+	
+	# Alternatively, if the type parameter is some string that we
+	# recognise and know RDF::RDFa::Parser can deal with, then let it.
+	if (($type||'') =~ m'atom'i or ((!defined $type) and $input =~ m'http://www.w3.org/2005/Atom'))
+	{
+		my $opts = RDF::RDFa::Parser::Config->new('atom', '1.1', atom_parser=>1);
+		my $p = RDF::RDFa::Parser->new($input, $base, $opts, $model->_store);
+		$p->consume;
+		return $model;
+	}
+	elsif (($type||'') =~ m'svg'i)
+	{
+		my $opts = RDF::RDFa::Parser::Config->new('svg', '1.1', atom_parser=>1);
+		my $p = RDF::RDFa::Parser->new($input, $base, $opts, $model->_store);
+		$p->consume;
+		return $model;
+	}
+	elsif (($type||'') =~ m'(xhtml|rdfa)'i)
+	{
+		my $opts = RDF::RDFa::Parser::Config->new('xhtml', '1.1');
+		my $p = RDF::RDFa::Parser->new($input, $base, $opts, $model->_store);
+		$p->consume;
+		return $model;
+	}
+	elsif (($type||'') =~ m'html\s*4'i)
+	{
+		my $opts = RDF::RDFa::Parser::Config->new('html4', '1.1');
+		my $p = RDF::RDFa::Parser->new($input, $base, $opts, $model->_store);
+		$p->consume;
+		return $model;
+	}
+	elsif (($type||'') =~ m'html'i)
+	{
+		my $opts = RDF::RDFa::Parser::Config->new('html5', '1.1');
+		my $p = RDF::RDFa::Parser->new($input, $base, $opts, $model->_store);
+		$p->consume;
+		return $model;
+	}
+	elsif (($type||'') =~ m'opendoc'i)
+	{
+		my $opts = RDF::RDFa::Parser::Config->new('opendocument-zip', '1.1');
+		my $p = RDF::RDFa::Parser->new($input, $base, $opts, $model->_store);
+		$p->consume;
+		return $model;
+	}
+	
+	# If XRD::Parser is installed and the input seems to be XRD, then let
+	# it do its trick.
+	if ($Has->{'XRD::Parser'}
+	and (($type||'') =~ m'xrd'i or ((!defined $type) and $input =~ m'http://docs.oasis-open.org/ns/xri/xrd-1.0')))
+	{
+		my $p = XRD::Parser->new($input, $base, undef, $model->_store);
+		$p->consume;
+		return $model;
+	}
+
+	# Otherwise, hand the string over to RDF::Trine::Parser according
+	# to the type provided.
+	my $parser;
+	if (defined $type)
+	{
+		if ($type =~ /rdf.?xml/i)
+		{
+			$parser = RDF::Trine::Parser->new('RDFXML');
+		}
+		elsif ($type =~ /json/i)
+		{
+			$parser = RDF::Trine::Parser->new('RDFJSON');
+		}
+		elsif ($type =~ /n3/i)
+		{
+			$parser = $Has->{'RDF::TriN3'} ?
+				RDF::Trine::Parser::Notation3->new() :
+				RDF::Trine::Parser->new('Turtle');
+		}
+		elsif ($type =~ /turtle/i)
+		{
+			$parser = RDF::Trine::Parser->new('Turtle');
+		}
+		elsif ($type =~ /ntriple/i)
+		{
+			$parser = RDF::Trine::Parser->new('NTriples');
+		}
+		elsif ($type =~ /nquad/i)
+		{
+			$parser = RDF::Trine::Parser->new('NQuads');
+		}
+		elsif ($type =~ /trig/i)
+		{
+			$parser = RDF::Trine::Parser->new('TriG');
+		}
+		else
+		{
+			eval { $parser = RDF::Trine::Parser->new($type); }
+		}
+	}
+	
+	# The type provided wasn't enough, let's try to sniff the content type.
+	unless ($parser)
+	{
+		my $tester = substr($input, 0, 512);
+		if ($tester =~ /^\s*\{/s)
+		{
+			$parser = RDF::Trine::Parser->new('RDFJSON');
+		}
+		elsif ($tester =~ /<rdf:RDF/)
+		{
+			$parser = RDF::Trine::Parser->new('RDFXML');
+		}
+		elsif ($tester =~ /<html/ or $tester =~ m'xmlns="http://www.w3.org/1999/xhtml"')
+		{
+			my $opts = RDF::RDFa::Parser::Config->new('html5', '1.1');
+			my $p = RDF::RDFa::Parser->new($input, $base, $opts, $model->_store);
+			$p->consume;
+			return $model;
+		}
+		elsif ($tester =~ /<http/)
+		{
+			$parser = $Has->{'RDF::TriN3'} ?
+				RDF::Trine::Parser::Notation3->new() :
+				RDF::Trine::Parser->new('Turtle');
+		}
+		elsif ($tester =~ /\@prefix/)
+		{
+			$parser = $Has->{'RDF::TriN3'} ?
+				RDF::Trine::Parser::Notation3->new() :
+				RDF::Trine::Parser->new('Turtle');
+		}
+		else
+		{
+			$parser = RDF::Trine::Parser->new('RDFXML');
+		}
+	}
+
+	if (defined $context)
+	{
+		$parser->parse_into_model($base, $input, $model, context=>$context);
+	}
+	else
+	{
+		$parser->parse_into_model($base, $input, $model);
+	}
+
+	return $model;
+}
+
+*rdf_parse = \&parse;
+
+TRUE;#DAT
+
+__END__
+

File lib/RDF/Shortcuts/Pattern.pm

View file
 {
 	@EXPORT    = qw[];
 	@EXPORT_OK = qw[pattern rdf_pattern];
-	
-	foreach my $f (@EXPORT_OK)
-	{
-		no strict 'refs';
-		*{"RDF::Shortcuts::$f"} = subname "RDF::Shortcuts::$f" => \&$f;
-	}
 }
 
 use RDF::Shortcuts::Statement qw(statement);

File lib/RDF/Shortcuts/Statement.pm

View file
 
 use base qw[Exporter];
 use Scalar::Util qw[blessed];
-use Sub::Name qw[subname];
 
 our (@EXPORT, @EXPORT_OK, %EXPORT_TAGS);
 BEGIN
 {
 	@EXPORT    = qw[];
 	@EXPORT_OK = qw[statement quad triple rdf_statement rdf_quad rdf_triple];
-
-	foreach my $f (@EXPORT_OK)
-	{
-		no strict 'refs';
-		*{"RDF::Shortcuts::$f"} = subname "RDF::Shortcuts::$f" => \&$f;
-	}
 }
 
 use RDF::Shortcuts::Node   qw(node);