diff --git a/etc/turtle.bnf b/etc/turtle.bnf
index 81d5f1e..3faf101 100644
--- a/etc/turtle.bnf
+++ b/etc/turtle.bnf
@@ -26,7 +26,7 @@ iri ::= IRIREF | PrefixedName
PrefixedName ::= PNAME_LN | PNAME_NS
BlankNode ::= BLANK_NODE_LABEL | ANON
reifier ::= '~' (iri | BlankNode)?
-reifiedTriple ::= '<<' (subject | reifiedTriple) predicate object reifier* '>>'
+reifiedTriple ::= '<<' (subject | reifiedTriple) predicate object reifier? '>>'
tripleTerm ::= '<<(' ttSubject predicate ttObject ')>>'
ttSubject ::= iri | BlankNode
ttObject ::= iri | BlankNode | literal | tripleTerm
diff --git a/lib/rdf/turtle/reader.rb b/lib/rdf/turtle/reader.rb
index b269fcb..a23388a 100644
--- a/lib/rdf/turtle/reader.rb
+++ b/lib/rdf/turtle/reader.rb
@@ -451,7 +451,7 @@ def read_object(subject = nil, predicate = nil)
##
# Read reifiedTriple
#
- # reifiedTriple ::= '<<' (subject | reifiedTriple) predicate object reifier* '>>'
+ # reifiedTriple ::= '<<' (subject | reifiedTriple) predicate object reifier? '>>'
#
# @return [RDF::Term]
def read_reifiedTriple
@@ -537,7 +537,7 @@ def read_ttObject(subject = nil, predicate = nil)
##
# Read an annotation on a triple
#
- # annotation := (reifier | '{|' predicateObjectList '|}')*
+ # annotation := (reifier | annotationBlock)*
#
# The `reifier` becomes the identifier for a subsequent annotation block (if it exists). If there is no reifier, then a blank node is created.
def read_annotation(subject, predicate, object)
@@ -548,7 +548,7 @@ def read_annotation(subject, predicate, object)
while %w(~ {|).include? @lexer.first.to_s
if @lexer.first === '~'
- prod(:annotation, %(~})) do
+ prod(:annotation, %(~)) do
@lexer.shift # eat '~'
# Emit any pending reifiedTriple if there was no annotation block
add_statement('annotation', RDF::Statement(id, RDF.reifies, tt)) if id
diff --git a/lib/rdf/turtle/writer.rb b/lib/rdf/turtle/writer.rb
index 680899e..ac35916 100644
--- a/lib/rdf/turtle/writer.rb
+++ b/lib/rdf/turtle/writer.rb
@@ -335,7 +335,7 @@ def format_node(node, **options)
# @param [Hash{Symbol => Object}] options
# @return [String]
def format_tripleTerm(statement, **options)
- log_debug("rdfstar") {"#{statement.to_ntriples}"}
+ log_debug("tripleTerm") {"#{statement.to_ntriples}"}
"<<(%s %s %s)>>" % statement.to_a.map { |value| format_term(value, **options) }
end
@@ -443,7 +443,7 @@ def preprocess_statement(statement, as_subject: true)
statement.to_a.each {|t| @in_triple_term[t] = true}
end
- # If it fits, allow this to be rendered as a reification
+ # If it fits, allow this to be rendered as a reifiedTriple
if statement.object.statement? && statement.predicate == RDF.reifies
@reification[statement.subject] ||= []
@reification[statement.subject] << statement.object unless
@@ -483,7 +483,7 @@ def reset
@serialized = {}
@subjects = {}
@reification = {}
- @as_reification = {}
+ @as_reifiedTriple = {}
@in_triple_term = {}
end
@@ -572,7 +572,7 @@ def collection(node, position)
def blankNodePropertyList?(resource, position)
!resource.statement? && resource.node? &&
!collection?(resource) &&
- !reification?(resource, position) &&
+ !reifiedTriple?(resource, position) &&
!in_triple_term?(resource) &&
(!is_done?(resource) || position == :subject) &&
ref_count(resource) == (position == :object ? 1 : 0)
@@ -590,33 +590,34 @@ def blankNodePropertyList(resource, position)
true
end
- # Is this a reification?
- def reification?(resource, position)
+ # Is this a reifiedTriple?
+ def reifiedTriple?(resource, position)
@reification.key?(resource) &&
(position == :subject ? (prop_count(resource) > 0) : (prop_count(resource) == 0))
end
- # Render a reification
- def reification(resource, position)
- return false unless reification?(resource, position)
+ # Render a reifiedTriple
+ def reifiedTriple(resource, position)
+ return false unless reifiedTriple?(resource, position)
write_id = resource.iri? || ref_count(resource) > 1
- @as_reification[resource] = true # Prevent rdf:reifies from being emitted
+ @as_reifiedTriple[resource] = true # Prevent rdf:reifies from being emitted
- log_debug("reification") {resource.to_ntriples}
+ log_debug("reifiedTriple") {resource.to_ntriples}
subject_done(resource)
- # There may be multiple reifications using this resource
+ # There may be multiple reifiedTriples using this resource
@reification[resource].each do |tt|
@output.write(position == :subject ? "\n#{indent} << " : '<< ')
+ reifiedTriple(tt.subject, :object) || p_term(tt.subject, :object)
+ @output.write(' ')
+ predicate(tt.predicate)
+ @output.write(' ')
+ reifiedTriple(tt.object, :object) || p_term(tt.object, :object)
+
if write_id
# Only need to output blank node identifiers if they have more than one reference
+ @output.write(' ~')
p_term(resource, :subject)
- @output.write(' | ')
end
- reification(tt.subject, :object) || p_term(tt.subject, :object)
- @output.write(' ')
- predicate(tt.predicate)
- @output.write(' ')
- reification(tt.object, :object) || p_term(tt.object, :object)
@output.write(' >>')
end
true
@@ -645,7 +646,7 @@ def path(resource, position)
end
raise RDF::WriterError, "Cannot serialize resource '#{resource}'" unless
collection(resource, position) ||
- reification(resource, position) ||
+ reifiedTriple(resource, position) ||
blankNodePropertyList(resource, position) ||
p_term(resource, position)
end
@@ -677,7 +678,7 @@ def objectList(subject, predicate, objects)
reifs = @reification.select {|k, v| v.include?(tt)}.keys
if reifs.length == 1
reif = reifs.first
- @as_reification[reif] = true
+ @as_reifiedTriple[reif] = true
@output.write ' {| '
predicateObjectList(reif, true)
@output.write ' |}'
@@ -693,7 +694,7 @@ def predicateObjectList(subject, from_bpl = false)
prop_list = sort_properties(properties)
prop_list -= [RDF.first, RDF.rest] if @lists.key?(subject)
- prop_list -= [RDF.reifies] if @as_reification.key?(subject)
+ prop_list -= [RDF.reifies] if @as_reifiedTriple.key?(subject)
log_debug("predicateObjectList") {prop_list.inspect}
return 0 if prop_list.empty?
diff --git a/spec/writer_spec.rb b/spec/writer_spec.rb
index 2365a20..b823fa7 100644
--- a/spec/writer_spec.rb
+++ b/spec/writer_spec.rb
@@ -653,7 +653,7 @@
regexp: [
%r(ex:s ex:p <<\(\s*ex:s1 ex:p1 <<\(\s*ex:s2 ex:p2 ex:o2*\s*\)>>\s*\)>>)
]
- },
+ }
}.each do |name, params|
it name do
graph = RDF::Graph.new {|g| g << params[:input]}
@@ -661,7 +661,7 @@
end
end
- context "reifications" do
+ context "reifiedTriples" do
{
"subject-iii": {
input: %(
@@ -765,6 +765,28 @@
%r(<<\s*<<\s*ex:s2 ex:p2 ex:o2\s*>> ex:p1 ex:o1\s*>> ex:p ex:o .)
]
},
+ "explicit reifier as subject": {
+ input: %(
+ PREFIX :
+ PREFIX rdf:
+ :r rdf:reifies <<( :s :p :o )>> .
+ :r :p1 :o1 .
+ ),
+ regexp: [
+ %r(<<\s*ex:s ex:p ex:o\s*~\s*ex:r\s*>>\s*ex:p1 ex:o1 .)
+ ]
+ },
+ "explicit reifier as object": {
+ input: %(
+ PREFIX :
+ PREFIX rdf:
+ :r rdf:reifies <<( :s :p :o )>> .
+ :s1 :p1 :r .
+ ),
+ regexp: [
+ %r(ex:s1 ex:p1 <<\s*ex:s ex:p ex:o\s*~\s*ex:r\s*>>\s*.)
+ ]
+ },
}.each do |name, params|
it name do
graph = RDF::Graph.new {|g| g << parse(params[:input], rdfstar: true)}