Skip to content

Commit

Permalink
Initial import of Treetop-based N3 parser
Browse files Browse the repository at this point in the history
  • Loading branch information
Patrick Sinclair committed Jul 25, 2008
1 parent 41dfcf8 commit 85469ff
Show file tree
Hide file tree
Showing 19 changed files with 424 additions and 0 deletions.
125 changes: 125 additions & 0 deletions lib/rena/n3_grammer.treetop
@@ -0,0 +1,125 @@
grammar N3Grammer
rule document
statements
end

rule statements
(space / (statement / directive) space* ('.' space*)? )*
end

rule statement
subject space+ property_list
end

rule subject
node
end

rule verb
">-" prop "->" # has xxx of
/ "<-" prop "<-" # is xxx of
# / # / operator # has operator:xxx of??? NOT IMPLMENTED
/ prop # has xxx of -- shorthand
# / "has" prop # has xxx of
# / "is" prop "of" # is xxx of
/ "a" # has rdf:type of
# / "=" # has daml:equivaent of
end

rule prop
node
end

rule node
uri_ref2 / anonnode / 'this'
end

rule anonnode
"[" space* property_list space* "]" # something which ...
/ "{" statementlist "}" # the statementlist itself as a resource
/ "(" nodelist ")" {
def anonnode; true; end
}
end

rule property_list
verb space+ object_list space* ";" space+ property_list
/ verb space+ object_list
/ ":-" anonnode #to allow two anonymous forms to be given eg [ a :Truth; :- { :sky :color :blue } ] )
/ ":-" anonnode ";" property_list
/ '.'
end

rule object_list
object "," space* object_list / object
end

rule directive
'@prefix' space+ nprefix:nprefix? ':' space+ uri_ref2:uri_ref2 {
def directive; true; end
}
end

rule uri_ref2
qname / "<" uri:URI_Reference ">"
end

rule qname
nprefix ":" localname / ':' localname
end

rule object
subject
/ string1 # " constant-value-with-escaping "
/ string2 # """ constant value with escaping including single or double occurences of quotes and/or newlines """
end

rule localname
fragid
end

rule URI_Reference
[^{}<>]*
end

rule nprefix
((alpha / "_") alphanumeric*)
end

rule fragid
alpha alphanumeric*
end

rule alpha
[a-zA-Z]
end

rule alphanumeric
alpha / [0-9] / "_"
end

rule space
[ \t\n\r]+ / comment
end

rule comment
'#' (![\n\r] .)*
end

rule string1
'"' string1_char+ '"'
end

