rdf_context 0.5.7 → 0.5.8.1

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.
Files changed (59) hide show
  1. data/History.rdoc +15 -1
  2. data/README.rdoc +2 -0
  3. data/Rakefile +2 -4
  4. data/VERSION +1 -1
  5. data/bin/rdf_context +5 -54
  6. data/lib/rdf_context.rb +5 -0
  7. data/lib/rdf_context/graph.rb +68 -49
  8. data/lib/rdf_context/n3parser.rb +2 -2
  9. data/lib/rdf_context/namespace.rb +1 -1
  10. data/lib/rdf_context/nokogiri_hacks.rb +7 -0
  11. data/lib/rdf_context/parser.rb +57 -13
  12. data/lib/rdf_context/rdfaparser.rb +200 -130
  13. data/lib/rdf_context/rdfxmlparser.rb +8 -8
  14. data/lib/rdf_context/serializer/recursive_serializer.rb +1 -1
  15. data/lib/rdf_context/serializer/turtle_serializer.rb +15 -15
  16. data/lib/rdf_context/serializer/xml_serializer.rb +8 -8
  17. data/lib/rdf_context/store/memory_store.rb +14 -14
  18. data/lib/rdf_context/store/sqlite3_store.rb +4 -4
  19. data/lib/rdf_context/uriref.rb +11 -4
  20. data/script/console +1 -3
  21. data/script/tc +44 -0
  22. data/spec/.gitignore +1 -0
  23. data/spec/aggregate_graph_spec.rb +1 -0
  24. data/spec/bnode_spec.rb +2 -1
  25. data/spec/conjunctive_graph_spec.rb +1 -0
  26. data/spec/cwm_spec.rb +1 -0
  27. data/spec/duration_spec.rb +1 -0
  28. data/spec/graph_spec.rb +27 -0
  29. data/spec/list_store_spec.rb +1 -0
  30. data/spec/literal_spec.rb +1 -0
  31. data/spec/matchers.rb +1 -1
  32. data/spec/memory_store_spec.rb +1 -0
  33. data/spec/n3parser_spec.rb +1 -0
  34. data/spec/namespaces_spec.rb +1 -0
  35. data/spec/parser_spec.rb +1 -0
  36. data/spec/rdf_helper.rb +4 -4
  37. data/spec/rdfa_helper.rb +24 -0
  38. data/spec/rdfa_parser_spec.rb +6 -36
  39. data/spec/rdfcore/.gitignore +1 -0
  40. data/spec/rdfxml_spec.rb +1 -0
  41. data/spec/sqlite3_store_spec.rb +1 -0
  42. data/spec/string_hacks_spec.rb +2 -0
  43. data/spec/swap_test/.gitignore +1 -0
  44. data/spec/triple_spec.rb +1 -0
  45. data/spec/turtle/.gitignore +1 -0
  46. data/spec/turtle_serializer_spec.rb +3 -2
  47. data/spec/turtle_spec.rb +1 -0
  48. data/spec/uriref_spec.rb +13 -12
  49. data/spec/xml_serializer_spec.rb +7 -6
  50. metadata +26 -61
  51. data/spec/html4-manifest.yml +0 -4937
  52. data/spec/html5-manifest.yml +0 -4937
  53. data/spec/rdfcore/Manifest.yml +0 -6242
  54. data/spec/swap_test/n3parser.yml +0 -773
  55. data/spec/swap_test/regression.yml +0 -902
  56. data/spec/turtle/manifest-bad.yml +0 -807
  57. data/spec/turtle/manifest.yml +0 -807
  58. data/spec/xhtml-manifest.yml +0 -3901
  59. 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/ED-rdfa-core-20100705/ RDFa 1.1
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 [String] base
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
- raise ParserException, "Empty document" if @doc.nil? && @strict
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
- # Determine host language
161
- # XXX - right now only XHTML defined
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.new(base, :normalize => false, :normalize => false)
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(base, @host_defaults)
228
+ evaluation_context = EvaluationContext.new(@uri, @host_defaults)
215
229
 
216
230
  traverse(doc.root, evaluation_context)
217
231
  end
218
232
 
219
- # Extract the XMLNS mappings from an element
220
- def extract_mappings(element, uri_mappings, term_mappings)
221
- # Process @profile
222
- # Next the current element is parsed for any updates to the local term mappings and
223
- # local list of URI mappings via @profile.
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, "extract_mappings: skip recursive profile <#{profile}>")
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, "extract_mappings: skip previously parsed profile <#{profile}>")
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, "extract_mappings: profile open <#{profile}>")
242
- require 'patron' unless defined?(Patron)
243
- sess = Patron::Session.new
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, = $DEBUG, $verbose
250
- $DEBUG, $verbose = false, false
251
- p_graph = Parser.parse(resp.body, profile)
252
- ttl = p_graph.serialize(:format => :ttl) if @debug || $DEBUG
253
- $DEBUG, $verbose = old_debug, old_verbose
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
- add_debug(element, "extract_mappings: uri=#{uri.inspect}, term=#{term.inspect}, prefix=#{prefix.inspect}")
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
- next if !uri || (!term && !prefix)
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
- raise ParserException, "rdf:uri must be a Literal" unless uri.is_a?(Literal)
275
- raise ParserException, "rdf:term must be a Literal" unless term.nil? || term.is_a?(Literal)
276
- raise ParserException, "rdf:prefix must be a Literal" unless prefix.nil? || prefix.is_a?(Literal)
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.new(uri.to_s, :normalize => false) if term
301
+ tm[term.to_s.downcase] = URIRef.intern(uri.to_s, :normalize => false) if term
289
302
  end
