rdf-rdfa 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +13 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/rdf/rdfa/patches/literal_hacks.rb +21 -10
- data/lib/rdf/rdfa/patches/nokogiri_hacks.rb +16 -0
- data/lib/rdf/rdfa/patches/uri_hacks.rb +6 -1
- data/lib/rdf/rdfa/reader.rb +357 -181
- data/lib/rdf/rdfa/version.rb +1 -1
- data/lib/rdf/rdfa.rb +4 -0
- data/rdf-rdfa.gemspec +11 -6
- data/script/console +3 -3
- data/script/parse +49 -0
- data/script/tc +10 -5
- data/spec/html4-manifest.yml +176 -176
- data/spec/html5-manifest.yml +176 -176
- data/spec/literal_spec.rb +245 -0
- data/spec/matchers.rb +1 -1
- data/spec/rdfa_helper.rb +44 -3
- data/spec/rdfa_reader_spec.rb +32 -67
- data/spec/xhtml-manifest.yml +139 -603
- data/spec/xhtml11-manifest.yml +4707 -0
- metadata +28 -4
data/lib/rdf/rdfa/reader.rb
CHANGED
@@ -4,10 +4,27 @@ module RDF::RDFa
|
|
4
4
|
##
|
5
5
|
# An RDFa parser in Ruby
|
6
6
|
#
|
7
|
+
# Based on processing rules described here:
|
8
|
+
# @see http://www.w3.org/TR/rdfa-syntax/#s_model RDFa 1.0
|
9
|
+
# @see http://www.w3.org/2010/02/rdfa/drafts/2010/ED-rdfa-core-20100803/ RDFa 1.1
|
10
|
+
#
|
7
11
|
# @author [Gregg Kellogg](http://kellogg-assoc.com/)
|
8
12
|
class Reader < RDF::Reader
|
9
13
|
format Format
|
10
14
|
|
15
|
+
SafeCURIEorCURIEorURI = {
|
16
|
+
:rdfa_1_0 => [:term, :safe_curie, :uri, :bnode],
|
17
|
+
:rdfa_1_1 => [:safe_curie, :curie, :term, :uri, :bnode],
|
18
|
+
}
|
19
|
+
TERMorCURIEorAbsURI = {
|
20
|
+
:rdfa_1_0 => [:term, :curie],
|
21
|
+
:rdfa_1_1 => [:term, :curie, :absuri],
|
22
|
+
}
|
23
|
+
TERMorCURIEorAbsURIprop = {
|
24
|
+
:rdfa_1_0 => [:curie],
|
25
|
+
:rdfa_1_1 => [:term, :curie, :absuri],
|
26
|
+
}
|
27
|
+
|
11
28
|
NC_REGEXP = Regexp.new(
|
12
29
|
%{^
|
13
30
|
(?!\\\\u0301) # ́ is a non-spacing acute accent.
|
@@ -21,49 +38,78 @@ module RDF::RDFa
|
|
21
38
|
$},
|
22
39
|
Regexp::EXTENDED)
|
23
40
|
|
24
|
-
# Host language
|
25
|
-
#
|
26
|
-
# :xhtml_rdfa_1_1
|
41
|
+
# Host language
|
42
|
+
# @return [:xhtml]
|
27
43
|
attr_reader :host_language
|
28
44
|
|
29
45
|
# The Recursive Baggage
|
46
|
+
# @private
|
30
47
|
class EvaluationContext # :nodoc:
|
31
|
-
# The base.
|
48
|
+
# The base.
|
49
|
+
#
|
50
|
+
# This will usually be the URL of the document being processed,
|
32
51
|
# but it could be some other URL, set by some other mechanism,
|
33
52
|
# such as the (X)HTML base element. The important thing is that it establishes
|
34
53
|
# a URL against which relative paths can be resolved.
|
54
|
+
#
|
55
|
+
# @return [URI]
|
35
56
|
attr :base, true
|
36
57
|
# The parent subject.
|
58
|
+
#
|
37
59
|
# The initial value will be the same as the initial value of base,
|
38
60
|
# but it will usually change during the course of processing.
|
61
|
+
#
|
62
|
+
# @return [URI]
|
39
63
|
attr :parent_subject, true
|
40
64
|
# The parent object.
|
65
|
+
#
|
41
66
|
# In some situations the object of a statement becomes the subject of any nested statements,
|
42
67
|
# and this property is used to convey this value.
|
43
68
|
# Note that this value may be a bnode, since in some situations a number of nested statements
|
44
69
|
# are grouped together on one bnode.
|
45
70
|
# This means that the bnode must be set in the containing statement and passed down,
|
46
71
|
# and this property is used to convey this value.
|
72
|
+
#
|
73
|
+
# @return URI
|
47
74
|
attr :parent_object, true
|
48
75
|
# A list of current, in-scope URI mappings.
|
76
|
+
#
|
77
|
+
# @return [Hash{Symbol => String}]
|
49
78
|
attr :uri_mappings, true
|
50
|
-
# A list of incomplete triples.
|
79
|
+
# A list of incomplete triples.
|
80
|
+
#
|
81
|
+
# A triple can be incomplete when no object resource
|
51
82
|
# is provided alongside a predicate that requires a resource (i.e., @rel or @rev).
|
52
83
|
# The triples can be completed when a resource becomes available,
|
53
84
|
# which will be when the next subject is specified (part of the process called chaining).
|
85
|
+
#
|
86
|
+
# @return [Array<Array<URI, Resource>>]
|
54
87
|
attr :incomplete_triples, true
|
55
88
|
# The language. Note that there is no default language.
|
89
|
+
#
|
90
|
+
# @return [Symbol]
|
56
91
|
attr :language, true
|
57
92
|
# The term mappings, a list of terms and their associated URIs.
|
93
|
+
#
|
58
94
|
# This specification does not define an initial list.
|
59
95
|
# Host Languages may define an initial list.
|
60
96
|
# If a Host Language provides an initial list, it should do so via an RDFa Profile document.
|
97
|
+
#
|
98
|
+
# @return [Hash{Symbol => URI}]
|
61
99
|
attr :term_mappings, true
|
62
|
-
# The default vocabulary
|
100
|
+
# The default vocabulary
|
101
|
+
#
|
102
|
+
# A value to use as the prefix URI when a term is used.
|
63
103
|
# This specification does not define an initial setting for the default vocabulary.
|
64
104
|
# Host Languages may define an initial setting.
|
105
|
+
#
|
106
|
+
# @return [URI]
|
65
107
|
attr :default_vocabulary, true
|
66
108
|
|
109
|
+
# @param [RDF::URI] base
|
110
|
+
# @param [Hash] host_defaults
|
111
|
+
# @option host_defaults [Hash{String => URI}] :term_mappings Hash of NCName => URI
|
112
|
+
# @option host_defaults [Hash{String => URI}] :vocabulary Hash of prefix => URI
|
67
113
|
def initialize(base, host_defaults)
|
68
114
|
# Initialize the evaluation context, [5.1]
|
69
115
|
@base = base
|
@@ -73,10 +119,12 @@ module RDF::RDFa
|
|
73
119
|
@language = nil
|
74
120
|
@uri_mappings = host_defaults.fetch(:uri_mappings, {})
|
75
121
|
@term_mappings = host_defaults.fetch(:term_mappings, {})
|
76
|
-
@
|
122
|
+
@default_vocabulary = host_defaults.fetch(:vocabulary, nil)
|
77
123
|
end
|
78
124
|
|
79
125
|
# Copy this Evaluation Context
|
126
|
+
#
|
127
|
+
# @param [EvaluationContext] from
|
80
128
|
def initialize_copy(from)
|
81
129
|
# clone the evaluation context correctly
|
82
130
|
@uri_mappings = from.uri_mappings.clone
|
@@ -95,13 +143,16 @@ module RDF::RDFa
|
|
95
143
|
##
|
96
144
|
# Initializes the RDFa reader instance.
|
97
145
|
#
|
98
|
-
# @param [Nokogiri::HTML::Document, Nokogiri::XML::Document,
|
146
|
+
# @param [Nokogiri::HTML::Document, Nokogiri::XML::Document, #read, #to_s] input
|
99
147
|
# @option options [Array] :debug (nil) Array to place debug messages
|
148
|
+
# @option options [Graph] :processor_graph (nil) Graph to record information, warnings and errors.
|
100
149
|
# @option options [Boolean] :strict (false) Raise Error if true, continue with lax parsing, otherwise
|
101
150
|
# @option options [Boolean] :base_uri (nil) Base URI to use for relative URIs.
|
151
|
+
# @option options [:rdfa_1_0, :rdfa_1_1] :version (:rdfa_1_1) Parser version information
|
152
|
+
# @option options [:xhtml] :host_language (:xhtml) Host Language
|
102
153
|
# @return [reader]
|
103
154
|
# @yield [reader]
|
104
|
-
# @yieldparam [Reader] reader
|
155
|
+
# @yieldparam [RDF::Reader] reader
|
105
156
|
# @raise [RDF::ReaderError]:: Raises RDF::ReaderError if _strict_
|
106
157
|
def initialize(input = $stdin, options = {}, &block)
|
107
158
|
super do
|
@@ -110,14 +161,18 @@ module RDF::RDFa
|
|
110
161
|
@base_uri = RDF::URI.intern(options[:base_uri])
|
111
162
|
@@vocabulary_cache ||= {}
|
112
163
|
|
164
|
+
@version = options[:version] ? options[:version].to_sym : :rdfa_1_1
|
165
|
+
@host_language = options[:host_language] || :xhtml
|
166
|
+
|
113
167
|
@doc = case input
|
114
168
|
when Nokogiri::HTML::Document then input
|
115
169
|
when Nokogiri::XML::Document then input
|
116
170
|
else Nokogiri::XML.parse(input, @base_uri.to_s)
|
117
171
|
end
|
118
172
|
|
119
|
-
|
120
|
-
|
173
|
+
add_error(nil, "Empty document", RDF::RDFA.HostLanguageMarkupError) if (@doc.nil? || @doc.root.nil?)
|
174
|
+
add_warning(nil, "Synax errors:\n#{@doc.errors}", RDF::RDFA.HostLanguageMarkupError) unless @doc.errors.empty?
|
175
|
+
|
121
176
|
block.call(self) if block_given?
|
122
177
|
end
|
123
178
|
end
|
@@ -131,16 +186,11 @@ module RDF::RDFa
|
|
131
186
|
def each_statement(&block)
|
132
187
|
@callback = block
|
133
188
|
|
134
|
-
#
|
135
|
-
#
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
# If none found, assume xhtml
|
141
|
-
@host_language ||= :xhtml
|
142
|
-
|
143
|
-
@host_defaults = {}
|
189
|
+
# Section 4.2 RDFa Host Language Conformance
|
190
|
+
#
|
191
|
+
# The Host Language may define a default RDFa Profile. If it does, the RDFa Profile triples that establish term or
|
192
|
+
# URI mappings associated with that profile must not change without changing the profile URI. RDFa Processors may
|
193
|
+
# embed, cache, or retrieve the RDFa Profile triples associated with that profile.
|
144
194
|
@host_defaults = case @host_language
|
145
195
|
when :xhtml
|
146
196
|
{
|
@@ -156,6 +206,10 @@ module RDF::RDFa
|
|
156
206
|
{}
|
157
207
|
end
|
158
208
|
|
209
|
+
@host_defaults.delete(:vocabulary) if @version == :rdfa_1_0
|
210
|
+
|
211
|
+
add_debug(@doc, "version = #{@version}, host_language = #{@host_language}")
|
212
|
+
|
159
213
|
# parse
|
160
214
|
parse_whole_document(@doc, @base_uri)
|
161
215
|
end
|
@@ -185,9 +239,8 @@ module RDF::RDFa
|
|
185
239
|
# Figure out the document path, if it is a Nokogiri::XML::Element or Attribute
|
186
240
|
def node_path(node)
|
187
241
|
case node
|
188
|
-
when Nokogiri::XML::
|
189
|
-
|
190
|
-
else ""
|
242
|
+
when Nokogiri::XML::Node then node.display_path
|
243
|
+
else node.to_s
|
191
244
|
end
|
192
245
|
end
|
193
246
|
|
@@ -196,10 +249,36 @@ module RDF::RDFa
|
|
196
249
|
# @param [XML Node, any] node:: XML Node or string for showing context
|
197
250
|
# @param [String] message::
|
198
251
|
def add_debug(node, message)
|
199
|
-
|
200
|
-
@debug << "#{node_path(node)}: #{message}" if @debug.is_a?(Array)
|
252
|
+
add_processor_message(node, message, RDF::RDFA.InformationalMessage)
|
201
253
|
end
|
202
254
|
|
255
|
+
def add_info(node, message, process_class = RDF::RDFA.InformationalMessage)
|
256
|
+
add_processor_message(node, message, process_class)
|
257
|
+
end
|
258
|
+
|
259
|
+
def add_warning(node, message, process_class = RDF::RDFA.MiscellaneousWarning)
|
260
|
+
add_processor_message(node, message, process_class)
|
261
|
+
end
|
262
|
+
|
263
|
+
def add_error(node, message, process_class = RDF::RDFA.MiscellaneousError)
|
264
|
+
add_processor_message(node, message, process_class)
|
265
|
+
raise ParserException, message if @strict
|
266
|
+
end
|
267
|
+
|
268
|
+
def add_processor_message(node, message, process_class)
|
269
|
+
puts "#{node_path(node)}: #{message}" if ::RDF::RDFa::debug?
|
270
|
+
@debug << "#{node_path(node)}: #{message}" if @debug.is_a?(Array)
|
271
|
+
if @processor_graph
|
272
|
+
@processor_sequence ||= 0
|
273
|
+
n = RDF::Node.new
|
274
|
+
@processor_graph << RDF::Statement.new(n, RDF["type"], process_class)
|
275
|
+
@processor_graph << RDF::Statement.new(n, RDF::DC.description, message)
|
276
|
+
@processor_graph << RDF::Statement.new(n, RDF::DC.date, RDF::Literal::Date.new(DateTime.now.to_date))
|
277
|
+
@processor_graph << RDF::Statement.new(n, RDF::RDFA.sequence, RDF::Literal::Integer.new(@processor_sequence += 1))
|
278
|
+
@processor_graph << RDF::Statement.new(n, RDF::RDFA.source, node_path(node))
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
203
282
|
# add a statement, object can be literal or URI or bnode
|
204
283
|
#
|
205
284
|
# @param [Nokogiri::XML::Node, any] node:: XML Node or string for showing context
|
@@ -210,7 +289,7 @@ module RDF::RDFa
|
|
210
289
|
# @raise [ReaderError]:: Checks parameter types and raises if they are incorrect if parsing mode is _strict_.
|
211
290
|
def add_triple(node, subject, predicate, object)
|
212
291
|
statement = RDF::Statement.new(subject, predicate, object)
|
213
|
-
add_debug(node, "statement: #{statement}")
|
292
|
+
add_debug(node, "statement: #{statement.to_ntriples}")
|
214
293
|
@callback.call(statement)
|
215
294
|
end
|
216
295
|
|
@@ -229,99 +308,96 @@ module RDF::RDFa
|
|
229
308
|
end
|
230
309
|
|
231
310
|
# initialize the evaluation context with the appropriate base
|
232
|
-
evaluation_context = EvaluationContext.new(
|
311
|
+
evaluation_context = EvaluationContext.new(@base_uri, @host_defaults)
|
233
312
|
|
234
313
|
traverse(doc.root, evaluation_context)
|
235
314
|
end
|
236
315
|
|
237
|
-
#
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
# Don't try to open ourselves!
|
246
|
-
add_debug(element, "extract_mappings: skip head profile <#{profile}>")
|
247
|
-
next
|
248
|
-
elsif @@vocabulary_cache[profile]
|
249
|
-
add_debug(element, "extract_mappings: cached profile <#{profile}>")
|
250
|
-
@@vocabulary_cache[profile]
|
251
|
-
elsif @base_uri.to_s == profile
|
252
|
-
# Don't try to open ourselves!
|
253
|
-
add_debug(element, "extract_mappings: skip recursive profile <#{profile}>")
|
254
|
-
next
|
316
|
+
# Parse and process URI mappings, Term mappings and a default vocabulary from @profile
|
317
|
+
#
|
318
|
+
# Yields each mapping
|
319
|
+
def process_profile(element)
|
320
|
+
element.attributes['profile'].to_s.split(/\s/).reverse.each do |profile|
|
321
|
+
# Don't try to open ourselves!
|
322
|
+
if @uri == profile
|
323
|
+
add_debug(element, "process_profile: skip recursive profile <#{profile}>")
|
255
324
|
elsif @@vocabulary_cache.has_key?(profile)
|
256
|
-
add_debug(element, "
|
325
|
+
add_debug(element, "process_profile: skip previously parsed profile <#{profile}>")
|
257
326
|
else
|
258
327
|
begin
|
259
|
-
add_debug(element, "extract_mappings: parse profile <#{profile}>")
|
260
328
|
@@vocabulary_cache[profile] = {
|
261
329
|
:uri_mappings => {},
|
262
|
-
:term_mappings => {}
|
330
|
+
:term_mappings => {},
|
331
|
+
:default_vocabulary => nil
|
263
332
|
}
|
264
333
|
um = @@vocabulary_cache[profile][:uri_mappings]
|
265
334
|
tm = @@vocabulary_cache[profile][:term_mappings]
|
266
|
-
add_debug(element, "
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
p_graph.
|
275
|
-
|
335
|
+
add_debug(element, "process_profile: parse profile <#{profile}>")
|
336
|
+
|
337
|
+
# Parse profile, and extract mappings from graph
|
338
|
+
old_debug, old_verbose, = ::RDF::RDFa::debug?, $verbose
|
339
|
+
::RDF::RDFa::debug, $verbose = false, false
|
340
|
+
# Fixme, RDF isn't smart enough to figure this out from MIME-Type
|
341
|
+
load_opts = {:base_uri => profile}
|
342
|
+
load_opts[:format] = :rdfa unless RDF::Format.for(:file_name => profile)
|
343
|
+
p_graph = RDF::Graph.load(profile, load_opts)
|
344
|
+
::RDF::RDFa::debug, $verbose = old_debug, old_verbose
|
345
|
+
p_graph.subjects.each do |subject|
|
346
|
+
# If one of the objects is not a Literal or if there are additional rdfa:uri or rdfa:term
|
347
|
+
# predicates sharing the same subject, no mapping is created.
|
276
348
|
uri = p_graph.first_object([subject, RDF::RDFA['uri'], nil])
|
277
349
|
term = p_graph.first_object([subject, RDF::RDFA['term'], nil])
|
278
350
|
prefix = p_graph.first_object([subject, RDF::RDFA['prefix'], nil])
|
279
|
-
|
351
|
+
vocab = p_graph.first_object([subject, RDF::RDFA['vocabulary'], nil])
|
352
|
+
add_debug(element, "process_profile: uri=#{uri.inspect}, term=#{term.inspect}, prefix=#{prefix.inspect}, vocabulary=#{vocab.inspect}")
|
280
353
|
|
281
|
-
|
282
|
-
raise RDF::ReaderError, "rdf:
|
283
|
-
raise RDF::ReaderError, "rdf:
|
284
|
-
raise RDF::ReaderError, "rdf:
|
285
|
-
|
354
|
+
raise RDF::ReaderError, "rdf:uri #{uri.inspect} must be a Literal" unless uri.nil? || uri.is_a?(RDF::Literal)
|
355
|
+
raise RDF::ReaderError, "rdf:term #{term.inspect} must be a Literal" unless term.nil? || term.is_a?(RDF::Literal)
|
356
|
+
raise RDF::ReaderError, "rdf:prefix #{prefix.inspect} must be a Literal" unless prefix.nil? || prefix.is_a?(RDF::Literal)
|
357
|
+
raise RDF::ReaderError, "rdf:vocabulary #{vocab.inspect} must be a Literal" unless vocab.nil? || vocab.is_a?(RDF::Literal)
|
358
|
+
|
359
|
+
@@vocabulary_cache[profile][:default_vocabulary] = vocab.value if vocab
|
360
|
+
|
286
361
|
# For every extracted triple that is the common subject of an rdfa:prefix and an rdfa:uri
|
287
362
|
# predicate, create a mapping from the object literal of the rdfa:prefix predicate to the
|
288
363
|
# object literal of the rdfa:uri predicate. Add or update this mapping in the local list of
|
289
364
|
# URI mappings after transforming the 'prefix' component to lower-case.
|
290
365
|
# For every extracted
|
291
|
-
um[prefix.value.downcase] = uri.value if prefix
|
366
|
+
um[prefix.value.downcase] = uri.value if prefix && prefix.value != "_"
|
292
367
|
|
293
368
|
# triple that is the common subject of an rdfa:term and an rdfa:uri predicate, create a
|
294
369
|
# mapping from the object literal of the rdfa:term predicate to the object literal of the
|
295
370
|
# rdfa:uri predicate. Add or update this mapping in the local term mappings.
|
296
|
-
tm[term.value] = RDF::URI.intern(uri.value) if term
|
371
|
+
tm[term.value.downcase] = RDF::URI.intern(uri.value) if term
|
297
372
|
end
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
# raise if @strict
|
302
|
-
rescue RuntimeError => e
|
303
|
-
add_debug(element, "extract_mappings: profile: #{e.message}")
|
304
|
-
raise if @strict
|
373
|
+
rescue RDF::ReaderError => e
|
374
|
+
add_error(element, e.message, RDF::RDFA.ProfileReferenceError)
|
375
|
+
raise # Incase we're not in strict mode, we need to be sure processing stops
|
305
376
|
end
|
306
377
|
end
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
378
|
+
profile_mappings = @@vocabulary_cache[profile]
|
379
|
+
yield :uri_mappings, profile_mappings[:uri_mappings] unless profile_mappings[:uri_mappings].empty?
|
380
|
+
yield :term_mappings, profile_mappings[:term_mappings] unless profile_mappings[:term_mappings].empty?
|
381
|
+
yield :default_vocabulary, profile_mappings[:default_vocabulary] if profile_mappings[:default_vocabulary]
|
311
382
|
end
|
312
|
-
|
383
|
+
end
|
384
|
+
|
385
|
+
# Extract the XMLNS mappings from an element
|
386
|
+
def extract_mappings(element, uri_mappings, term_mappings)
|
313
387
|
# look for xmlns
|
314
388
|
# (note, this may be dependent on @host_language)
|
315
389
|
# Regardless of how the mapping is declared, the value to be mapped must be converted to lower case,
|
316
390
|
# and the URI is not processed in any way; in particular if it is a relative path it is
|
317
391
|
# not resolved against the current base.
|
318
|
-
element.
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
392
|
+
element.namespace_definitions.each do |ns|
|
393
|
+
# A Conforming RDFa Processor must ignore any definition of a mapping for the '_' prefix.
|
394
|
+
next if ns.prefix == "_"
|
395
|
+
|
396
|
+
# Downcase prefix for RDFa 1.1
|
397
|
+
pfx_lc = (@version == :rdfa_1_0 || ns.prefix.nil?) ? ns.prefix : ns.prefix.to_s.downcase
|
398
|
+
if ns.prefix
|
399
|
+
uri_mappings[pfx_lc] = ns.href
|
400
|
+
add_debug(element, "extract_mappings: xmlns:#{ns.prefix} => <#{ns.href}>")
|
325
401
|
end
|
326
402
|
end
|
327
403
|
|
@@ -335,11 +411,12 @@ module RDF::RDFa
|
|
335
411
|
next unless prefix.match(/:$/)
|
336
412
|
prefix.chop!
|
337
413
|
|
414
|
+
# A Conforming RDFa Processor must ignore any definition of a mapping for the '_' prefix.
|
415
|
+
next if prefix == "_"
|
416
|
+
|
338
417
|
uri_mappings[prefix] = uri
|
339
|
-
|
340
|
-
|
341
|
-
add_debug(element, "uri_mappings: #{uri_mappings.map{|k,v|"#{k}='#{v}'"}.join(", ")}")
|
342
|
-
add_debug(element, "term_mappings: #{term_mappings.map{|k,v|"#{k}='#{v}'"}.join(", ")}")
|
418
|
+
add_debug(element, "extract_mappings: prefix #{prefix} => <#{uri}>")
|
419
|
+
end unless @version == :rdfa_1_0
|
343
420
|
end
|
344
421
|
|
345
422
|
# The recursive helper function
|
@@ -352,7 +429,7 @@ module RDF::RDFa
|
|
352
429
|
|
353
430
|
add_debug(element, "traverse, ec: #{evaluation_context.inspect}")
|
354
431
|
|
355
|
-
# local variables [
|
432
|
+
# local variables [7.5 Step 1]
|
356
433
|
recurse = true
|
357
434
|
skip = false
|
358
435
|
new_subject = nil
|
@@ -375,30 +452,53 @@ module RDF::RDFa
|
|
375
452
|
vocab = attrs['vocab']
|
376
453
|
|
377
454
|
# Pull out the attributes needed for the skip test.
|
378
|
-
property = attrs['property'].to_s if attrs['property']
|
379
|
-
typeof = attrs['typeof'].to_s if attrs['typeof']
|
455
|
+
property = attrs['property'].to_s.strip if attrs['property']
|
456
|
+
typeof = attrs['typeof'].to_s.strip if attrs['typeof']
|
380
457
|
datatype = attrs['datatype'].to_s if attrs['datatype']
|
381
458
|
content = attrs['content'].to_s if attrs['content']
|
382
|
-
rel = attrs['rel'].to_s if attrs['rel']
|
383
|
-
rev = attrs['rev'].to_s if attrs['rev']
|
459
|
+
rel = attrs['rel'].to_s.strip if attrs['rel']
|
460
|
+
rev = attrs['rev'].to_s.strip if attrs['rev']
|
461
|
+
|
462
|
+
# Local term mappings [7.5 Steps 2]
|
463
|
+
# Next the current element is parsed for any updates to the local term mappings and local list of URI mappings via @profile.
|
464
|
+
# If @profile is present, its value is processed as defined in RDFa Profiles.
|
465
|
+
unless @version == :rdfa_1_0
|
466
|
+
begin
|
467
|
+
process_profile(element) do |which, value|
|
468
|
+
add_debug(element, "[Step 2] traverse, #{which}: #{value.inspect}")
|
469
|
+
case which
|
470
|
+
when :uri_mappings then uri_mappings.merge!(value)
|
471
|
+
when :term_mappings then term_mappings.merge!(value)
|
472
|
+
when :default_vocabulary then default_vocabulary = value
|
473
|
+
end
|
474
|
+
end
|
475
|
+
rescue
|
476
|
+
# Skip this element and all sub-elements
|
477
|
+
# If any referenced RDFa Profile is not available, then the current element and its children must not place any
|
478
|
+
# triples in the default graph .
|
479
|
+
raise if @strict
|
480
|
+
return
|
481
|
+
end
|
482
|
+
end
|
384
483
|
|
385
|
-
# Default vocabulary [7.5 Step
|
386
|
-
#
|
484
|
+
# Default vocabulary [7.5 Step 3]
|
485
|
+
# Next the current element is examined for any change to the default vocabulary via @vocab.
|
387
486
|
# If @vocab is present and contains a value, its value updates the local default vocabulary.
|
388
487
|
# If the value is empty, then the local default vocabulary must be reset to the Host Language defined default.
|
389
488
|
unless vocab.nil?
|
390
489
|
default_vocabulary = if vocab.to_s.empty?
|
391
490
|
# Set default_vocabulary to host language default
|
392
|
-
@host_defaults.fetch(:
|
491
|
+
add_debug(element, "[Step 2] traverse, reset default_vocaulary to #{@host_defaults.fetch(:vocabulary, nil).inspect}")
|
492
|
+
@host_defaults.fetch(:vocabulary, nil)
|
393
493
|
else
|
394
|
-
vocab
|
494
|
+
RDF::URI.intern(vocab)
|
395
495
|
end
|
396
496
|
add_debug(element, "[Step 2] traverse, default_vocaulary: #{default_vocabulary.inspect}")
|
397
497
|
end
|
398
498
|
|
399
|
-
# Local term mappings [7.5 Steps
|
400
|
-
# Next the current element is
|
401
|
-
#
|
499
|
+
# Local term mappings [7.5 Steps 4]
|
500
|
+
# Next, the current element is then examined for URI mapping s and these are added to the local list of URI mappings.
|
501
|
+
# Note that a URI mapping will simply overwrite any current mapping in the list that has the same name
|
402
502
|
extract_mappings(element, uri_mappings, term_mappings)
|
403
503
|
|
404
504
|
# Language information [7.5 Step 5]
|
@@ -419,8 +519,16 @@ module RDF::RDFa
|
|
419
519
|
add_debug(element, "HTML5 [3.2.3.3] traverse, lang: #{language || 'nil'}") if attrs['lang']
|
420
520
|
|
421
521
|
# rels and revs
|
422
|
-
rels = process_uris(element, rel, evaluation_context,
|
423
|
-
|
522
|
+
rels = process_uris(element, rel, evaluation_context,
|
523
|
+
:uri_mappings => uri_mappings,
|
524
|
+
:term_mappings => term_mappings,
|
525
|
+
:vocab => default_vocabulary,
|
526
|
+
:restrictions => TERMorCURIEorAbsURI[@version])
|
527
|
+
revs = process_uris(element, rev, evaluation_context,
|
528
|
+
:uri_mappings => uri_mappings,
|
529
|
+
:term_mappings => term_mappings,
|
530
|
+
:vocab => default_vocabulary,
|
531
|
+
:restrictions => TERMorCURIEorAbsURI[@version])
|
424
532
|
|
425
533
|
add_debug(element, "traverse, about: #{about.nil? ? 'nil' : about}, src: #{src.nil? ? 'nil' : src}, resource: #{resource.nil? ? 'nil' : resource}, href: #{href.nil? ? 'nil' : href}")
|
426
534
|
add_debug(element, "traverse, property: #{property.nil? ? 'nil' : property}, typeof: #{typeof.nil? ? 'nil' : typeof}, datatype: #{datatype.nil? ? 'nil' : datatype}, content: #{content.nil? ? 'nil' : content}")
|
@@ -429,14 +537,18 @@ module RDF::RDFa
|
|
429
537
|
if !(rel || rev)
|
430
538
|
# Establishing a new subject if no rel/rev [7.5 Step 6]
|
431
539
|
# May not be valid, but can exist
|
432
|
-
if about
|
433
|
-
|
540
|
+
new_subject = if about
|
541
|
+
process_uri(element, about, evaluation_context,
|
542
|
+
:uri_mappings => uri_mappings,
|
543
|
+
:restrictions => SafeCURIEorCURIEorURI[@version])
|
434
544
|
elsif src
|
435
|
-
|
545
|
+
process_uri(element, src, evaluation_context, :restrictions => [:uri])
|
436
546
|
elsif resource
|
437
|
-
|
547
|
+
process_uri(element, resource, evaluation_context,
|
548
|
+
:uri_mappings => uri_mappings,
|
549
|
+
:restrictions => SafeCURIEorCURIEorURI[@version])
|
438
550
|
elsif href
|
439
|
-
|
551
|
+
process_uri(element, href, evaluation_context, :restrictions => [:uri])
|
440
552
|
end
|
441
553
|
|
442
554
|
# If no URI is provided by a resource attribute, then the first match from the following rules
|
@@ -445,52 +557,52 @@ module RDF::RDFa
|
|
445
557
|
# otherwise,
|
446
558
|
# if parent object is present, new subject is set to the value of parent object.
|
447
559
|
# Additionally, if @property is not present then the skip element flag is set to 'true';
|
448
|
-
if
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
skip = true unless property
|
460
|
-
end
|
560
|
+
new_subject ||= if @host_language == :xhtml && element.name =~ /^(head|body)$/ && evaluation_context.base
|
561
|
+
# From XHTML+RDFa 1.1:
|
562
|
+
# if no URI is provided, then first check to see if the element is the head or body element.
|
563
|
+
# If it is, then act as if there is an empty @about present, and process it according to the rule for @about.
|
564
|
+
evaluation_context.base
|
565
|
+
elsif element.attributes['typeof']
|
566
|
+
RDF::Node.new
|
567
|
+
else
|
568
|
+
# if it's null, it's null and nothing changes
|
569
|
+
skip = true unless property
|
570
|
+
evaluation_context.parent_object
|
461
571
|
end
|
462
572
|
add_debug(element, "[Step 6] new_subject: #{new_subject}, skip = #{skip}")
|
463
573
|
else
|
464
574
|
# [7.5 Step 7]
|
465
575
|
# If the current element does contain a @rel or @rev attribute, then the next step is to
|
466
576
|
# establish both a value for new subject and a value for current object resource:
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
577
|
+
new_subject = process_uri(element, about, evaluation_context,
|
578
|
+
:uri_mappings => uri_mappings,
|
579
|
+
:restrictions => SafeCURIEorCURIEorURI[@version]) ||
|
580
|
+
process_uri(element, src, evaluation_context,
|
581
|
+
:uri_mappings => uri_mappings,
|
582
|
+
:restrictions => [:uri])
|
472
583
|
|
473
584
|
# If no URI is provided then the first match from the following rules will apply
|
474
|
-
if
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
# no skip flag set this time
|
486
|
-
end
|
585
|
+
new_subject ||= if @host_language == :xhtml && element.name =~ /^(head|body)$/
|
586
|
+
# From XHTML+RDFa 1.1:
|
587
|
+
# if no URI is provided, then first check to see if the element is the head or body element.
|
588
|
+
# If it is, then act as if there is an empty @about present, and process it according to the rule for @about.
|
589
|
+
evaluation_context.base
|
590
|
+
elsif element.attributes['typeof']
|
591
|
+
RDF::Node.new
|
592
|
+
else
|
593
|
+
# if it's null, it's null and nothing changes
|
594
|
+
evaluation_context.parent_object
|
595
|
+
# no skip flag set this time
|
487
596
|
end
|
488
597
|
|
489
598
|
# Then the current object resource is set to the URI obtained from the first match from the following rules:
|
490
|
-
if resource
|
491
|
-
|
599
|
+
current_object_resource = if resource
|
600
|
+
process_uri(element, resource, evaluation_context,
|
601
|
+
:uri_mappings => uri_mappings,
|
602
|
+
:restrictions => SafeCURIEorCURIEorURI[@version])
|
492
603
|
elsif href
|
493
|
-
|
604
|
+
process_uri(element, href, evaluation_context,
|
605
|
+
:restrictions => [:uri])
|
494
606
|
end
|
495
607
|
|
496
608
|
add_debug(element, "[Step 7] new_subject: #{new_subject}, current_object_resource = #{current_object_resource.nil? ? 'nil' : current_object_resource}")
|
@@ -498,11 +610,15 @@ module RDF::RDFa
|
|
498
610
|
|
499
611
|
# Process @typeof if there is a subject [Step 8]
|
500
612
|
if new_subject and typeof
|
501
|
-
# Typeof is
|
502
|
-
types = process_uris(element, typeof, evaluation_context,
|
613
|
+
# Typeof is TERMorCURIEorAbsURIs
|
614
|
+
types = process_uris(element, typeof, evaluation_context,
|
615
|
+
:uri_mappings => uri_mappings,
|
616
|
+
:term_mappings => term_mappings,
|
617
|
+
:vocab => default_vocabulary,
|
618
|
+
:restrictions => TERMorCURIEorAbsURI[@version])
|
503
619
|
add_debug(element, "typeof: #{typeof}")
|
504
620
|
types.each do |one_type|
|
505
|
-
add_triple(element, new_subject, RDF
|
621
|
+
add_triple(element, new_subject, RDF["type"], one_type)
|
506
622
|
end
|
507
623
|
end
|
508
624
|
|
@@ -531,30 +647,60 @@ module RDF::RDFa
|
|
531
647
|
|
532
648
|
# Establish current object literal [Step 11]
|
533
649
|
if property
|
534
|
-
properties = process_uris(element, property, evaluation_context,
|
650
|
+
properties = process_uris(element, property, evaluation_context,
|
651
|
+
:uri_mappings => uri_mappings,
|
652
|
+
:term_mappings => term_mappings,
|
653
|
+
:vocab => default_vocabulary,
|
654
|
+
:restrictions => TERMorCURIEorAbsURIprop[@version])
|
655
|
+
|
656
|
+
properties.reject! do |p|
|
657
|
+
if p.is_a?(RDF::URI)
|
658
|
+
false
|
659
|
+
else
|
660
|
+
add_debug(element, "Illegal predicate: #{p.inspect}")
|
661
|
+
raise RDF::ReaderError, "predicate #{p.inspect} must be a URI" if @strict
|
662
|
+
true
|
663
|
+
end
|
664
|
+
end
|
535
665
|
|
536
666
|
# get the literal datatype
|
537
|
-
type = datatype
|
538
667
|
children_node_types = element.children.collect{|c| c.class}.uniq
|
539
668
|
|
540
669
|
# the following 3 IF clauses should be mutually exclusive. Written as is to prevent extensive indentation.
|
541
|
-
|
542
|
-
|
670
|
+
datatype = process_uri(element, datatype, evaluation_context,
|
671
|
+
:uri_mappings => uri_mappings,
|
672
|
+
:term_mappings => term_mappings,
|
673
|
+
:vocab => default_vocabulary,
|
674
|
+
:restrictions => TERMorCURIEorAbsURI[@version]) unless datatype.to_s.empty?
|
675
|
+
current_object_literal = if !datatype.to_s.empty? && datatype.to_s != RDF.XMLLiteral.to_s
|
543
676
|
# typed literal
|
544
|
-
add_debug(element, "[Step 11] typed literal")
|
545
|
-
|
546
|
-
elsif
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
677
|
+
add_debug(element, "[Step 11] typed literal (#{datatype})")
|
678
|
+
RDF::Literal.new(content || element.inner_text.to_s, :datatype => datatype, :language => language)
|
679
|
+
elsif @version == :rdfa_1_1
|
680
|
+
if datatype.to_s == RDF.XMLLiteral.to_s
|
681
|
+
# XML Literal
|
682
|
+
add_debug(element, "[Step 11(1.1)] XML Literal: #{element.inner_html}")
|
683
|
+
recurse = false
|
684
|
+
RDF::Literal.new(element.inner_html, :datatype => RDF.XMLLiteral, :language => language, :namespaces => uri_mappings.merge("" => "http://www.w3.org/1999/xhtml"))
|
685
|
+
else
|
686
|
+
# plain literal
|
687
|
+
add_debug(element, "[Step 11(1.1)] plain literal")
|
688
|
+
RDF::Literal.new(content || element.inner_text.to_s, :language => language)
|
689
|
+
end
|
690
|
+
else
|
691
|
+
if content || (children_node_types == [Nokogiri::XML::Text]) || (element.children.length == 0) || datatype == ""
|
692
|
+
# plain literal
|
693
|
+
add_debug(element, "[Step 11 (1.0)] plain literal")
|
694
|
+
RDF::Literal.new(content || element.inner_text.to_s, :language => language)
|
695
|
+
elsif children_node_types != [Nokogiri::XML::Text] and (datatype == nil or datatype.to_s == RDF.XMLLiteral.to_s)
|
696
|
+
# XML Literal
|
697
|
+
add_debug(element, "[Step 11 (1.0)] XML Literal: #{element.inner_html}")
|
698
|
+
recurse = false
|
699
|
+
RDF::Literal.new(element.inner_html, :datatype => RDF.XMLLiteral, :language => language, :namespaces => uri_mappings.merge("" => "http://www.w3.org/1999/xhtml"))
|
700
|
+
end
|
555
701
|
end
|
556
|
-
|
557
|
-
|
702
|
+
|
703
|
+
# add each property
|
558
704
|
properties.each do |p|
|
559
705
|
add_triple(element, new_subject, p, current_object_literal)
|
560
706
|
end
|
@@ -611,7 +757,7 @@ module RDF::RDFa
|
|
611
757
|
end
|
612
758
|
end
|
613
759
|
|
614
|
-
# space-separated
|
760
|
+
# space-separated TERMorCURIEorAbsURI or SafeCURIEorCURIEorURI
|
615
761
|
def process_uris(element, value, evaluation_context, options)
|
616
762
|
return [] if value.to_s.empty?
|
617
763
|
add_debug(element, "process_uris: #{value}")
|
@@ -619,34 +765,56 @@ module RDF::RDFa
|
|
619
765
|
end
|
620
766
|
|
621
767
|
def process_uri(element, value, evaluation_context, options = {})
|
622
|
-
|
623
|
-
|
768
|
+
return if value.nil?
|
769
|
+
restrictions = options[:restrictions]
|
770
|
+
add_debug(element, "process_uri: #{value}, restrictions = #{restrictions.inspect}")
|
624
771
|
options = {:uri_mappings => {}}.merge(options)
|
625
|
-
if !options[:term_mappings] && options[:uri_mappings] && value.to_s.match(/^\[(.*)\]$/)
|
772
|
+
if !options[:term_mappings] && options[:uri_mappings] && value.to_s.match(/^\[(.*)\]$/) && restrictions.include?(:safe_curie)
|
626
773
|
# SafeCURIEorCURIEorURI
|
627
774
|
# When the value is surrounded by square brackets, then the content within the brackets is
|
628
775
|
# evaluated as a CURIE according to the CURIE Syntax definition. If it is not a valid CURIE, the
|
629
776
|
# value must be ignored.
|
630
|
-
uri = curie_to_resource_or_bnode(element, $1, options[:uri_mappings], evaluation_context.parent_subject)
|
777
|
+
uri = curie_to_resource_or_bnode(element, $1, options[:uri_mappings], evaluation_context.parent_subject, restrictions)
|
631
778
|
add_debug(element, "process_uri: #{value} => safeCURIE => <#{uri}>")
|
632
779
|
uri
|
633
|
-
elsif options[:term_mappings] && NC_REGEXP.match(value.to_s)
|
634
|
-
#
|
780
|
+
elsif options[:term_mappings] && NC_REGEXP.match(value.to_s) && restrictions.include?(:term)
|
781
|
+
# TERMorCURIEorAbsURI
|
635
782
|
# If the value is an NCName, then it is evaluated as a term according to General Use of Terms in
|
636
783
|
# Attributes. Note that this step may mean that the value is to be ignored.
|
637
|
-
uri = process_term(value.to_s, options)
|
784
|
+
uri = process_term(element, value.to_s, options)
|
638
785
|
add_debug(element, "process_uri: #{value} => term => <#{uri}>")
|
639
786
|
uri
|
640
787
|
else
|
641
|
-
# SafeCURIEorCURIEorURI or
|
788
|
+
# SafeCURIEorCURIEorURI or TERMorCURIEorAbsURI
|
642
789
|
# Otherwise, the value is evaluated as a CURIE.
|
643
790
|
# If it is a valid CURIE, the resulting URI is used; otherwise, the value will be processed as a URI.
|
644
|
-
uri = curie_to_resource_or_bnode(element, value, options[:uri_mappings], evaluation_context.parent_subject)
|
791
|
+
uri = curie_to_resource_or_bnode(element, value, options[:uri_mappings], evaluation_context.parent_subject, restrictions)
|
645
792
|
if uri
|
646
793
|
add_debug(element, "process_uri: #{value} => CURIE => <#{uri}>")
|
647
|
-
|
648
|
-
|
649
|
-
|
794
|
+
elsif @version == :rdfa_1_0 && value.to_s.match(/^xml/i)
|
795
|
+
# Special case to not allow anything starting with XML to be treated as a URI
|
796
|
+
elsif restrictions.include?(:absuri) || restrictions.include?(:uri)
|
797
|
+
begin
|
798
|
+
# AbsURI does not use xml:base
|
799
|
+
if restrictions.include?(:absuri)
|
800
|
+
uri = RDF::URI.intern(value)
|
801
|
+
unless uri.absolute?
|
802
|
+
uri = nil
|
803
|
+
raise RDF::ReaderError, "Relative URI #{value}"
|
804
|
+
end
|
805
|
+
else
|
806
|
+
uri = evaluation_context.base.join(Addressable::URI.parse(value))
|
807
|
+
end
|
808
|
+
rescue Addressable::URI::InvalidURIError => e
|
809
|
+
add_warning(element, "Malformed prefix #{value}", RDF::RDFA.UndefinedPrefixError)
|
810
|
+
rescue RDF::ReaderError => e
|
811
|
+
add_debug(element, e.message)
|
812
|
+
if value.to_s =~ /^\(^\w\):/
|
813
|
+
add_warning(element, "Undefined prefix #{$1}", RDF::RDFA.UndefinedPrefixError)
|
814
|
+
else
|
815
|
+
add_warning(element, "Relative URI #{value}")
|
816
|
+
end
|
817
|
+
end
|
650
818
|
add_debug(element, "process_uri: #{value} => URI => <#{uri}>")
|
651
819
|
end
|
652
820
|
uri
|
@@ -659,7 +827,7 @@ module RDF::RDFa
|
|
659
827
|
# @param [Hash] options:: Parser options, one of
|
660
828
|
# <em>options[:term_mappings]</em>:: Term mappings
|
661
829
|
# <em>options[:vocab]</em>:: Default vocabulary
|
662
|
-
def process_term(value, options)
|
830
|
+
def process_term(element, value, options)
|
663
831
|
case
|
664
832
|
when options[:term_mappings].is_a?(Hash) && options[:term_mappings].has_key?(value.to_s.downcase)
|
665
833
|
# If the term is in the local term mappings, use the associated URI.
|
@@ -670,35 +838,43 @@ module RDF::RDFa
|
|
670
838
|
RDF::URI.intern(options[:vocab] + value)
|
671
839
|
else
|
672
840
|
# Finally, if there is no local default vocabulary, the term has no associated URI and must be ignored.
|
841
|
+
add_warning(element, "Term #{value} is not defined", RDF::RDFA.UndefinedTermError)
|
673
842
|
nil
|
674
843
|
end
|
675
844
|
end
|
676
845
|
|
677
846
|
# From section 6. CURIE Syntax Definition
|
678
|
-
def curie_to_resource_or_bnode(element, curie, uri_mappings, subject)
|
847
|
+
def curie_to_resource_or_bnode(element, curie, uri_mappings, subject, restrictions)
|
679
848
|
# URI mappings for CURIEs default to XHV, rather than the default doc namespace
|
680
849
|
prefix, reference = curie.to_s.split(":")
|
681
850
|
|
682
851
|
# consider the bnode situation
|
683
|
-
if prefix == "_"
|
852
|
+
if prefix == "_" && restrictions.include?(:bnode)
|
853
|
+
# we force a non-nil name, otherwise it generates a new name
|
854
|
+
# As a special case, _: is also a valid reference for one specific bnode.
|
684
855
|
bnode(reference)
|
685
856
|
elsif curie.to_s.match(/^:/)
|
857
|
+
add_debug(element, "curie_to_resource_or_bnode: default prefix: defined? #{!!uri_mappings[""]}, defaults: #{@host_defaults[:prefix]}")
|
686
858
|
# Default prefix
|
687
859
|
if uri_mappings[""]
|
688
860
|
RDF::URI.intern(uri_mappings[""] + reference.to_s)
|
689
861
|
elsif @host_defaults[:prefix]
|
690
862
|
RDF::URI.intern(uri_mappings[@host_defaults[:prefix]] + reference.to_s)
|
863
|
+
else
|
864
|
+
#add_warning(element, "Default namespace prefix is not defined", RDF::RDFA.UndefinedPrefixError)
|
865
|
+
nil
|
691
866
|
end
|
692
867
|
elsif !curie.to_s.match(/:/)
|
693
868
|
# No prefix, undefined (in this context, it is evaluated as a term elsewhere)
|
694
869
|
nil
|
695
870
|
else
|
696
871
|
# Prefixes always downcased
|
697
|
-
|
872
|
+
prefix = prefix.to_s.downcase unless @version == :rdfa_1_0
|
873
|
+
ns = uri_mappings[prefix.to_s]
|
698
874
|
if ns
|
699
875
|
RDF::URI.intern(ns + reference.to_s)
|
700
876
|
else
|
701
|
-
add_debug(element, "curie_to_resource_or_bnode No namespace mapping for #{prefix
|
877
|
+
#add_debug(element, "curie_to_resource_or_bnode No namespace mapping for #{prefix}")
|
702
878
|
nil
|
703
879
|
end
|
704
880
|
end
|