rule string1_char
!["] .
end

rule string2
'"""' string2_char* '"""'
end

rule string2_char
!'"""' . # something like this; need to think about it some more
end

end
163 changes: 163 additions & 0 deletions lib/rena/n3parser.rb
@@ -0,0 +1,163 @@
require 'rena/graph'
require 'treetop'

Treetop.load(File.join(File.dirname(__FILE__), "n3_grammer"))

class N3Parser
attr_accessor :graph

def initialize(n3_str, uri=nil)
@uri = Addressable::URI.parse(uri) unless uri.nil?
parser = N3GrammerParser.new
document = parser.parse(n3_str)
if document
@graph = Graph.new
process_directives(document)
process_statements(document)
else
parser.terminal_failures.each do |tf|
puts "Expected #{tf.expected_string.inspect} (#{tf.index})- '#{string[tf.index,10].inspect}'"
end
end
end

protected

def process_directives(document)
directives = document.elements.find_all { |e| e.elements.first.respond_to? :directive }
directives.map! { |d| d.elements.first }
directives.each { |d| namespace(d.uri_ref2.uri.text_value, d.nprefix.text_value) }
end

def namespace(uri, short)
short = '__local__' if short == ''
@graph.namespace(uri, short)
end

def process_statements(document)
subjects = document.elements.find_all { |e| e.elements.first.respond_to? :subject }
subjects.map! { |s| s.elements.first }
subjects.each do |s|
subject = process_node(s.subject)
properties = process_properties(s.property_list)
properties.each do |p|
predicate = process_verb(p.verb)
objects = process_objects(p.object_list)
objects.each { |object| triple(subject, predicate, object) }
end
end
end

def triple(subject, predicate, object)
@graph.add_triple(subject, predicate, object)
end

def process_anonnode(anonnode)
bnode = BNode.new
properties = process_properties(anonnode.property_list)
properties.each do |p|
predicate = process_node(p.verb)
objects = process_objects(p.object_list)
objects.each { |object| triple(bnode, predicate, object) }
end
bnode
end

def process_verb(verb)
return URIRef.new('http://www.w3.org/1999/02/22-rdf-syntax-ns#type') if (verb.text_value=='a')
return process_node(verb)
end

def process_node(node)
if (node.respond_to? :uri)
URIRef.new(node.uri.text_value)
else
prefix = (node.respond_to? :nprefix) ? node.nprefix.text_value : nil
localname = node.localname.text_value
build_uri(prefix, localname)
end
end

def process_properties(properties)
result = []
result << properties if (properties.respond_to? :verb)
result << process_properties(properties.property_list) if (properties.respond_to? :property_list)
result.flatten
end

def process_objects(objects)
result = []
if (objects.respond_to? :object)
result << process_object(objects.object)
else
result << process_object(objects)
end
result << process_objects(objects.object_list) if (objects.respond_to? :object_list)
result.flatten
end

def process_object(object)
if (object.respond_to? :localname or object.respond_to? :uri)
process_node(object)
elsif (object.respond_to? :property_list)
process_anonnode(object)
else
Literal.new(object.elements[1].text_value)
end
end

# pp objects.object
# if (objects.respond_to? :object and objects.object.respond_to? :anonnode)
# pp 'foo'
# elsif (objects.respond_to? :object and objects.respond_to? :object_list)
# result << process_node(objects.object)
# result << process_objects(objects.object_list)
# elsif (objects.respond_to? :localname)
# result << process_node(objects)
# elsif (objects.respond_to? :uri)
# result << URIRef.new(objects.uri.text_value)
# else
# result << Literal.new(objects.elements[1].text_value)
# end
# result.flatten
# end

def build_uri(prefix, localname)
prefix = '__local__' if prefix.nil?
if (prefix=='_')
BNode.new(localname)
else
@graph.nsbinding[prefix].send(localname)
end
end


end

# # string = %[
# # <rdf:RDF xmlns="http://example.org/#"
# # xmlns:log="http://www.w3.org/2000/10/swap/log#"
# # xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
# #
# # <rdf:Description rdf:about="http://example.org/#Subject">
# # <predicate rdf:resource="http://example.org/#ObjectP"/>
# # </rdf:Description>
# # </rdf:RDF>
# # ]
# # parser = RdfXmlParser.new(string)
# # puts parser.graph.to_ntriples
#
# [ 'simple-01.n3',
# 'simple-02.n3',
# 'simple-03.n3',
# 'simple-04.n3',
# 'simple-05.n3',
# 'simple-06.n3',
# 'simple-07.n3',
# 'on_now-01.n3',
# ].each do |f|
# string = File.read("test/n3p_tests/#{f}")
# parser = N3Parser.new(string)
# puts f
# puts parser.graph.to_ntriples
# end
28 changes: 28 additions & 0 deletions test/n3_tests/misc/on_now-01.n3
@@ -0,0 +1,28 @@
@prefix dc: <http://purl.org/dc/elements/1.1/>.
@prefix po: <http://purl.org/ontology/po/>.
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
_:broadcast
a po:Broadcast;
po:schedule_date """2008-06-24T12:00:00Z""";
po:broadcast_of _:version;
po:broadcast_on <http://www.bbc.co.uk/programmes/service/6music>;
.
_:version
a po:Version;
.
<http://www.bbc.co.uk/programmes/b0072l93>
dc:title """Nemone""";
a po:Brand;
.
<http://www.bbc.co.uk/programmes/b00c735d>
a po:Episode;
po:episode <http://www.bbc.co.uk/programmes/b0072l93>;
po:version _:version;
po:long_synopsis """Actor and comedian Rhys Darby chats to Nemone.""";
dc:title """Nemone""";
po:synopsis """Actor and comedian Rhys Darby chats to Nemone.""";
.
<http://www.bbc.co.uk/programmes/service/6music>
a po:Service;
dc:title """BBC 6 Music""";
.
15 changes: 15 additions & 0 deletions test/n3_tests/misc/on_now-01.nt
@@ -0,0 +1,15 @@
_:broadcast <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://purl.org/ontology/po/Broadcast> .
_:broadcast <http://purl.org/ontology/po/schedule_date> "2008-06-24T12:00:00Z" .
_:broadcast <http://purl.org/ontology/po/broadcast_of> _:version .
_:broadcast <http://purl.org/ontology/po/broadcast_on> <http://www.bbc.co.uk/programmes/service/6music> .
_:version <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://purl.org/ontology/po/Version> .
<http://www.bbc.co.uk/programmes/b0072l93> <http://purl.org/dc/elements/1.1/title> "Nemone" .
<http://www.bbc.co.uk/programmes/b0072l93> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://purl.org/ontology/po/Brand> .
<http://www.bbc.co.uk/programmes/b00c735d> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://purl.org/ontology/po/Episode> .
<http://www.bbc.co.uk/programmes/b00c735d> <http://purl.org/ontology/po/episode> <http://www.bbc.co.uk/programmes/b0072l93> .
<http://www.bbc.co.uk/programmes/b00c735d> <http://purl.org/ontology/po/version> _:version .
<http://www.bbc.co.uk/programmes/b00c735d> <http://purl.org/ontology/po/long_synopsis> "Actor and comedian Rhys Darby chats to Nemone." .
<http://www.bbc.co.uk/programmes/b00c735d> <http://purl.org/dc/elements/1.1/title> "Nemone" .
<http://www.bbc.co.uk/programmes/b00c735d> <http://purl.org/ontology/po/synopsis> "Actor and comedian Rhys Darby chats to Nemone." .
<http://www.bbc.co.uk/programmes/service/6music> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://purl.org/ontology/po/Service> .
<http://www.bbc.co.uk/programmes/service/6music> <http://purl.org/dc/elements/1.1/title> "BBC 6 Music" .
1 change: 1 addition & 0 deletions test/n3_tests/n3p/simple-01.n3
@@ -0,0 +1 @@
# simple-01.n3 - Empty file
Empty file added test/n3_tests/n3p/simple-01.nt
Empty file.
4 changes: 4 additions & 0 deletions test/n3_tests/n3p/simple-02.n3
@@ -0,0 +1,4 @@
# simple-02.n3 - Prefix and Keywords

@prefix : <#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
Empty file added test/n3_tests/n3p/simple-02.nt
Empty file.
5 changes: 5 additions & 0 deletions test/n3_tests/n3p/simple-03.n3
@@ -0,0 +1,5 @@
# simple-03.n3 - Simple triple

@prefix foaf: <http://xmlns.com/foaf/0.1/> .

_:Sean foaf:name "Sean B. Palmer" .
1 change: 1 addition & 0 deletions test/n3_tests/n3p/simple-03.nt
@@ -0,0 +1 @@
_:Sean <http://xmlns.com/foaf/0.1/name> "Sean B. Palmer" .
6 changes: 6 additions & 0 deletions test/n3_tests/n3p/simple-04.n3
@@ -0,0 +1,6 @@
# simple-04.n3 - Multiple objects

@prefix : <http://example.org/#> .

:Subject :predicate :ObjectP, :ObjectQ,
:ObjectR .
3 changes: 3 additions & 0 deletions test/n3_tests/n3p/simple-04.nt
@@ -0,0 +1,3 @@
<http://example.org/#Subject> <http://example.org/#predicate> <http://example.org/#ObjectP> .
<http://example.org/#Subject> <http://example.org/#predicate> <http://example.org/#ObjectQ> .
<http://example.org/#Subject> <http://example.org/#predicate> <http://example.org/#ObjectR> .
7 changes: 7 additions & 0 deletions test/n3_tests/n3p/simple-05.n3
@@ -0,0 +1,7 @@
# simple-05.n3 - Popairs

@prefix : <#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .

_:Sean foaf:name "Sean B. Palmer";
foaf:homepage <http://inamidst.com/sbp/> .
2 changes: 2 additions & 0 deletions test/n3_tests/n3p/simple-05.nt
@@ -0,0 +1,2 @@
_:Sean <http://xmlns.com/foaf/0.1/name> "Sean B. Palmer" .
_:Sean <http://xmlns.com/foaf/0.1/homepage> <http://inamidst.com/sbp/> .
6 changes: 6 additions & 0 deletions test/n3_tests/n3p/simple-06.n3
@@ -0,0 +1,6 @@
# simple-06.n3 - Popairs and multiple objects

@prefix : <http://example.org/#> .

:Subject :predicateOne :ObjectA, :ObjectB;
:predicateTwo :ObjectC, :ObjectD .
4 changes: 4 additions & 0 deletions test/n3_tests/n3p/simple-06.nt
@@ -0,0 +1,4 @@
<http://example.org/#Subject> <http://example.org/#predicateOne> <http://example.org/#ObjectA> .
<http://example.org/#Subject> <http://example.org/#predicateOne> <http://example.org/#ObjectB> .
<http://example.org/#Subject> <http://example.org/#predicateTwo> <http://example.org/#ObjectC> .
<http://example.org/#Subject> <http://example.org/#predicateTwo> <http://example.org/#ObjectD> .
7 changes: 7 additions & 0 deletions test/n3_tests/n3p/simple-07.n3
@@ -0,0 +1,7 @@
# simple-07.n3 - Popairs and multiple objects, mixed types

@prefix : <http://example.org/#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .

:Subject :predicateOne :ObjectP, <http://example.org/path#ObjectQ>;
:predicateTwo [ foaf:nick "spiggot" ], "ObjectR", _:ObjectS .
6 changes: 6 additions & 0 deletions test/n3_tests/n3p/simple-07.nt
@@ -0,0 +1,6 @@
<http://example.org/#Subject> <http://example.org/#predicateOne> <http://example.org/#ObjectP> .
<http://example.org/#Subject> <http://example.org/#predicateOne> <http://example.org/path#ObjectQ> .
<http://example.org/#Subject> <http://example.org/#predicateTwo> _:node1 .
_:node1 <http://xmlns.com/foaf/0.1/nick> "spiggot" .
<http://example.org/#Subject> <http://example.org/#predicateTwo> "ObjectR" .
<http://example.org/#Subject> <http://example.org/#predicateTwo> _:ObjectS .

0 comments on commit 85469ff

Please sign in to comment.