rdf_context 0.5.7 → 0.5.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +15 -1
- data/README.rdoc +2 -0
- data/Rakefile +2 -4
- data/VERSION +1 -1
- data/bin/rdf_context +5 -54
- data/lib/rdf_context.rb +5 -0
- data/lib/rdf_context/graph.rb +68 -49
- data/lib/rdf_context/n3parser.rb +2 -2
- data/lib/rdf_context/namespace.rb +1 -1
- data/lib/rdf_context/nokogiri_hacks.rb +7 -0
- data/lib/rdf_context/parser.rb +57 -13
- data/lib/rdf_context/rdfaparser.rb +200 -130
- data/lib/rdf_context/rdfxmlparser.rb +8 -8
- data/lib/rdf_context/serializer/recursive_serializer.rb +1 -1
- data/lib/rdf_context/serializer/turtle_serializer.rb +15 -15
- data/lib/rdf_context/serializer/xml_serializer.rb +8 -8
- data/lib/rdf_context/store/memory_store.rb +14 -14
- data/lib/rdf_context/store/sqlite3_store.rb +4 -4
- data/lib/rdf_context/uriref.rb +11 -4
- data/script/console +1 -3
- data/script/tc +44 -0
- data/spec/.gitignore +1 -0
- data/spec/aggregate_graph_spec.rb +1 -0
- data/spec/bnode_spec.rb +2 -1
- data/spec/conjunctive_graph_spec.rb +1 -0
- data/spec/cwm_spec.rb +1 -0
- data/spec/duration_spec.rb +1 -0
- data/spec/graph_spec.rb +27 -0
- data/spec/list_store_spec.rb +1 -0
- data/spec/literal_spec.rb +1 -0
- data/spec/matchers.rb +1 -1
- data/spec/memory_store_spec.rb +1 -0
- data/spec/n3parser_spec.rb +1 -0
- data/spec/namespaces_spec.rb +1 -0
- data/spec/parser_spec.rb +1 -0
- data/spec/rdf_helper.rb +4 -4
- data/spec/rdfa_helper.rb +24 -0
- data/spec/rdfa_parser_spec.rb +6 -36
- data/spec/rdfcore/.gitignore +1 -0
- data/spec/rdfxml_spec.rb +1 -0
- data/spec/sqlite3_store_spec.rb +1 -0
- data/spec/string_hacks_spec.rb +2 -0
- data/spec/swap_test/.gitignore +1 -0
- data/spec/triple_spec.rb +1 -0
- data/spec/turtle/.gitignore +1 -0
- data/spec/turtle_serializer_spec.rb +3 -2
- data/spec/turtle_spec.rb +1 -0
- data/spec/uriref_spec.rb +13 -12
- data/spec/xml_serializer_spec.rb +7 -6
- metadata +26 -61
- data/spec/html4-manifest.yml +0 -4937
- data/spec/html5-manifest.yml +0 -4937
- data/spec/rdfcore/Manifest.yml +0 -6242
- data/spec/swap_test/n3parser.yml +0 -773
- data/spec/swap_test/regression.yml +0 -902
- data/spec/turtle/manifest-bad.yml +0 -807
- data/spec/turtle/manifest.yml +0 -807
- data/spec/xhtml-manifest.yml +0 -3901
- data/spec/xhtml11-manifest.yml +0 -4405
@@ -1,4 +1,5 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'parser')
|
2
|
+
require 'open-uri'
|
2
3
|
|
3
4
|
module RdfContext
|
4
5
|
##
|
@@ -6,11 +7,24 @@ module RdfContext
|
|
6
7
|
#
|
7
8
|
# Based on processing rules described here:
|
8
9
|
# @see http://www.w3.org/TR/rdfa-syntax/#s_model RDFa 1.0
|
9
|
-
# @see http://www.w3.org/2010/02/rdfa/drafts/2010/
|
10
|
+
# @see http://www.w3.org/2010/02/rdfa/drafts/2010/WD-rdfa-core-20100803/ RDFa 1.1
|
10
11
|
#
|
11
12
|
# @author Ben Adida
|
12
13
|
# @author Gregg Kellogg
|
13
14
|
class RdfaParser < Parser
|
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
|
+
|
14
28
|
# Host language
|
15
29
|
# @return [:xhtml]
|
16
30
|
attr_reader :host_language
|
@@ -83,7 +97,7 @@ module RdfContext
|
|
83
97
|
# @return [URIRef]
|
84
98
|
attr :default_vocabulary, true
|
85
99
|
|
86
|
-
# @param [
|
100
|
+
# @param [URIRef] base
|
87
101
|
# @param [Hash] host_defaults
|
88
102
|
# @option host_defaults [Hash{String => URIRef}] :term_mappings Hash of NCName => URIRef
|
89
103
|
# @option host_defaults [Hash{String => Namespace}] :vocabulary Hash of prefix => URIRef
|
@@ -92,7 +106,7 @@ module RdfContext
|
|
92
106
|
@base = base
|
93
107
|
@parent_subject = @base
|
94
108
|
@parent_object = nil
|
95
|
-
@uri_mappings = {}
|
109
|
+
@uri_mappings = host_defaults.fetch(:uri_mappings, {})
|
96
110
|
@incomplete_triples = []
|
97
111
|
@language = nil
|
98
112
|
@term_mappings = host_defaults.fetch(:term_mappings, {})
|
@@ -121,6 +135,7 @@ module RdfContext
|
|
121
135
|
# Creates a new parser for RDFa.
|
122
136
|
#
|
123
137
|
# @option options [Graph] :graph (nil) Graph to parse into, otherwise a new RdfContext::Graph instance is created
|
138
|
+
# @option options [Graph] :processor_graph (nil) Graph to record information, warnings and errors.
|
124
139
|
# @option options [Array] :debug (nil) Array to place debug messages
|
125
140
|
# @option options [:rdfxml, :html, :n3] :type (nil)
|
126
141
|
# @option options [Boolean] :strict (false) Raise Error if true, continue with lax parsing, otherwise
|
@@ -140,6 +155,8 @@ module RdfContext
|
|
140
155
|
# @param [Nokogiri::HTML::Document, Nokogiri::XML::Document, #read, #to_s] stream the HTML+RDFa IO stream, string, Nokogiri::HTML::Document or Nokogiri::XML::Document
|
141
156
|
# @param [String] uri (nil) the URI of the document
|
142
157
|
# @option options [Array] :debug (nil) Array to place debug messages
|
158
|
+
# @option options [:rdfa_1_0, :rdfa_1_1] :version (:rdfa_1_1) Parser version information
|
159
|
+
# @option options [:xhtml] :host_language (:xhtml) Host Language
|
143
160
|
# @option options [Boolean] :strict (false) Raise Error if true, continue with lax parsing, otherwise
|
144
161
|
# @return [Graph] Returns the graph containing parsed triples
|
145
162
|
# @yield [triple]
|
@@ -154,22 +171,19 @@ module RdfContext
|
|
154
171
|
else Nokogiri::XML.parse(stream, uri.to_s)
|
155
172
|
end
|
156
173
|
|
157
|
-
|
174
|
+
add_error(nil, "Empty document", RDFA_NS.HostLanguageMarkupError) if @doc.nil?
|
175
|
+
add_warning(nil, "Synax errors:\n#{@doc.errors}", RDFA_NS.HostLanguageMarkupError) unless @doc.errors.empty?
|
176
|
+
|
158
177
|
@callback = block
|
159
178
|
|
160
|
-
|
161
|
-
|
162
|
-
version = @doc.root.attributes["version"].to_s if @doc.root
|
163
|
-
|
164
|
-
@host_language = case version.to_s
|
165
|
-
when /XHTML+RDFa/ then :xhtml
|
166
|
-
end
|
167
|
-
|
168
|
-
# If none found, assume xhtml
|
169
|
-
@host_language ||= :xhtml
|
170
|
-
|
171
|
-
@version = version.to_s.match(/RDFa 1.0/) ? :rdfa_1_0 : :rdfa_1_1
|
179
|
+
@version = options[:version] ? options[:version].to_sym : :rdfa_1_1
|
180
|
+
@host_language = options[:host_language] || :xhtml
|
172
181
|
|
182
|
+
# Section 4.2 RDFa Host Language Conformance
|
183
|
+
#
|
184
|
+
# The Host Language may define a default RDFa Profile. If it does, the RDFa Profile triples that establish term or
|
185
|
+
# URI mappings associated with that profile must not change without changing the profile URI. RDFa Processors may
|
186
|
+
# embed, cache, or retrieve the RDFa Profile triples associated with that profile.
|
173
187
|
@host_defaults = case @host_language
|
174
188
|
when :xhtml
|
175
189
|
@graph.bind(XHV_NS)
|
@@ -188,7 +202,7 @@ module RdfContext
|
|
188
202
|
|
189
203
|
@host_defaults.delete(:vocabulary) if @version == :rdfa_1_0
|
190
204
|
|
191
|
-
add_debug(@doc, "version = #{@version}, host_language = #{@host_language}")
|
205
|
+
add_debug(@doc.root, "version = #{@version.inspect}, host_language = #{@host_language}")
|
192
206
|
# parse
|
193
207
|
parse_whole_document(@doc, @uri)
|
194
208
|
|
@@ -206,51 +220,45 @@ module RdfContext
|
|
206
220
|
base = base_el.attributes['href']
|
207
221
|
# Strip any fragment from base
|
208
222
|
base = base.to_s.split("#").first
|
209
|
-
@uri = URIRef.
|
223
|
+
@uri = URIRef.intern(base, :normalize => false, :normalize => false)
|
210
224
|
add_debug(base_el, "parse_whole_doc: base='#{base}'")
|
211
225
|
end
|
212
226
|
|
213
227
|
# initialize the evaluation context with the appropriate base
|
214
|
-
evaluation_context = EvaluationContext.new(
|
228
|
+
evaluation_context = EvaluationContext.new(@uri, @host_defaults)
|
215
229
|
|
216
230
|
traverse(doc.root, evaluation_context)
|
217
231
|
end
|
218
232
|
|
219
|
-
#
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
# If @profile is present, its value is processed as defined in RDFa Profiles.
|
225
|
-
element.attributes['profile'].to_s.split(/\s/).each do |profile|
|
233
|
+
# Parse and process URI mappings, Term mappings and a default vocabulary from @profile
|
234
|
+
#
|
235
|
+
# Yields each mapping
|
236
|
+
def process_profile(element)
|
237
|
+
element.attributes['profile'].to_s.split(/\s/).reverse.each do |profile|
|
226
238
|
# Don't try to open ourselves!
|
227
239
|
if @uri == profile
|
228
|
-
add_debug(element, "
|
229
|
-
@@vocabulary_cache[profile]
|
240
|
+
add_debug(element, "process_profile: skip recursive profile <#{profile}>")
|
230
241
|
elsif @@vocabulary_cache.has_key?(profile)
|
231
|
-
add_debug(element, "
|
242
|
+
add_debug(element, "process_profile: skip previously parsed profile <#{profile}>")
|
232
243
|
else
|
233
244
|
begin
|
234
|
-
add_debug(element, "extract_mappings: parse profile <#{profile}>")
|
235
245
|
@@vocabulary_cache[profile] = {
|
236
246
|
:uri_mappings => {},
|
237
|
-
:term_mappings => {}
|
247
|
+
:term_mappings => {},
|
248
|
+
:default_vocabulary => nil
|
238
249
|
}
|
239
250
|
um = @@vocabulary_cache[profile][:uri_mappings]
|
240
251
|
tm = @@vocabulary_cache[profile][:term_mappings]
|
241
|
-
add_debug(element, "
|
242
|
-
|
243
|
-
|
244
|
-
sess.timeout = 10
|
245
|
-
resp = sess.get(profile)
|
246
|
-
raise RuntimeError, "HTTP returned status #{resp.status} when reading #{profile}" if resp.status >= 400
|
252
|
+
add_debug(element, "process_profile: parse profile <#{profile}>")
|
253
|
+
prof_body = OpenURI.open_uri(profile)
|
254
|
+
raise ParserException, "Empty profile #{profile}" if prof_body.to_s.empty?
|
247
255
|
|
248
256
|
# Parse profile, and extract mappings from graph
|
249
|
-
old_debug, old_verbose, =
|
250
|
-
|
251
|
-
p_graph = Parser.parse(
|
252
|
-
ttl = p_graph.serialize(:format => :ttl) if @debug ||
|
253
|
-
|
257
|
+
old_debug, old_verbose, = ::RdfContext::debug?, $verbose
|
258
|
+
::RdfContext::debug, $verbose = false, false
|
259
|
+
p_graph = Parser.parse(prof_body, profile)
|
260
|
+
ttl = p_graph.serialize(:format => :ttl) if @debug || ::RdfContext::debug?
|
261
|
+
::RdfContext::debug, $verbose = old_debug, old_verbose
|
254
262
|
add_debug(element, ttl) if ttl
|
255
263
|
p_graph.subjects.each do |subject|
|
256
264
|
props = p_graph.properties(subject)
|
@@ -261,19 +269,24 @@ module RdfContext
|
|
261
269
|
uri = props[RDFA_NS.uri_.to_s]
|
262
270
|
term = props[RDFA_NS.term_.to_s]
|
263
271
|
prefix = props[RDFA_NS.prefix_.to_s]
|
264
|
-
|
272
|
+
vocab = props[RDFA_NS.vocabulary.to_s]
|
273
|
+
add_debug(element, "process_profile: uri=#{uri.inspect}, term=#{term.inspect}, prefix=#{prefix.inspect}, vocabulary=#{vocab.inspect}")
|
265
274
|
|
266
|
-
|
267
|
-
raise ParserException, "multi-valued rdf:uri" if uri.length != 1
|
275
|
+
raise ParserException, "multi-valued rdf:uri" if uri && uri.length != 1
|
268
276
|
raise ParserException, "multi-valued rdf:term." if term && term.length != 1
|
269
277
|
raise ParserException, "multi-valued rdf:prefix" if prefix && prefix.length != 1
|
278
|
+
raise ParserException, "multi-valued rdf:vocabulary" if vocab && vocab.length != 1
|
270
279
|
|
271
|
-
uri = uri.first
|
280
|
+
uri = uri.first if uri
|
272
281
|
term = term.first if term
|
273
282
|
prefix = prefix.first if prefix
|
274
|
-
|
275
|
-
raise ParserException, "rdf:
|
276
|
-
raise ParserException, "rdf:
|
283
|
+
vocab = vocab.first if vocab
|
284
|
+
raise ParserException, "rdf:uri #{uri.inspect} must be a Literal" unless uri.nil? || uri.is_a?(Literal)
|
285
|
+
raise ParserException, "rdf:term #{term.inspect} must be a Literal" unless term.nil? || term.is_a?(Literal)
|
286
|
+
raise ParserException, "rdf:prefix #{prefix.inspect} must be a Literal" unless prefix.nil? || prefix.is_a?(Literal)
|
287
|
+
raise ParserException, "rdf:vocabulary #{vocab.inspect} must be a Literal" unless vocab.nil? || vocab.is_a?(Literal)
|
288
|
+
|
289
|
+
@@vocabulary_cache[profile][:default_vocabulary] = vocab if vocab
|
277
290
|
|
278
291
|
# For every extracted triple that is the common subject of an rdfa:prefix and an rdfa:uri
|
279
292
|
# predicate, create a mapping from the object literal of the rdfa:prefix predicate to the
|
@@ -285,38 +298,42 @@ module RdfContext
|
|
285
298
|
# triple that is the common subject of an rdfa:term and an rdfa:uri predicate, create a
|
286
299
|
# mapping from the object literal of the rdfa:term predicate to the object literal of the
|
287
300
|
# rdfa:uri predicate. Add or update this mapping in the local term mappings.
|
288
|
-
tm[term.to_s] = URIRef.
|
301
|
+
tm[term.to_s.downcase] = URIRef.intern(uri.to_s, :normalize => false) if term
|
289
302
|
end
|
290
|
-
rescue
|
291
|
-
|
292
|
-
raise
|
293
|
-
rescue RuntimeError => e
|
294
|
-
add_debug(element, "extract_mappings: profile: #{e.message}")
|
295
|
-
raise if @strict
|
303
|
+
rescue Exception => e
|
304
|
+
add_error(element, e.message, RDFA_NS.ProfileReferenceError)
|
305
|
+
raise # We need to be sure processing stops
|
296
306
|
end
|
297
307
|
end
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
end
|
303
|
-
|
308
|
+
profile_mappings = @@vocabulary_cache[profile]
|
309
|
+
yield :uri_mappings, profile_mappings[:uri_mappings] unless profile_mappings[:uri_mappings].empty?
|
310
|
+
yield :term_mappings, profile_mappings[:term_mappings] unless profile_mappings[:term_mappings].empty?
|
311
|
+
yield :default_vocabulary, profile_mappings[:default_vocabulary] if profile_mappings[:default_vocabulary]
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
# Extract the XMLNS mappings from an element
|
316
|
+
def extract_mappings(element, uri_mappings)
|
304
317
|
# look for xmlns
|
305
318
|
# (note, this may be dependent on @host_language)
|
306
319
|
# Regardless of how the mapping is declared, the value to be mapped must be converted to lower case,
|
307
320
|
# and the URI is not processed in any way; in particular if it is a relative path it is
|
308
321
|
# not resolved against the current base.
|
309
|
-
element.
|
322
|
+
element.namespace_definitions.each do |ns|
|
323
|
+
add_debug(element, "extract_mappings: namespace #{ns.prefix} => <#{ns.href}>")
|
310
324
|
begin
|
311
|
-
abbr, prefix = attr_name.split(":")
|
312
325
|
# A Conforming RDFa Processor must ignore any definition of a mapping for the '_' prefix.
|
313
|
-
next if prefix == "_"
|
326
|
+
next if ns.prefix == "_"
|
314
327
|
|
315
|
-
|
316
|
-
|
328
|
+
# Downcase prefix for RDFa 1.1
|
329
|
+
pfx_lc = (@version == :rdfa_1_0 || ns.prefix.nil?) ? ns.prefix : ns.prefix.to_s.downcase
|
330
|
+
if ns.prefix
|
331
|
+
uri_mappings[pfx_lc] = @graph.bind(Namespace.new(ns.href, ns.prefix.to_s))
|
332
|
+
add_debug(element, "extract_mappings: xmlns:#{ns.prefix} => <#{ns.href}>")
|
333
|
+
end
|
334
|
+
|
317
335
|
rescue RdfException => e
|
318
|
-
|
319
|
-
raise if @strict
|
336
|
+
add_error(element, "extract_mappings raised #{e.class}: #{e.message}")
|
320
337
|
end
|
321
338
|
end
|
322
339
|
|
@@ -335,10 +352,8 @@ module RdfContext
|
|
335
352
|
next if prefix == "_"
|
336
353
|
|
337
354
|
uri_mappings[prefix] = @graph.bind(Namespace.new(uri, prefix))
|
355
|
+
add_debug(element, "extract_mappings: prefix #{prefix} => <#{uri}>")
|
338
356
|
end unless @version == :rdfa_1_0
|
339
|
-
|
340
|
-
add_debug(element, "uri_mappings: #{uri_mappings.values.map{|ns|ns.to_s}.join(", ")}")
|
341
|
-
add_debug(element, "term_mappings: #{term_mappings.keys.join(", ")}")
|
342
357
|
end
|
343
358
|
|
344
359
|
# The recursive helper function
|
@@ -351,7 +366,7 @@ module RdfContext
|
|
351
366
|
|
352
367
|
add_debug(element, "traverse, ec: #{evaluation_context.inspect}")
|
353
368
|
|
354
|
-
# local variables [
|
369
|
+
# local variables [7.5 Step 1]
|
355
370
|
recurse = true
|
356
371
|
skip = false
|
357
372
|
new_subject = nil
|
@@ -374,31 +389,54 @@ module RdfContext
|
|
374
389
|
vocab = attrs['vocab']
|
375
390
|
|
376
391
|
# Pull out the attributes needed for the skip test.
|
377
|
-
property = attrs['property'].to_s if attrs['property']
|
378
|
-
typeof = attrs['typeof'].to_s if attrs['typeof']
|
392
|
+
property = attrs['property'].to_s.strip if attrs['property']
|
393
|
+
typeof = attrs['typeof'].to_s.strip if attrs['typeof']
|
379
394
|
datatype = attrs['datatype'].to_s if attrs['datatype']
|
380
395
|
content = attrs['content'].to_s if attrs['content']
|
381
|
-
rel = attrs['rel'].to_s if attrs['rel']
|
382
|
-
rev = attrs['rev'].to_s if attrs['rev']
|
396
|
+
rel = attrs['rel'].to_s.strip if attrs['rel']
|
397
|
+
rev = attrs['rev'].to_s.strip if attrs['rev']
|
383
398
|
|
384
|
-
#
|
385
|
-
#
|
399
|
+
# Local term mappings [7.5 Steps 2]
|
400
|
+
# Next the current element is parsed for any updates to the local term mappings and local list of URI mappings via @profile.
|
401
|
+
# If @profile is present, its value is processed as defined in RDFa Profiles.
|
402
|
+
unless @version == :rdfa_1_0
|
403
|
+
begin
|
404
|
+
process_profile(element) do |which, value|
|
405
|
+
add_debug(element, "[Step 2] traverse, #{which}: #{value.inspect}")
|
406
|
+
case which
|
407
|
+
when :uri_mappings then uri_mappings.merge!(value)
|
408
|
+
when :term_mappings then term_mappings.merge!(value)
|
409
|
+
when :default_vocabulary then default_vocabulary = value
|
410
|
+
end
|
411
|
+
end
|
412
|
+
rescue
|
413
|
+
# Skip this element and all sub-elements
|
414
|
+
# If any referenced RDFa Profile is not available, then the current element and its children must not place any
|
415
|
+
# triples in the default graph .
|
416
|
+
raise if @strict
|
417
|
+
return
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
# Default vocabulary [7.5 Step 3]
|
422
|
+
# Next the current element is examined for any change to the default vocabulary via @vocab.
|
386
423
|
# If @vocab is present and contains a value, its value updates the local default vocabulary.
|
387
424
|
# If the value is empty, then the local default vocabulary must be reset to the Host Language defined default.
|
388
425
|
unless vocab.nil?
|
389
426
|
default_vocabulary = if vocab.to_s.empty?
|
427
|
+
add_debug(element, "[Step 2] traverse, reset default_vocaulary to #{@host_defaults.fetch(:vocabulary, nil).inspect}")
|
390
428
|
# Set default_vocabulary to host language default
|
391
429
|
@host_defaults.fetch(:vocabulary, nil)
|
392
430
|
else
|
393
|
-
URIRef.
|
431
|
+
URIRef.intern(vocab)
|
394
432
|
end
|
395
433
|
add_debug(element, "[Step 2] traverse, default_vocaulary: #{default_vocabulary.inspect}")
|
396
434
|
end
|
397
435
|
|
398
|
-
# Local term mappings [7.5 Steps
|
399
|
-
# Next the current element is
|
400
|
-
#
|
401
|
-
extract_mappings(element, uri_mappings
|
436
|
+
# Local term mappings [7.5 Steps 4]
|
437
|
+
# Next, the current element is then examined for URI mapping s and these are added to the local list of URI mappings.
|
438
|
+
# Note that a URI mapping will simply overwrite any current mapping in the list that has the same name
|
439
|
+
extract_mappings(element, uri_mappings)
|
402
440
|
|
403
441
|
# Language information [7.5 Step 5]
|
404
442
|
# From HTML5 [3.2.3.3]
|
@@ -421,12 +459,12 @@ module RdfContext
|
|
421
459
|
:uri_mappings => uri_mappings,
|
422
460
|
:term_mappings => term_mappings,
|
423
461
|
:vocab => default_vocabulary,
|
424
|
-
:
|
462
|
+
:restrictions => TERMorCURIEorAbsURI[@version])
|
425
463
|
revs = process_uris(element, rev, evaluation_context,
|
426
464
|
:uri_mappings => uri_mappings,
|
427
465
|
:term_mappings => term_mappings,
|
428
466
|
:vocab => default_vocabulary,
|
429
|
-
:
|
467
|
+
:restrictions => TERMorCURIEorAbsURI[@version])
|
430
468
|
|
431
469
|
add_debug(element, "traverse, about: #{about.nil? ? 'nil' : about}, src: #{src.nil? ? 'nil' : src}, resource: #{resource.nil? ? 'nil' : resource}, href: #{href.nil? ? 'nil' : href}")
|
432
470
|
add_debug(element, "traverse, property: #{property.nil? ? 'nil' : property}, typeof: #{typeof.nil? ? 'nil' : typeof}, datatype: #{datatype.nil? ? 'nil' : datatype}, content: #{content.nil? ? 'nil' : content}")
|
@@ -438,15 +476,15 @@ module RdfContext
|
|
438
476
|
new_subject = if about
|
439
477
|
process_uri(element, about, evaluation_context,
|
440
478
|
:uri_mappings => uri_mappings,
|
441
|
-
:
|
479
|
+
:restrictions => SafeCURIEorCURIEorURI[@version])
|
442
480
|
elsif src
|
443
|
-
process_uri(element, src, evaluation_context, :
|
481
|
+
process_uri(element, src, evaluation_context, :restrictions => [:uri])
|
444
482
|
elsif resource
|
445
483
|
process_uri(element, resource, evaluation_context,
|
446
484
|
:uri_mappings => uri_mappings,
|
447
|
-
:
|
485
|
+
:restrictions => SafeCURIEorCURIEorURI[@version])
|
448
486
|
elsif href
|
449
|
-
process_uri(element, href, evaluation_context, :
|
487
|
+
process_uri(element, href, evaluation_context, :restrictions => [:uri])
|
450
488
|
end
|
451
489
|
|
452
490
|
# If no URI is provided by a resource attribute, then the first match from the following rules
|
@@ -459,7 +497,7 @@ module RdfContext
|
|
459
497
|
# From XHTML+RDFa 1.1:
|
460
498
|
# if no URI is provided, then first check to see if the element is the head or body element.
|
461
499
|
# If it is, then act as if there is an empty @about present, and process it according to the rule for @about.
|
462
|
-
|
500
|
+
evaluation_context.base
|
463
501
|
elsif element.attributes['typeof']
|
464
502
|
BNode.new
|
465
503
|
else
|
@@ -472,16 +510,19 @@ module RdfContext
|
|
472
510
|
# [7.5 Step 7]
|
473
511
|
# If the current element does contain a @rel or @rev attribute, then the next step is to
|
474
512
|
# establish both a value for new subject and a value for current object resource:
|
475
|
-
new_subject = process_uri(element, about
|
513
|
+
new_subject = process_uri(element, about, evaluation_context,
|
476
514
|
:uri_mappings => uri_mappings,
|
477
|
-
:
|
478
|
-
|
515
|
+
:restrictions => SafeCURIEorCURIEorURI[@version]) ||
|
516
|
+
process_uri(element, src, evaluation_context,
|
517
|
+
:uri_mappings => uri_mappings,
|
518
|
+
:restrictions => [:uri])
|
519
|
+
|
479
520
|
# If no URI is provided then the first match from the following rules will apply
|
480
521
|
new_subject ||= if @host_language == :xhtml && element.name =~ /^(head|body)$/
|
481
522
|
# From XHTML+RDFa 1.1:
|
482
523
|
# if no URI is provided, then first check to see if the element is the head or body element.
|
483
524
|
# If it is, then act as if there is an empty @about present, and process it according to the rule for @about.
|
484
|
-
|
525
|
+
evaluation_context.base
|
485
526
|
elsif element.attributes['typeof']
|
486
527
|
BNode.new
|
487
528
|
else
|
@@ -494,10 +535,10 @@ module RdfContext
|
|
494
535
|
current_object_resource = if resource
|
495
536
|
process_uri(element, resource, evaluation_context,
|
496
537
|
:uri_mappings => uri_mappings,
|
497
|
-
:
|
538
|
+
:restrictions => SafeCURIEorCURIEorURI[@version])
|
498
539
|
elsif href
|
499
540
|
process_uri(element, href, evaluation_context,
|
500
|
-
:
|
541
|
+
:restrictions => [:uri])
|
501
542
|
end
|
502
543
|
|
503
544
|
add_debug(element, "[Step 7] new_subject: #{new_subject}, current_object_resource = #{current_object_resource.nil? ? 'nil' : current_object_resource}")
|
@@ -505,12 +546,12 @@ module RdfContext
|
|
505
546
|
|
506
547
|
# Process @typeof if there is a subject [Step 8]
|
507
548
|
if new_subject and typeof
|
508
|
-
# Typeof is
|
549
|
+
# Typeof is TERMorCURIEorAbsURIs
|
509
550
|
types = process_uris(element, typeof, evaluation_context,
|
510
551
|
:uri_mappings => uri_mappings,
|
511
552
|
:term_mappings => term_mappings,
|
512
553
|
:vocab => default_vocabulary,
|
513
|
-
:
|
554
|
+
:restrictions => TERMorCURIEorAbsURI[@version])
|
514
555
|
add_debug(element, "typeof: #{typeof}")
|
515
556
|
types.each do |one_type|
|
516
557
|
add_triple(element, new_subject, RDF_TYPE, one_type)
|
@@ -546,7 +587,7 @@ module RdfContext
|
|
546
587
|
:uri_mappings => uri_mappings,
|
547
588
|
:term_mappings => term_mappings,
|
548
589
|
:vocab => default_vocabulary,
|
549
|
-
:
|
590
|
+
:restrictions => TERMorCURIEorAbsURIprop[@version])
|
550
591
|
|
551
592
|
properties.reject! do |p|
|
552
593
|
if p.is_a?(URIRef)
|
@@ -559,28 +600,40 @@ module RdfContext
|
|
559
600
|
end
|
560
601
|
|
561
602
|
# get the literal datatype
|
562
|
-
type = datatype
|
563
603
|
children_node_types = element.children.collect{|c| c.class}.uniq
|
564
604
|
|
565
605
|
# the following 3 IF clauses should be mutually exclusive. Written as is to prevent extensive indentation.
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
current_object_literal = if
|
606
|
+
datatype = process_uri(element, datatype, evaluation_context,
|
607
|
+
:uri_mappings => uri_mappings,
|
608
|
+
:term_mappings => term_mappings,
|
609
|
+
:vocab => default_vocabulary,
|
610
|
+
:restrictions => TERMorCURIEorAbsURI[@version]) unless datatype.to_s.empty?
|
611
|
+
current_object_literal = if !datatype.to_s.empty? && datatype.to_s != XML_LITERAL.to_s
|
572
612
|
# typed literal
|
573
613
|
add_debug(element, "[Step 11] typed literal")
|
574
|
-
Literal.typed(content || element.inner_text,
|
575
|
-
elsif
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
614
|
+
Literal.typed(content || element.inner_text, datatype, :language => language)
|
615
|
+
elsif @version == :rdfa_1_1
|
616
|
+
if datatype.to_s == XML_LITERAL.to_s
|
617
|
+
# XML Literal
|
618
|
+
add_debug(element, "[Step 11(1.1)] XML Literal: #{element.inner_html}")
|
619
|
+
recurse = false
|
620
|
+
Literal.typed(element.children, XML_LITERAL, :language => language, :namespaces => uri_mappings)
|
621
|
+
else
|
622
|
+
# plain literal
|
623
|
+
add_debug(element, "[Step 11(1.1)] plain literal")
|
624
|
+
Literal.untyped(content || element.inner_text, language)
|
625
|
+
end
|
626
|
+
else
|
627
|
+
if content || (children_node_types == [Nokogiri::XML::Text]) || (element.children.length == 0) || datatype == ""
|
628
|
+
# plain literal
|
629
|
+
add_debug(element, "[Step 11 (1.0)] plain literal")
|
630
|
+
Literal.untyped(content || element.inner_text, language)
|
631
|
+
elsif children_node_types != [Nokogiri::XML::Text] and (datatype == nil or datatype.to_s == XML_LITERAL.to_s)
|
632
|
+
# XML Literal
|
633
|
+
add_debug(element, "[Step 11 (1.0)] XML Literal: #{element.inner_html}")
|
634
|
+
recurse = false
|
635
|
+
Literal.typed(element.children, XML_LITERAL, :language => language, :namespaces => uri_mappings)
|
636
|
+
end
|
584
637
|
end
|
585
638
|
|
586
639
|
# add each property
|
@@ -640,7 +693,7 @@ module RdfContext
|
|
640
693
|
end
|
641
694
|
end
|
642
695
|
|
643
|
-
# space-separated
|
696
|
+
# space-separated TERMorCURIEorAbsURI or SafeCURIEorCURIEorURI
|
644
697
|
def process_uris(element, value, evaluation_context, options)
|
645
698
|
return [] if value.to_s.empty?
|
646
699
|
add_debug(element, "process_uris: #{value}")
|
@@ -649,8 +702,8 @@ module RdfContext
|
|
649
702
|
|
650
703
|
def process_uri(element, value, evaluation_context, options = {})
|
651
704
|
return if value.nil?
|
652
|
-
restrictions =
|
653
|
-
add_debug(element, "process_uri: restrictions = #{restrictions.inspect}")
|
705
|
+
restrictions = options[:restrictions]
|
706
|
+
add_debug(element, "process_uri: #{value}, restrictions = #{restrictions.inspect}")
|
654
707
|
options = {:uri_mappings => {}}.merge(options)
|
655
708
|
if !options[:term_mappings] && options[:uri_mappings] && value.to_s.match(/^\[(.*)\]$/) && restrictions.include?(:safe_curie)
|
656
709
|
# SafeCURIEorCURIEorURI
|
@@ -659,25 +712,38 @@ module RdfContext
|
|
659
712
|
# value must be ignored.
|
660
713
|
uri = curie_to_resource_or_bnode(element, $1, options[:uri_mappings], evaluation_context.parent_subject, restrictions)
|
661
714
|
add_debug(element, "process_uri: #{value} => safeCURIE => <#{uri}>")
|
715
|
+
|
662
716
|
uri
|
663
717
|
elsif options[:term_mappings] && NC_REGEXP.match(value.to_s) && restrictions.include?(:term)
|
664
|
-
#
|
718
|
+
# TERMorCURIEorAbsURI
|
665
719
|
# If the value is an NCName, then it is evaluated as a term according to General Use of Terms in
|
666
720
|
# Attributes. Note that this step may mean that the value is to be ignored.
|
667
|
-
uri = process_term(value.to_s, options)
|
721
|
+
uri = process_term(element, value.to_s, options)
|
668
722
|
add_debug(element, "process_uri: #{value} => term => <#{uri}>")
|
669
723
|
uri
|
670
724
|
else
|
671
|
-
# SafeCURIEorCURIEorURI or
|
725
|
+
# SafeCURIEorCURIEorURI or TERMorCURIEorAbsURI
|
672
726
|
# Otherwise, the value is evaluated as a CURIE.
|
673
727
|
# If it is a valid CURIE, the resulting URI is used; otherwise, the value will be processed as a URI.
|
674
728
|
uri = curie_to_resource_or_bnode(element, value, options[:uri_mappings], evaluation_context.parent_subject, restrictions)
|
675
729
|
if uri
|
676
730
|
add_debug(element, "process_uri: #{value} => CURIE => <#{uri}>")
|
677
|
-
elsif @version == :rdfa_1_0 && value.to_s.match(/^xml/)
|
731
|
+
elsif @version == :rdfa_1_0 && value.to_s.match(/^xml/i)
|
678
732
|
# Special case to not allow anything starting with XML to be treated as a URI
|
679
|
-
|
680
|
-
|
733
|
+
elsif restrictions.include?(:absuri) || restrictions.include?(:uri)
|
734
|
+
begin
|
735
|
+
# AbsURI does not use xml:base
|
736
|
+
uri = URIRef.intern(value, restrictions.include?(:absuri) ? nil : evaluation_context.base, :normalize => false)
|
737
|
+
rescue Addressable::URI::InvalidURIError => e
|
738
|
+
add_warning(element, "Malformed prefix #{value}", RDFA_NS.UndefinedPrefixError)
|
739
|
+
rescue ParserException => e
|
740
|
+
add_debug(element, e.message)
|
741
|
+
if value.to_s =~ /^\(^\w\):/
|
742
|
+
add_warning(element, "Undefined prefix #{$1}", RDFA_NS.UndefinedPrefixError)
|
743
|
+
else
|
744
|
+
add_warning(element, "Relative URI #{value}")
|
745
|
+
end
|
746
|
+
end
|
681
747
|
add_debug(element, "process_uri: #{value} => URI => <#{uri}>")
|
682
748
|
end
|
683
749
|
uri
|
@@ -690,17 +756,17 @@ module RdfContext
|
|
690
756
|
# @param [Hash] options:: Parser options, one of
|
691
757
|
# <em>options[:term_mappings]</em>:: Term mappings
|
692
758
|
# <em>options[:vocab]</em>:: Default vocabulary
|
693
|
-
def process_term(value, options)
|
759
|
+
def process_term(element, value, options)
|
694
760
|
case
|
695
761
|
when options[:term_mappings].is_a?(Hash) && options[:term_mappings].has_key?(value.to_s.downcase)
|
696
762
|
# If the term is in the local term mappings, use the associated URI.
|
697
|
-
# XXX Spec Confusion: are terms always downcased? Or only for XHTML Vocab?
|
698
763
|
options[:term_mappings][value.to_s.downcase]
|
699
764
|
when options[:vocab]
|
700
765
|
# Otherwise, if there is a local default vocabulary the URI is obtained by concatenating that value and the term.
|
701
|
-
URIRef.
|
766
|
+
URIRef.intern(options[:vocab].to_s + value)
|
702
767
|
else
|
703
768
|
# Finally, if there is no local default vocabulary, the term has no associated URI and must be ignored.
|
769
|
+
add_warning(element, "Term #{value} is not defined", RDFA_NS.UndefinedTermError)
|
704
770
|
nil
|
705
771
|
end
|
706
772
|
end
|
@@ -713,6 +779,7 @@ module RdfContext
|
|
713
779
|
# consider the bnode situation
|
714
780
|
if prefix == "_" && restrictions.include?(:bnode)
|
715
781
|
# we force a non-nil name, otherwise it generates a new name
|
782
|
+
# As a special case, _: is also a valid reference for one specific bnode.
|
716
783
|
BNode.new(reference || "", @named_bnodes)
|
717
784
|
elsif curie.to_s.match(/^:/)
|
718
785
|
add_debug(element, "curie_to_resource_or_bnode: default prefix: defined? #{!!uri_mappings[""]}, defaults: #{@host_defaults[:prefix]}")
|
@@ -721,6 +788,9 @@ module RdfContext
|
|
721
788
|
uri_mappings[""].send("#{reference}_")
|
722
789
|
elsif @host_defaults[:prefix]
|
723
790
|
@host_defaults[:prefix].send("#{reference}_")
|
791
|
+
else
|
792
|
+
#add_warning(element, "Default namespace prefix is not defined", RDFA_NS.UndefinedPrefixError)
|
793
|
+
nil
|
724
794
|
end
|
725
795
|
elsif !curie.to_s.match(/:/)
|
726
796
|
# No prefix, undefined (in this context, it is evaluated as a term elsewhere)
|
@@ -732,7 +802,7 @@ module RdfContext
|
|
732
802
|
if ns
|
733
803
|
ns + reference
|
734
804
|
else
|
735
|
-
add_debug(element, "curie_to_resource_or_bnode No namespace mapping for #{prefix}")
|
805
|
+
#add_debug(element, "curie_to_resource_or_bnode No namespace mapping for #{prefix}")
|
736
806
|
nil
|
737
807
|
end
|
738
808
|
end
|