290
- rescue ParserException
291
- add_debug(element, "extract_mappings: profile subject #{subject.to_s}: #{e.message}")
292
- raise if @strict
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
- # Merge mappings from this vocabulary
300
- uri_mappings.merge!(@@vocabulary_cache[profile][:uri_mappings])
301
- term_mappings.merge!(@@vocabulary_cache[profile][:term_mappings])
302
- end unless @version == :rdfa_1_0
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.namespaces.each do |attr_name, attr_value|
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
- pfx_lc = @version == :rdfa_1_0 || prefix.nil? ? prefix : prefix.to_s.downcase
316
- uri_mappings[pfx_lc] = @graph.bind(Namespace.new(attr_value, prefix.to_s)) if abbr.downcase == "xmlns" && prefix
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
- add_debug(element, "extract_mappings raised #{e.class}: #{e.message}")
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 [5.5 Step 1]
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
- # Default vocabulary [7.5 Step 2]
385
- # First the current element is examined for any change to the default vocabulary via @vocab.
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.new(vocab)
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 3 & 4]
399
- # Next the current element is parsed for any updates to the local term mappings and local list of URI mappings via @profile.
400
- # If @profile is present, its value is processed as defined in RDFa Profiles.
401
- extract_mappings(element, uri_mappings, term_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
- :r_1_0_restrictions => [:uri, :bnode, :term])
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
- :r_1_0_restrictions => [:uri, :bnode, :term])
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
- :r_1_0_restrictions => [:uri, :safe_curie, :bnode])
479
+ :restrictions => SafeCURIEorCURIEorURI[@version])
442
480
  elsif src
443
- process_uri(element, src, evaluation_context, :r_1_0_restrictions => [:uri])
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
- :r_1_0_restrictions => [:uri, :safe_curie, :bnode])
485
+ :restrictions => SafeCURIEorCURIEorURI[@version])
448
486
  elsif href
449
- process_uri(element, href, evaluation_context, :r_1_0_restrictions => [:uri])
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
- URIRef.new(evaluation_context.base, :normalize => false)
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 || src, evaluation_context,
513
+ new_subject = process_uri(element, about, evaluation_context,
476
514
  :uri_mappings => uri_mappings,
477
- :r_1_0_restrictions => [:uri, :safe_curie, :bnode])
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
- URIRef.new(evaluation_context.base, :normalize => false)
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
- :r_1_0_restrictions => [:uri, :safe_curie, :bnode])
538
+ :restrictions => SafeCURIEorCURIEorURI[@version])
498
539
  elsif href
499
540
  process_uri(element, href, evaluation_context,
500
- :r_1_0_restrictions => [:uri])
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 TERMorCURIEorURIs
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
- :r_1_0_restrictions => [:curie, :bnode])
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
- :r_1_0_restrictions => [:curie, :bnode])
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
- type_resource = process_uri(element, type, evaluation_context,
567
- :uri_mappings => uri_mappings,
568
- :term_mappings => term_mappings,
569
- :vocab => default_vocabulary,
570
- :r_1_0_restrictions => [:curie, :bnode]) if type
571
- current_object_literal = if type and !type.empty? and (type_resource.to_s != XML_LITERAL.to_s)
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, type_resource, :language => language)
575
- elsif content or (children_node_types == [Nokogiri::XML::Text]) or (element.children.length == 0) or (type == '')
576
- # plain literal
577
- add_debug(element, "[Step 11] plain literal")
578
- Literal.untyped(content || element.inner_text, language)
579
- elsif children_node_types != [Nokogiri::XML::Text] and (type == nil or type_resource.to_s == XML_LITERAL.to_s)
580
- # XML Literal
581
- add_debug(element, "[Step 11] XML Literal: #{element.inner_html}")
582
- recurse = false
583
- Literal.typed(element.children, XML_LITERAL, :language => language, :namespaces => uri_mappings)
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 TERMorCURIEorURI
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 = @version == :rdfa_1_0 ? options[:r_1_0_restrictions] : [:uri, :bnode, :curie, :safe_curie, :term]
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
- # TERMorCURIEorURI
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 TERMorCURIEorURI
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
- else
680
- uri = URIRef.new(value, evaluation_context.base, :normalize => false)
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.new(options[:vocab].to_s + value)
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