rdf-rdfa 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. data/.gitignore +2 -0
  2. data/.yardopts +3 -1
  3. data/History.rdoc +52 -0
  4. data/README.rdoc +2 -2
  5. data/Rakefile +12 -17
  6. data/VERSION +1 -1
  7. data/lib/rdf/.gitignore +2 -0
  8. data/lib/rdf/rdfa.rb +1 -1
  9. data/lib/rdf/rdfa/patches/literal_hacks.rb +15 -17
  10. data/lib/rdf/rdfa/profile.rb +167 -0
  11. data/lib/rdf/rdfa/reader.rb +287 -199
  12. data/lib/rdf/rdfa/version.rb +4 -7
  13. data/lib/rdf/rdfa/vocab.rb +1 -0
  14. data/rdf-rdfa.gemspec +16 -125
  15. data/script/parse +16 -9
  16. data/script/tc +29 -13
  17. data/spec/html4-manifest.yml +491 -3855
  18. data/spec/html5-manifest.yml +491 -3855
  19. data/spec/literal_spec.rb +7 -8
  20. data/spec/profile_spec.rb +53 -0
  21. data/spec/rdfa_helper.rb +48 -47
  22. data/spec/rdfa_reader_spec.rb +312 -172
  23. data/spec/spec_helper.rb +12 -3
  24. data/spec/svgtiny-manifest.yml +37 -0
  25. data/spec/xhtml-manifest.yml +533 -2824
  26. metadata +19 -126
  27. data/History.txt +0 -30
  28. data/lib/rdf/rdfa/patches/uri_hacks.rb +0 -24
  29. data/spec/rdfa-triples/0001.nt +0 -1
  30. data/spec/rdfa-triples/0006.nt +0 -2
  31. data/spec/rdfa-triples/0007.nt +0 -3
  32. data/spec/rdfa-triples/0008.nt +0 -1
  33. data/spec/rdfa-triples/0009.nt +0 -1
  34. data/spec/rdfa-triples/0010.nt +0 -2
  35. data/spec/rdfa-triples/0011.nt +0 -3
  36. data/spec/rdfa-triples/0012.nt +0 -1
  37. data/spec/rdfa-triples/0013.nt +0 -1
  38. data/spec/rdfa-triples/0014.nt +0 -1
  39. data/spec/rdfa-triples/0015.nt +0 -2
  40. data/spec/rdfa-triples/0017.nt +0 -3
  41. data/spec/rdfa-triples/0018.nt +0 -1
  42. data/spec/rdfa-triples/0019.nt +0 -1
  43. data/spec/rdfa-triples/0020.nt +0 -1
  44. data/spec/rdfa-triples/0021.nt +0 -1
  45. data/spec/rdfa-triples/0023.nt +0 -1
  46. data/spec/rdfa-triples/0025.nt +0 -2
  47. data/spec/rdfa-triples/0026.nt +0 -1
  48. data/spec/rdfa-triples/0027.nt +0 -1
  49. data/spec/rdfa-triples/0029.nt +0 -1
  50. data/spec/rdfa-triples/0030.nt +0 -1
  51. data/spec/rdfa-triples/0031.nt +0 -1
  52. data/spec/rdfa-triples/0032.nt +0 -1
  53. data/spec/rdfa-triples/0033.nt +0 -2
  54. data/spec/rdfa-triples/0034.nt +0 -1
  55. data/spec/rdfa-triples/0035.nt +0 -1
  56. data/spec/rdfa-triples/0036.nt +0 -1
  57. data/spec/rdfa-triples/0037.nt +0 -1
  58. data/spec/rdfa-triples/0038.nt +0 -1
  59. data/spec/rdfa-triples/0039.nt +0 -1
  60. data/spec/rdfa-triples/0040.nt +0 -1
  61. data/spec/rdfa-triples/0041.nt +0 -1
  62. data/spec/rdfa-triples/0042.nt +0 -0
  63. data/spec/rdfa-triples/0046.nt +0 -3
  64. data/spec/rdfa-triples/0047.nt +0 -3
  65. data/spec/rdfa-triples/0048.nt +0 -3
  66. data/spec/rdfa-triples/0049.nt +0 -2
  67. data/spec/rdfa-triples/0050.nt +0 -2
  68. data/spec/rdfa-triples/0051.nt +0 -2
  69. data/spec/rdfa-triples/0052.nt +0 -1
  70. data/spec/rdfa-triples/0053.nt +0 -2
  71. data/spec/rdfa-triples/0054.nt +0 -2
  72. data/spec/rdfa-triples/0055.nt +0 -2
  73. data/spec/rdfa-triples/0056.nt +0 -3
  74. data/spec/rdfa-triples/0057.nt +0 -4
  75. data/spec/rdfa-triples/0058.nt +0 -6
  76. data/spec/rdfa-triples/0059.nt +0 -6
  77. data/spec/rdfa-triples/0060.nt +0 -2
  78. data/spec/rdfa-triples/0061.nt +0 -1
  79. data/spec/rdfa-triples/0062.nt +0 -1
  80. data/spec/rdfa-triples/0063.nt +0 -1
  81. data/spec/rdfa-triples/0064.nt +0 -1
  82. data/spec/rdfa-triples/0065.nt +0 -3
  83. data/spec/rdfa-triples/0066.nt +0 -1
  84. data/spec/rdfa-triples/0067.nt +0 -1
  85. data/spec/rdfa-triples/0068.nt +0 -1
  86. data/spec/rdfa-triples/0069.nt +0 -1
  87. data/spec/rdfa-triples/0070.nt +0 -1
  88. data/spec/rdfa-triples/0071.nt +0 -1
  89. data/spec/rdfa-triples/0072.nt +0 -1
  90. data/spec/rdfa-triples/0073.nt +0 -1
  91. data/spec/rdfa-triples/0074.nt +0 -1
  92. data/spec/rdfa-triples/0075.nt +0 -1
  93. data/spec/rdfa-triples/0076.nt +0 -23
  94. data/spec/rdfa-triples/0077.nt +0 -23
  95. data/spec/rdfa-triples/0078.nt +0 -6
  96. data/spec/rdfa-triples/0079.nt +0 -3
  97. data/spec/rdfa-triples/0080.nt +0 -1
  98. data/spec/rdfa-triples/0081.nt +0 -6
  99. data/spec/rdfa-triples/0082.nt +0 -8
  100. data/spec/rdfa-triples/0083.nt +0 -6
  101. data/spec/rdfa-triples/0084.nt +0 -8
  102. data/spec/rdfa-triples/0085.nt +0 -4
  103. data/spec/rdfa-triples/0086.nt +0 -0
  104. data/spec/rdfa-triples/0087.nt +0 -23
  105. data/spec/rdfa-triples/0088.nt +0 -3
  106. data/spec/rdfa-triples/0089.nt +0 -1
  107. data/spec/rdfa-triples/0090.nt +0 -1
  108. data/spec/rdfa-triples/0091.nt +0 -3
  109. data/spec/rdfa-triples/0092.nt +0 -3
  110. data/spec/rdfa-triples/0093.nt +0 -2
  111. data/spec/rdfa-triples/0094.nt +0 -3
  112. data/spec/rdfa-triples/0099.nt +0 -1
  113. data/spec/rdfa-triples/0100.nt +0 -1
  114. data/spec/rdfa-triples/0101.nt +0 -1
  115. data/spec/rdfa-triples/0102.nt +0 -1
  116. data/spec/rdfa-triples/0103.nt +0 -1
  117. data/spec/rdfa-triples/0104.nt +0 -3
  118. data/spec/rdfa-triples/0105.nt +0 -1
  119. data/spec/rdfa-triples/0106.nt +0 -1
  120. data/spec/rdfa-triples/0107.nt +0 -0
  121. data/spec/rdfa-triples/0108.nt +0 -1
  122. data/spec/rdfa-triples/0109.nt +0 -1
  123. data/spec/rdfa-triples/0110.nt +0 -1
  124. data/spec/rdfa-triples/0111.nt +0 -2
  125. data/spec/rdfa-triples/0112.nt +0 -1
  126. data/spec/rdfa-triples/0113.nt +0 -2
  127. data/spec/rdfa-triples/0114.nt +0 -3
  128. data/spec/rdfa-triples/0115.nt +0 -4
  129. data/spec/rdfa-triples/0116.nt +0 -2
  130. data/spec/rdfa-triples/0117.nt +0 -2
  131. data/spec/rdfa-triples/0118.nt +0 -1
  132. data/spec/rdfa-triples/0119.nt +0 -1
  133. data/spec/rdfa-triples/0120.nt +0 -1
  134. data/spec/rdfa-triples/0121.nt +0 -2
  135. data/spec/rdfa-triples/0122.nt +0 -1
  136. data/spec/rdfa-triples/0123.nt +0 -3
  137. data/spec/rdfa-triples/0124.nt +0 -4
  138. data/spec/rdfa-triples/0125.nt +0 -1
  139. data/spec/rdfa-triples/0126.nt +0 -3
  140. data/spec/rdfa-triples/1001.nt +0 -6
  141. data/spec/xhtml11-manifest.yml +0 -4707
data/.gitignore CHANGED
@@ -1,2 +1,4 @@
1
1
  /.DS_Store
2
2
  /pkg
3
+ /doc/
4
+ /.yardoc/
data/.yardopts CHANGED
@@ -1,4 +1,4 @@
1
- --title "RDF::RDFa - XHTML+RDFa Support for RDF.rb"
1
+ --title "RDFa parser for RDF.rb."
2
2
  --output-dir doc/yard
3
3
  --protected
4
4
  --no-private
@@ -6,6 +6,8 @@
6
6
  --markup rdoc
7
7
  --readme README.rdoc
8
8
  -
9
+ READEME.rdoc
9
10
  AUTHORS
11
+ History.rdoc
10
12
  CONTRIBUTORS
11
13
  VERSION
data/History.rdoc ADDED
@@ -0,0 +1,52 @@
1
+ === 0.3.0
2
+ * RDF.rb 0.3.0 compatibility updates
3
+ * Remove literal_normalization and qname_hacks, add back uri_hacks (until 0.3.0)
4
+ * URI canonicalization and validation.
5
+ * Added :canonicalize, and :intern options.
6
+ * Change :strict option to :validate.
7
+ * Add check to ensure that predicates are not literals, it's not legal in any RDF variant.
8
+ * Collect prefixes when extracting mappings.
9
+ * Added :profile_repository option to RDF::RDFa::Reader.initialize. This MUST be an RDF::Repository and will be used to save profiles that are encountered.
10
+ * Fixme, for now, retrieval should include HTTP headers and perform appropriate HTTP cache control and check for potential updates.
11
+ * Update to 2010-10-26 LC version of RDFa Core 1.1
12
+ * Deep processing of XMLLiterals
13
+ * Case sensitive Terms
14
+ * Updated processor graph vocabulary
15
+ * Upgrade for changes to RDFa 1.1 test suite
16
+ * Allow use of xml:base for non-HTML languages
17
+ * XHTML has no default vocabulary.
18
+ * No longer pass vocabularies, prefixes or terms when creating XMLLiterals. Only namespaces derived via xmlns are passed to Literal#typed.
19
+ * Literal::XML
20
+ * Add all in-scope namespaces, not just those that seem to be used.
21
+ * RSpec 2 compatibility.
22
+
23
+ === 0.2.2
24
+ * Ruby 1.9.2 compatibility
25
+ * Added script/parse as command-line option for parsing files.
26
+ * Add back support for RDFa 1.0 as well as RDFa 1.1. Parser checks @version to determine which
27
+ * Update RDFa processing to WD-rdfa-core-20100803 semantics
28
+ * Added Processor Graph and required output
29
+ * Reverse order of processing profiles
30
+ * Don't process element if any profile fails
31
+ * XMLLiterals must be explicitly specified as @datatype
32
+ * TERMorCURIEorAbsURI requires an absolute URI, not document relative
33
+ * Extract a new default vocabulary from @profile.
34
+
35
+ === 0.2.1
36
+ * Update for RDF 0.2.1
37
+
38
+ === 0.2.0
39
+ * Updates for RDF 0.2.0
40
+ * Use URI#intern instead of URI#new
41
+ * Change use of Graph#predicates and Graph#objects to use as enumerables
42
+
43
+ === 0.0.3
44
+ * Removed internal graph in Reader and implement each_triple & each_statement to perform parsing
45
+
46
+ === 0.0.2
47
+ * Remove dependency on Namespace
48
+ * Changed to RDF::RDFa, and moved files accordingly.
49
+ * Added vocab definitions for RDA, XHV, XML, XSI and OWL
50
+
51
+ === 0.0.1
52
+ * First port from RdfContext version 0.5.4
data/README.rdoc CHANGED
@@ -25,7 +25,7 @@ Instantiate a parser and parse source, specifying type and base-URL
25
25
  end
26
26
 
27
27
  == Dependencies
28
- * [RDF.rb](http://rubygems.org/gems/rdf) (>= 0.2.0)
28
+ * [RDF.rb](http://rubygems.org/gems/rdf) (>= 0.3.0)
29
29
  * [Nokogiri](http://rubygems.org/gems/nokogiri) (>= 1.3.3)
30
30
 
31
31
  == TODO
@@ -37,7 +37,7 @@ Instantiate a parser and parse source, specifying type and base-URL
37
37
  == Resources:
38
38
  * RDF.rb[http://rdf.rubyforge.org/]
39
39
  * Distiller[http://kellogg-assoc/distiller]
40
- * RDoc[http://rdoc.info/projects/gkellogg/rdf-rdfa]
40
+ * RDoc[http://rdoc.info/github/gkellogg/rdf-rdfa]
41
41
  * History[http://github.com/gkellogg/rdf-rdfa/blob/master/History.txt]
42
42
  * "RDFa 1.1 Core"[http://www.w3.org/TR/2010/WD-rdfa-core-20100422/]
43
43
  * "XHTML+RDFa 1.1 Core"[http://www.w3.org/TR/2010/WD-xhtml-rdfa-20100422/]
data/Rakefile CHANGED
@@ -13,39 +13,32 @@ begin
13
13
  gemspec.email = "gregg@kellogg-assoc.com"
14
14
  gemspec.homepage = "http://github.com/gkellogg/rdf-rdfa"
15
15
  gemspec.authors = ["Gregg Kellogg"]
16
- gemspec.add_dependency('rdf', '>= 0.2.1')
16
+ gemspec.add_dependency('rdf', '>= 0.3.0')
17
17
  gemspec.add_dependency('nokogiri', '>= 1.3.3')
18
- gemspec.add_development_dependency('rspec')
18
+ gemspec.add_development_dependency('rspec', '>= 2.1.0')
19
19
  gemspec.add_development_dependency('rdf-spec', '>= 0.2.1')
20
20
  gemspec.add_development_dependency('rdf-rdfxml', '>= 0.2.1')
21
21
  gemspec.add_development_dependency('rdf-isomorphic')
22
22
  gemspec.add_development_dependency('yard')
23
- gemspec.extra_rdoc_files = %w(README.rdoc History.txt AUTHORS CONTRIBUTORS)
23
+ gemspec.extra_rdoc_files = %w(README.rdoc History.rdoc AUTHORS CONTRIBUTORS)
24
24
  end
25
25
  Jeweler::GemcutterTasks.new
26
26
  rescue LoadError
27
27
  puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
28
28
  end
29
29
 
30
- require 'spec/rake/spectask'
31
- Spec::Rake::SpecTask.new(:spec) do |spec|
32
- spec.libs << 'lib' << 'spec'
33
- spec.spec_files = FileList['spec/*_spec.rb']
34
- end
30
+ require 'rspec/core/rake_task'
31
+ RSpec::Core::RakeTask.new(:spec)
35
32
 
36
33
  desc "Run specs through RCov"
37
- Spec::Rake::SpecTask.new("spec:rcov") do |spec|
38
- spec.libs << 'lib' << 'spec'
39
- spec.pattern = 'spec/*_spec.rb'
34
+ RSpec::Core::RakeTask.new("spec:rcov") do |spec|
40
35
  spec.rcov = true
41
- spec.rcov_opts = ['-x', '/Library', '-x', '/System/Library', '-x', 'spec']
36
+ spec.rcov_opts = %q[--exclude "spec"]
42
37
  end
43
38
 
44
39
  desc "Generate HTML report specs"
45
- Spec::Rake::SpecTask.new("doc:spec") do |spec|
46
- spec.libs << 'lib' << 'spec'
47
- spec.spec_files = FileList['spec/*_spec.rb']
48
- spec.spec_opts = ["--format", "html:doc/spec.html"]
40
+ RSpec::Core::RakeTask.new("doc:spec") do |spec|
41
+ spec.rspec_opts = ["--format", "html", "-o", "doc/spec.html"]
49
42
  end
50
43
 
51
44
  YARD::Rake::YardocTask.new do |t|
@@ -60,10 +53,12 @@ namespace :spec do
60
53
  require 'spec/rdfa_helper'
61
54
  require 'fileutils'
62
55
 
63
- %w(xhtml xhtml11 html4 html5).each do |suite|
56
+ %w(xhtml html4 html5 svgtiny).each do |suite|
64
57
  yaml = manifest_file = File.join(File.dirname(__FILE__), "spec", "#{suite}-manifest.yml")
65
58
  FileUtils.rm_f(yaml)
59
+ #RDF::RDFa.debug = true
66
60
  RdfaHelper::TestCase.to_yaml(suite, yaml)
61
+ #RDF::RDFa.debug = false
67
62
  end
68
63
  end
69
64
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.2
1
+ 0.3.0
@@ -0,0 +1,2 @@
1
+ /rdfxml
2
+ /rdfxml.rb
data/lib/rdf/rdfa.rb CHANGED
@@ -27,7 +27,7 @@ module RDF
27
27
  require 'rdf/rdfa/vocab'
28
28
  require 'rdf/rdfa/patches/literal_hacks'
29
29
  require 'rdf/rdfa/patches/nokogiri_hacks'
30
- require 'rdf/rdfa/patches/uri_hacks'
30
+ autoload :Profile, 'rdf/rdfa/profile'
31
31
  autoload :Reader, 'rdf/rdfa/reader'
32
32
  autoload :VERSION, 'rdf/rdfa/version'
33
33
 
@@ -20,7 +20,7 @@ module RDF; class Literal
20
20
  ##
21
21
  # @param [Object] value
22
22
  # @option options [String] :lexical (nil)
23
- # @option options [Hash] :namespaces ({}) Use :__default__ or "" to declare default namespace
23
+ # @option options [Hash] :namespaces ({}) Use "" to declare default namespace
24
24
  # @option options [Symbol] :language (nil)
25
25
  # @option options [:nokogiri, :libxml, or :rexml] :library
26
26
  def initialize(value, options = {})
@@ -68,17 +68,15 @@ module RDF; class Literal
68
68
  def parse_value(value, options)
69
69
  ns_hash = {}
70
70
  options[:namespaces].each_pair do |prefix, uri|
71
- prefix = prefix == :__default__ ? "" : prefix.to_s
71
+ prefix = prefix.to_s
72
72
  attr = prefix.empty? ? "xmlns" : "xmlns:#{prefix}"
73
73
  ns_hash[attr] = uri.to_s
74
74
  end
75
- ns_strs = []
76
- ns_hash.each_pair {|a, u| ns_strs << "#{a}=\"#{u}\""}
77
75
 
78
76
  case @library
79
- when :nokogiri then parse_value_nokogiri(value, ns_strs, options[:language])
80
- when :libxml then parse_value_libxml(value, ns_strs, options[:language])
81
- when :rexml then parse_value_rexml(value, ns_strs, options[:language])
77
+ when :nokogiri then parse_value_nokogiri(value, ns_hash, options)
78
+ when :libxml then parse_value_libxml(value, ns_hash, options)
79
+ when :rexml then parse_value_rexml(value, ns_hash, options)
82
80
  else value.to_s
83
81
  end
84
82
  end
@@ -99,10 +97,12 @@ module RDF; class Literal
99
97
  # to the required element, and does not properly order either namespaces or attributes.
100
98
  #
101
99
  # An open-issue in Nokogiri is to add support for C14N from the underlying libxml2 libraries.
102
- def parse_value_nokogiri(value, ns_strs, language)
100
+ def parse_value_nokogiri(value, ns_hash, options)
103
101
  elements = if value.is_a?(Nokogiri::XML::NodeSet)
104
102
  value
105
103
  else
104
+ ns_strs = []
105
+ ns_hash.each_pair {|a, u| ns_strs << "#{a}=\"#{u}\""}
106
106
  # Add inherited namespaces to created root element so that they're inherited to sub-elements
107
107
  Nokogiri::XML::Document.parse("<foo #{ns_strs.join(" ")}>#{value.to_s}</foo>").root.children
108
108
  end
@@ -110,17 +110,15 @@ module RDF; class Literal
110
110
  elements.map do |c|
111
111
  if c.is_a?(Nokogiri::XML::Element)
112
112
  c = Nokogiri::XML.parse(c.dup.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::NO_EMPTY_TAGS)).root
113
- # Gather namespaces from self and decendant nodes
114
- c.traverse do |n|
115
- ns = n.namespace
116
- next unless ns
117
- prefix = ns.prefix ? "xmlns:#{ns.prefix}" : "xmlns"
118
- c[prefix] = ns.href.to_s unless c.namespaces[prefix]
119
- end
120
113
 
114
+ # Apply defined namespaces
115
+ ns_hash.each_pair do |prefix, href|
116
+ c[prefix] = href unless c.namespaces[prefix]
117
+ end
118
+
121
119
  # Add language
122
- if language && c["lang"].to_s.empty?
123
- c["xml:lang"] = language.to_s
120
+ if options[:language] && c["lang"].to_s.empty?
121
+ c["xml:lang"] = options[:language].to_s
124
122
  end
125
123
  end
126
124
  c
@@ -0,0 +1,167 @@
1
+ module RDF::RDFa
2
+ ##
3
+ # Profile representation existing of a hash of terms, prefixes, a default vocabulary and a URI.
4
+ #
5
+ # Profiles are used for storing RDFa profile representations. A representation is created
6
+ # by serializing a profile graph (typically also in RDFa, but may be in other representations).
7
+ #
8
+ # The class may be backed by an RDF::Repository, which will be used to retrieve a profile graph
9
+ # or to load into, if no such graph exists
10
+ class Profile
11
+ # Prefix mappings defined in this profile
12
+ # @return [Hash{Symbol => RDF::URI}]
13
+ attr_reader :prefixes
14
+
15
+ # Term mappings defined in this profile
16
+ # @return [Hash{Symbol => RDF::URI}]
17
+ attr_reader :terms
18
+
19
+ # Default URI defined for this vocabulary
20
+ # @return [RDF::URI]
21
+ attr_reader :vocabulary
22
+
23
+ # URI defining this profile
24
+ # @return [RDF::URI]
25
+ attr_reader :uri
26
+
27
+ ##
28
+ # Initialize a new profile from the given URI.
29
+ #
30
+ # Parses the profile and places it in the repository and cache
31
+ #
32
+ # @param [RDF::URI, #to_s] uri URI of profile to be represented
33
+ def initialize(uri)
34
+ @uri = RDF::URI.intern(uri)
35
+ @prefixes = {}
36
+ @terms = {}
37
+ @vocabulary = nil
38
+
39
+ Profile.load(@uri)
40
+
41
+ resource_info = {}
42
+ repository.query(:context => uri).each do |statement|
43
+ res = resource_info[statement.subject] ||= {}
44
+ raise RDF::ProfileError, "#{statement.object.inspect} must be a Literal" unless statement.object.is_a?(RDF::Literal)
45
+ %w(uri term prefix vocabulary).each do |term|
46
+ res[term] ||= statement.object.value if statement.predicate == RDF::RDFA[term]
47
+ end
48
+ end
49
+
50
+ resource_info.values.each do |res|
51
+ # If one of the objects is not a Literal or if there are additional rdfa:uri or rdfa:term
52
+ # predicates sharing the same subject, no mapping is created.
53
+ uri = res["uri"]
54
+ term = res["term"]
55
+ prefix = res["prefix"]
56
+ vocab = res["vocabulary"]
57
+
58
+ @vocabulary = vocab if vocab
59
+
60
+ # For every extracted triple that is the common subject of an rdfa:prefix and an rdfa:uri
61
+ # predicate, create a mapping from the object literal of the rdfa:prefix predicate to the
62
+ # object literal of the rdfa:uri predicate. Add or update this mapping in the local list of
63
+ # URI mappings after transforming the 'prefix' component to lower-case.
64
+ # For every extracted
65
+ prefix(prefix.downcase, uri) if uri && prefix && prefix != "_"
66
+
67
+ # triple that is the common subject of an rdfa:term and an rdfa:uri predicate, create a
68
+ # mapping from the object literal of the rdfa:term predicate to the object literal of the
69
+ # rdfa:uri predicate. Add or update this mapping in the local term mappings.
70
+ term(term, uri) if term && uri
71
+ end
72
+ end
73
+
74
+ ##
75
+ # @return [RDF::Util::Cache]
76
+ # @private
77
+ def self.cache
78
+ require 'rdf/util/cache' unless defined?(::RDF::Util::Cache)
79
+ @cache ||= RDF::Util::Cache.new(-1)
80
+ end
81
+
82
+ ##
83
+ # Repository used for saving profiles
84
+ # @return [RDF::Repository]
85
+ # @raise [RDF::RDFa::ProfileError] if profile does not support contexts
86
+ def self.repository
87
+ @repository ||= RDF::Repository.new(:title => "RDFa Profiles")
88
+ end
89
+
90
+ ##
91
+ # Set repository used for saving profiles
92
+ # @param [RDF::Repository] repo
93
+ # @return [RDF::Repository]
94
+ def self.repository=(repo)
95
+ raise ProfileError, "Profile Repository must support context" unless repo.supports?(:context)
96
+ @repository = repo
97
+ end
98
+
99
+ # Return a profile faulting through the cache
100
+ # @return [RDF::RDFa::Profile]
101
+ def self.find(uri)
102
+ uri = RDF::URI.intern(uri)
103
+
104
+ cache[uri] ||= new(uri)
105
+ end
106
+
107
+ # Load profile into repository
108
+ def self.load(uri)
109
+ uri = RDF::URI.intern(uri)
110
+ repository.load(uri.to_s, :base_uri => uri, :context => uri) unless repository.has_context?(uri)
111
+ end
112
+
113
+ # @return [RDF::Repository]
114
+ def repository
115
+ Profile.repository
116
+ end
117
+
118
+ ##
119
+ # Defines the given named URI prefix for this profile.
120
+ #
121
+ # @example Defining a URI prefix
122
+ # profile.prefix :dc, RDF::URI('http://purl.org/dc/terms/')
123
+ #
124
+ # @example Returning a URI prefix
125
+ # profile.prefix(:dc) #=> RDF::URI('http://purl.org/dc/terms/')
126
+ #
127
+ # @overload prefix(name, uri)
128
+ # @param [Symbol, #to_s] name
129
+ # @param [RDF::URI, #to_s] uri
130
+ #
131
+ # @overload prefix(name)
132
+ # @param [Symbol, #to_s] name
133
+ #
134
+ # @return [RDF::URI]
135
+ def prefix(name, uri = nil)
136
+ name = name.to_s.empty? ? nil : (name.respond_to?(:to_sym) ? name.to_sym : name.to_s.to_sym)
137
+ uri.nil? ? prefixes[name] : prefixes[name] = uri
138
+ end
139
+
140
+ ##
141
+ # Defines the given named URI term for this profile.
142
+ #
143
+ # @example Defining a URI term
144
+ # profile.term :title, RDF::URI('http://purl.org/dc/terms/title')
145
+ #
146
+ # @example Returning a URI profile
147
+ # profile.term(:title) #=> RDF::URI('http://purl.org/dc/terms/TITLE')
148
+ #
149
+ # @overload term(name, uri)
150
+ # @param [Symbol, #to_s] name
151
+ # @param [RDF::URI, #to_s] uri
152
+ #
153
+ # @overload term(name)
154
+ # @param [Symbol, #to_s] name
155
+ #
156
+ # @return [RDF::URI]
157
+ def term(name, uri = nil)
158
+ name = name.to_s.empty? ? nil : (name.respond_to?(:to_sym) ? name.to_sym : name.to_s.to_sym)
159
+ uri.nil? ? terms[name] : terms[name] = uri
160
+ end
161
+ end
162
+
163
+ ##
164
+ # The base class for RDF profile errors.
165
+ class ProfileError < IOError
166
+ end # ProfileError
167
+ end
@@ -6,7 +6,7 @@ module RDF::RDFa
6
6
  #
7
7
  # Based on processing rules described here:
8
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
9
+ # @see http://www.w3.org/2010/02/rdfa/drafts/2010/WD-rdfa-core-20101026/ RDFa 1.1
10
10
  #
11
11
  # @author [Gregg Kellogg](http://kellogg-assoc.com/)
12
12
  class Reader < RDF::Reader
@@ -39,9 +39,13 @@ module RDF::RDFa
39
39
  Regexp::EXTENDED)
40
40
 
41
41
  # Host language
42
- # @return [:xhtml]
42
+ # @return [:xhtml, :svg]
43
43
  attr_reader :host_language
44
44
 
45
+ # Version
46
+ # @return [:rdfa_1_0, :rdfa_1_1]
47
+ attr_reader :version
48
+
45
49
  # The Recursive Baggage
46
50
  # @private
47
51
  class EvaluationContext # :nodoc:
@@ -76,6 +80,11 @@ module RDF::RDFa
76
80
  #
77
81
  # @return [Hash{Symbol => String}]
78
82
  attr :uri_mappings, true
83
+ # A list of current, in-scope Namespaces. This is the subset of uri_mappings
84
+ # which are defined using xmlns.
85
+ #
86
+ # @return [Hash{String => Namespace}]
87
+ attr :namespaces, true
79
88
  # A list of incomplete triples.
80
89
  #
81
90
  # A triple can be incomplete when no object resource
@@ -115,6 +124,7 @@ module RDF::RDFa
115
124
  @base = base
116
125
  @parent_subject = @base
117
126
  @parent_object = nil
127
+ @namespaces = {}
118
128
  @incomplete_triples = []
119
129
  @language = nil
120
130
  @uri_mappings = host_defaults.fetch(:uri_mappings, {})
@@ -129,6 +139,7 @@ module RDF::RDFa
129
139
  # clone the evaluation context correctly
130
140
  @uri_mappings = from.uri_mappings.clone
131
141
  @incomplete_triples = from.incomplete_triples.clone
142
+ @namespaces = from.namespaces.clone
132
143
  end
133
144
 
134
145
  def inspect
@@ -143,26 +154,44 @@ module RDF::RDFa
143
154
  ##
144
155
  # Initializes the RDFa reader instance.
145
156
  #
146
- # @param [Nokogiri::HTML::Document, Nokogiri::XML::Document, #read, #to_s] input
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.
149
- # @option options [Boolean] :strict (false) Raise Error if true, continue with lax parsing, otherwise
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
157
+ # @param [Nokogiri::HTML::Document, Nokogiri::XML::Document, IO, File, String] input
158
+ # the input stream to read
159
+ # @param [Hash{Symbol => Object}] options
160
+ # any additional options
161
+ # @option options [Encoding] :encoding (Encoding::UTF_8)
162
+ # the encoding of the input stream (Ruby 1.9+)
163
+ # @option options [Boolean] :validate (false)
164
+ # whether to validate the parsed statements and values
165
+ # @option options [Boolean] :canonicalize (false)
166
+ # whether to canonicalize parsed literals
167
+ # @option options [Boolean] :intern (true)
168
+ # whether to intern all parsed URIs
169
+ # @option options [Hash] :prefixes (Hash.new)
170
+ # the prefix mappings to use (not supported by all readers)
171
+ # @option options [#to_s] :base_uri (nil)
172
+ # the base URI to use when resolving relative URIs
173
+ # @option options [:xhtml] :host_language (:xhtml)
174
+ # Host Language
175
+ # @option options [:rdfa_1_0, :rdfa_1_1] :version (:rdfa_1_1)
176
+ # Parser version information
177
+ # @option options [Graph] :processor_graph (nil)
178
+ # Graph to record information, warnings and errors.
179
+ # @option options [Repository] :profile_repository (nil)
180
+ # Repository to save profile graphs.
181
+ # @option options [Array] :debug
182
+ # Array to place debug messages
153
183
  # @return [reader]
154
- # @yield [reader]
155
- # @yieldparam [RDF::Reader] reader
156
- # @raise [RDF::ReaderError]:: Raises RDF::ReaderError if _strict_
184
+ # @yield [reader] `self`
185
+ # @yieldparam [RDF::Reader] reader
186
+ # @yieldreturn [void] ignored
187
+ # @raise [Error]:: Raises RDF::ReaderError if _validate_
157
188
  def initialize(input = $stdin, options = {}, &block)
158
189
  super do
159
190
  @debug = options[:debug]
160
- @strict = options[:strict]
161
- @base_uri = RDF::URI.intern(options[:base_uri])
162
- @@vocabulary_cache ||= {}
191
+ @base_uri = uri(options[:base_uri])
163
192
 
164
193
  @version = options[:version] ? options[:version].to_sym : :rdfa_1_1
165
- @host_language = options[:host_language] || :xhtml
194
+ @processor_graph = options[:processor_graph]
166
195
 
167
196
  @doc = case input
168
197
  when Nokogiri::HTML::Document then input
@@ -170,13 +199,32 @@ module RDF::RDFa
170
199
  else Nokogiri::XML.parse(input, @base_uri.to_s)
171
200
  end
172
201
 
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?
202
+ @host_language = options[:host_language] || case @doc.root.name.downcase.to_sym
203
+ when :html then :xhtml
204
+ when :svg then :svg
205
+ else :xhtml
206
+ end
207
+
208
+ add_error(nil, "Empty document", RDF::RDFA.DocumentError) if (@doc.nil? || @doc.root.nil?)
209
+ add_warning(nil, "Synax errors:\n#{@doc.errors}", RDF::RDFA.DocumentError) if !@doc.errors.empty? && validate?
210
+ add_error("Empty document") if (@doc.nil? || @doc.root.nil?) && validate?
175
211
 
176
212
  block.call(self) if block_given?
177
213
  end
214
+ self.profile_repository = options[:profile_repository] if options[:profile_repository]
178
215
  end
179
216
 
217
+ # @return [RDF::Repository]
218
+ def profile_repository
219
+ Profile.repository
220
+ end
221
+
222
+ # @param [RDF::Repository] repo
223
+ # @return [RDF::Repository]
224
+ def profile_repository=(repo)
225
+ Profile.repository = repo
226
+ end
227
+
180
228
  ##
181
229
  # Iterates the given block for each RDF statement in the input.
182
230
  #
@@ -194,20 +242,25 @@ module RDF::RDFa
194
242
  @host_defaults = case @host_language
195
243
  when :xhtml
196
244
  {
197
- :vocabulary => RDF::XHV.to_s,
245
+ :vocabulary => nil,
198
246
  :prefix => "xhv",
199
247
  :uri_mappings => {"xhv" => RDF::XHV.to_s}, # RDF::XHTML is wrong
200
248
  :term_mappings => %w(
201
249
  alternate appendix bookmark cite chapter contents copyright first glossary help icon index
202
250
  last license meta next p3pv1 prev role section stylesheet subsection start top up
203
- ).inject({}) { |hash, term| hash[term] = RDF::XHV[term]; hash },
251
+ ).inject({}) { |hash, term| hash[term.to_sym] = RDF::XHV[term].to_s; hash },
204
252
  }
205
253
  else
206
- {}
254
+ {
255
+ :uri_mappings => {},
256
+ }
207
257
  end
208
258
 
209
- @host_defaults.delete(:vocabulary) if @version == :rdfa_1_0
210
-
259
+ # Add prefix definitions from host defaults
260
+ @host_defaults[:uri_mappings].each_pair do |prefix, value|
261
+ prefix(prefix, value)
262
+ end
263
+
211
264
  add_debug(@doc, "version = #{@version}, host_language = #{@host_language}")
212
265
 
213
266
  # parse
@@ -249,35 +302,39 @@ module RDF::RDFa
249
302
  # @param [XML Node, any] node:: XML Node or string for showing context
250
303
  # @param [String] message::
251
304
  def add_debug(node, message)
252
- add_processor_message(node, message, RDF::RDFA.InformationalMessage)
305
+ add_processor_message(node, message, RDF::RDFA.Info)
253
306
  end
254
307
 
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
308
+ def add_info(node, message, process_class = RDF::RDFA.Info)
309
+ add_processor_message(node, message, process_class)
310
+ end
311
+
312
+ def add_warning(node, message, process_class = RDF::RDFA.Warning)
313
+ add_processor_message(node, message, process_class)
314
+ end
315
+
316
+ def add_error(node, message, process_class = RDF::RDFA.Error)
317
+ add_processor_message(node, message, process_class)
318
+ raise RDF::ReaderError, message if validate?
319
+ end
320
+
321
+ def add_processor_message(node, message, process_class)
322
+ puts "#{node_path(node)}: #{message}" if ::RDF::RDFa::debug?
323
+ @debug << "#{node_path(node)}: #{message}" if @debug.is_a?(Array)
324
+ if @processor_graph
325
+ @processor_sequence ||= 0
326
+ n = RDF::Node.new
327
+ @processor_graph << RDF::Statement.new(n, RDF["type"], process_class)
328
+ @processor_graph << RDF::Statement.new(n, RDF::DC.description, message)
329
+ @processor_graph << RDF::Statement.new(n, RDF::DC.date, RDF::Literal::Date.new(DateTime.now))
330
+ @processor_graph << RDF::Statement.new(n, RDF::RDFA.sequence, RDF::Literal::Integer.new(@processor_sequence += 1))
331
+ @processor_graph << RDF::Statement.new(n, RDF::RDFA.context, @base_uri)
332
+ nc = RDF::Node.new
333
+ @processor_graph << RDF::Statement.new(nc, RDF["type"], RDF::PTR.XPathPointer)
334
+ @processor_graph << RDF::Statement.new(nc, RDF::PTR.expression, node.path)
335
+ @processor_graph << RDF::Statement.new(n, RDF::RDFA.context, nc)
336
+ end
337
+ end
281
338
 
282
339
  # add a statement, object can be literal or URI or bnode
283
340
  #
@@ -286,10 +343,10 @@ module RDF::RDFa
286
343
  # @param [URI] predicate:: the predicate of the statement
287
344
  # @param [URI, BNode, Literal] object:: the object of the statement
288
345
  # @return [Statement]:: Added statement
289
- # @raise [ReaderError]:: Checks parameter types and raises if they are incorrect if parsing mode is _strict_.
346
+ # @raise [ReaderError]:: Checks parameter types and raises if they are incorrect if parsing mode is _validate_.
290
347
  def add_triple(node, subject, predicate, object)
291
348
  statement = RDF::Statement.new(subject, predicate, object)
292
- add_debug(node, "statement: #{statement.to_ntriples}")
349
+ add_debug(node, "statement: #{RDF::NTriples.serialize(statement)}")
293
350
  @callback.call(statement)
294
351
  end
295
352
 
@@ -297,93 +354,55 @@ module RDF::RDFa
297
354
  # Parsing an RDFa document (this is *not* the recursive method)
298
355
  def parse_whole_document(doc, base)
299
356
  # find if the document has a base element
300
- # XXX - HTML specific
301
- base_el = doc.css('html>head>base').first
302
- if (base_el)
303
- base = base_el.attributes['href']
357
+ case @host_language
358
+ when :xhtml
359
+ base_el = doc.at_css("html>head>base")
360
+ base = base_el.attribute("href").to_s.split("#").first if base_el
361
+ end
362
+
363
+ if (base)
304
364
  # Strip any fragment from base
305
365
  base = base.to_s.split("#").first
306
- @base_uri = RDF::URI.intern(base)
307
- add_debug(base_el, "parse_whole_doc: base='#{base}'")
366
+ base = uri(base)
367
+ add_debug("", "parse_whole_doc: base='#{base}'")
308
368
  end
309
369
 
310
370
  # initialize the evaluation context with the appropriate base
311
- evaluation_context = EvaluationContext.new(@base_uri, @host_defaults)
312
-
371
+ evaluation_context = EvaluationContext.new(base, @host_defaults)
372
+
313
373
  traverse(doc.root, evaluation_context)
314
374
  end
315
375
 
316
376
  # Parse and process URI mappings, Term mappings and a default vocabulary from @profile
317
377
  #
318
378
  # Yields each mapping
319
- def process_profile(element)
320
- element.attributes['profile'].to_s.split(/\s/).reverse.each do |profile|
379
+ def process_profile(element, profiles)
380
+ profiles.
381
+ reverse.
382
+ map {|uri| uri(uri).normalize}.
383
+ each do |uri|
321
384
  # Don't try to open ourselves!
322
- if @uri == profile
323
- add_debug(element, "process_profile: skip recursive profile <#{profile}>")
324
- elsif @@vocabulary_cache.has_key?(profile)
325
- add_debug(element, "process_profile: skip previously parsed profile <#{profile}>")
326
- else
327
- begin
328
- @@vocabulary_cache[profile] = {
329
- :uri_mappings => {},
330
- :term_mappings => {},
331
- :default_vocabulary => nil
332
- }
333
- um = @@vocabulary_cache[profile][:uri_mappings]
334
- tm = @@vocabulary_cache[profile][:term_mappings]
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.
348
- uri = p_graph.first_object([subject, RDF::RDFA['uri'], nil])
349
- term = p_graph.first_object([subject, RDF::RDFA['term'], nil])
350
- prefix = p_graph.first_object([subject, RDF::RDFA['prefix'], nil])
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}")
353
-
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
-
361
- # For every extracted triple that is the common subject of an rdfa:prefix and an rdfa:uri
362
- # predicate, create a mapping from the object literal of the rdfa:prefix predicate to the
363
- # object literal of the rdfa:uri predicate. Add or update this mapping in the local list of
364
- # URI mappings after transforming the 'prefix' component to lower-case.
365
- # For every extracted
366
- um[prefix.value.downcase] = uri.value if prefix && prefix.value != "_"
367
-
368
- # triple that is the common subject of an rdfa:term and an rdfa:uri predicate, create a
369
- # mapping from the object literal of the rdfa:term predicate to the object literal of the
370
- # rdfa:uri predicate. Add or update this mapping in the local term mappings.
371
- tm[term.value.downcase] = RDF::URI.intern(uri.value) if term
372
- end
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
376
- end
385
+ if @base_uri == uri
386
+ add_debug(element, "process_profile: skip recursive profile <#{uri}>")
387
+ next
388
+ end
389
+
390
+ next unless profile = Profile.find(uri)
391
+ # Add URI Mappings to prefixes
392
+ profile.prefixes.each_pair do |prefix, value|
393
+ prefix(prefix, value)
377
394
  end
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]
395
+ yield :uri_mappings, profile.prefixes unless profile.prefixes.empty?
396
+ yield :term_mappings, profile.terms unless profile.terms.empty?
397
+ yield :default_vocabulary, profile.vocabulary if profile.vocabulary
382
398
  end
399
+ rescue Exception => e
400
+ add_error(element, e.message, RDF::RDFA.ProfileReferenceError)
401
+ raise # In case we're not in strict mode, we need to be sure processing stops
383
402
  end
384
403
 
385
404
  # Extract the XMLNS mappings from an element
386
- def extract_mappings(element, uri_mappings, term_mappings)
405
+ def extract_mappings(element, uri_mappings, namespaces)
387
406
  # look for xmlns
388
407
  # (note, this may be dependent on @host_language)
389
408
  # Regardless of how the mapping is declared, the value to be mapped must be converted to lower case,
@@ -396,8 +415,12 @@ module RDF::RDFa
396
415
  # Downcase prefix for RDFa 1.1
397
416
  pfx_lc = (@version == :rdfa_1_0 || ns.prefix.nil?) ? ns.prefix : ns.prefix.to_s.downcase
398
417
  if ns.prefix
399
- uri_mappings[pfx_lc] = ns.href
418
+ uri_mappings[pfx_lc.to_sym] = ns.href
419
+ namespaces[pfx_lc] ||= ns.href
420
+ prefix(pfx_lc, ns.href)
400
421
  add_debug(element, "extract_mappings: xmlns:#{ns.prefix} => <#{ns.href}>")
422
+ else
423
+ namespaces[""] ||= ns.href
401
424
  end
402
425
  end
403
426
 
@@ -414,7 +437,8 @@ module RDF::RDFa
414
437
  # A Conforming RDFa Processor must ignore any definition of a mapping for the '_' prefix.
415
438
  next if prefix == "_"
416
439
 
417
- uri_mappings[prefix] = uri
440
+ uri_mappings[prefix.to_s.empty? ? nil : prefix.to_s.to_sym] = uri
441
+ prefix(prefix, uri)
418
442
  add_debug(element, "extract_mappings: prefix #{prefix} => <#{uri}>")
419
443
  end unless @version == :rdfa_1_0
420
444
  end
@@ -423,7 +447,7 @@ module RDF::RDFa
423
447
  def traverse(element, evaluation_context)
424
448
  if element.nil?
425
449
  add_debug(element, "traverse nil element")
426
- raise RDF::ReaderError, "Can't parse nil element" if @strict
450
+ raise RDF::ReaderError, "Can't parse nil element" if validate?
427
451
  return nil
428
452
  end
429
453
 
@@ -435,6 +459,7 @@ module RDF::RDFa
435
459
  new_subject = nil
436
460
  current_object_resource = nil
437
461
  uri_mappings = evaluation_context.uri_mappings.clone
462
+ namespaces = evaluation_context.namespaces.clone
438
463
  incomplete_triples = []
439
464
  language = evaluation_context.language
440
465
  term_mappings = evaluation_context.term_mappings.clone
@@ -450,6 +475,9 @@ module RDF::RDFa
450
475
  resource = attrs['resource']
451
476
  href = attrs['href']
452
477
  vocab = attrs['vocab']
478
+ xml_base = element.attribute_with_ns("base", RDF::XML.to_s)
479
+ base = xml_base.to_s if xml_base && @host_language != :xhtml
480
+ base ||= evaluation_context.base
453
481
 
454
482
  # Pull out the attributes needed for the skip test.
455
483
  property = attrs['property'].to_s.strip if attrs['property']
@@ -458,13 +486,31 @@ module RDF::RDFa
458
486
  content = attrs['content'].to_s if attrs['content']
459
487
  rel = attrs['rel'].to_s.strip if attrs['rel']
460
488
  rev = attrs['rev'].to_s.strip if attrs['rev']
489
+ profiles = attrs['profile'].to_s.split(/\s/) # In-scope profiles in order for passing to XMLLiteral
490
+
491
+ attrs = {
492
+ :about => about,
493
+ :src => src,
494
+ :resource => resource,
495
+ :href => href,
496
+ :vocab => vocab,
497
+ :base => xml_base,
498
+ :property => property,
499
+ :typeof => typeof,
500
+ :daetatype => datatype,
501
+ :rel => rel,
502
+ :rev => rev,
503
+ :profiles => (profiles.empty? ? nil : profiles),
504
+ }.select{|k,v| v}
505
+
506
+ add_debug(element, "traverse " + attrs.map{|a| "#{a.first}: #{a.last}"}.join(", ")) unless attrs.empty?
461
507
 
462
508
  # Local term mappings [7.5 Steps 2]
463
509
  # Next the current element is parsed for any updates to the local term mappings and local list of URI mappings via @profile.
464
510
  # If @profile is present, its value is processed as defined in RDFa Profiles.
465
511
  unless @version == :rdfa_1_0
466
512
  begin
467
- process_profile(element) do |which, value|
513
+ process_profile(element, profiles) do |which, value|
468
514
  add_debug(element, "[Step 2] traverse, #{which}: #{value.inspect}")
469
515
  case which
470
516
  when :uri_mappings then uri_mappings.merge!(value)
@@ -476,7 +522,7 @@ module RDF::RDFa
476
522
  # Skip this element and all sub-elements
477
523
  # If any referenced RDFa Profile is not available, then the current element and its children must not place any
478
524
  # triples in the default graph .
479
- raise if @strict
525
+ raise if validate?
480
526
  return
481
527
  end
482
528
  end
@@ -491,7 +537,7 @@ module RDF::RDFa
491
537
  add_debug(element, "[Step 2] traverse, reset default_vocaulary to #{@host_defaults.fetch(:vocabulary, nil).inspect}")
492
538
  @host_defaults.fetch(:vocabulary, nil)
493
539
  else
494
- RDF::URI.intern(vocab)
540
+ uri(vocab)
495
541
  end
496
542
  add_debug(element, "[Step 2] traverse, default_vocaulary: #{default_vocabulary.inspect}")
497
543
  end
@@ -499,7 +545,7 @@ module RDF::RDFa
499
545
  # Local term mappings [7.5 Steps 4]
500
546
  # Next, the current element is then examined for URI mapping s and these are added to the local list of URI mappings.
501
547
  # Note that a URI mapping will simply overwrite any current mapping in the list that has the same name
502
- extract_mappings(element, uri_mappings, term_mappings)
548
+ extract_mappings(element, uri_mappings, namespaces)
503
549
 
504
550
  # Language information [7.5 Step 5]
505
551
  # From HTML5 [3.2.3.3]
@@ -516,39 +562,37 @@ module RDF::RDFa
516
562
  language
517
563
  end
518
564
  language = nil if language.to_s.empty?
519
- add_debug(element, "HTML5 [3.2.3.3] traverse, lang: #{language || 'nil'}") if attrs['lang']
565
+ add_debug(element, "HTML5 [3.2.3.3] traverse, lang: #{language || 'nil'}") if language
520
566
 
521
567
  # rels and revs
522
- rels = process_uris(element, rel, evaluation_context,
568
+ rels = process_uris(element, rel, evaluation_context, base,
523
569
  :uri_mappings => uri_mappings,
524
570
  :term_mappings => term_mappings,
525
571
  :vocab => default_vocabulary,
526
572
  :restrictions => TERMorCURIEorAbsURI[@version])
527
- revs = process_uris(element, rev, evaluation_context,
573
+ revs = process_uris(element, rev, evaluation_context, base,
528
574
  :uri_mappings => uri_mappings,
529
575
  :term_mappings => term_mappings,
530
576
  :vocab => default_vocabulary,
531
577
  :restrictions => TERMorCURIEorAbsURI[@version])
532
578
 
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}")
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}")
535
- add_debug(element, "traverse, rels: #{rels.join(" ")}, revs: #{revs.join(" ")}")
579
+ add_debug(element, "traverse, rels: #{rels.join(" ")}, revs: #{revs.join(" ")}") unless (rels + revs).empty?
536
580
 
537
581
  if !(rel || rev)
538
582
  # Establishing a new subject if no rel/rev [7.5 Step 6]
539
583
  # May not be valid, but can exist
540
584
  new_subject = if about
541
- process_uri(element, about, evaluation_context,
585
+ process_uri(element, about, evaluation_context, base,
542
586
  :uri_mappings => uri_mappings,
543
587
  :restrictions => SafeCURIEorCURIEorURI[@version])
544
588
  elsif src
545
- process_uri(element, src, evaluation_context, :restrictions => [:uri])
589
+ process_uri(element, src, evaluation_context, base, :restrictions => [:uri])
546
590
  elsif resource
547
- process_uri(element, resource, evaluation_context,
591
+ process_uri(element, resource, evaluation_context, base,
548
592
  :uri_mappings => uri_mappings,
549
593
  :restrictions => SafeCURIEorCURIEorURI[@version])
550
594
  elsif href
551
- process_uri(element, href, evaluation_context, :restrictions => [:uri])
595
+ process_uri(element, href, evaluation_context, base, :restrictions => [:uri])
552
596
  end
553
597
 
554
598
  # If no URI is provided by a resource attribute, then the first match from the following rules
@@ -557,11 +601,14 @@ module RDF::RDFa
557
601
  # otherwise,
558
602
  # if parent object is present, new subject is set to the value of parent object.
559
603
  # Additionally, if @property is not present then the skip element flag is set to 'true';
560
- new_subject ||= if @host_language == :xhtml && element.name =~ /^(head|body)$/ && evaluation_context.base
604
+ new_subject ||= if @host_language == :xhtml && element.name =~ /^(head|body)$/ && base
561
605
  # From XHTML+RDFa 1.1:
562
606
  # if no URI is provided, then first check to see if the element is the head or body element.
563
607
  # 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
608
+ uri(base)
609
+ elsif @host_language != :xhtml && base
610
+ # XXX Spec confusion, assume that this is true
611
+ uri(base)
565
612
  elsif element.attributes['typeof']
566
613
  RDF::Node.new
567
614
  else
@@ -574,10 +621,10 @@ module RDF::RDFa
574
621
  # [7.5 Step 7]
575
622
  # If the current element does contain a @rel or @rev attribute, then the next step is to
576
623
  # establish both a value for new subject and a value for current object resource:
577
- new_subject = process_uri(element, about, evaluation_context,
624
+ new_subject = process_uri(element, about, evaluation_context, base,
578
625
  :uri_mappings => uri_mappings,
579
626
  :restrictions => SafeCURIEorCURIEorURI[@version]) ||
580
- process_uri(element, src, evaluation_context,
627
+ process_uri(element, src, evaluation_context, base,
581
628
  :uri_mappings => uri_mappings,
582
629
  :restrictions => [:uri])
583
630
 
@@ -586,7 +633,7 @@ module RDF::RDFa
586
633
  # From XHTML+RDFa 1.1:
587
634
  # if no URI is provided, then first check to see if the element is the head or body element.
588
635
  # 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
636
+ uri(base)
590
637
  elsif element.attributes['typeof']
591
638
  RDF::Node.new
592
639
  else
@@ -597,11 +644,11 @@ module RDF::RDFa
597
644
 
598
645
  # Then the current object resource is set to the URI obtained from the first match from the following rules:
599
646
  current_object_resource = if resource
600
- process_uri(element, resource, evaluation_context,
647
+ process_uri(element, resource, evaluation_context, base,
601
648
  :uri_mappings => uri_mappings,
602
649
  :restrictions => SafeCURIEorCURIEorURI[@version])
603
650
  elsif href
604
- process_uri(element, href, evaluation_context,
651
+ process_uri(element, href, evaluation_context, base,
605
652
  :restrictions => [:uri])
606
653
  end
607
654
 
@@ -611,7 +658,7 @@ module RDF::RDFa
611
658
  # Process @typeof if there is a subject [Step 8]
612
659
  if new_subject and typeof
613
660
  # Typeof is TERMorCURIEorAbsURIs
614
- types = process_uris(element, typeof, evaluation_context,
661
+ types = process_uris(element, typeof, evaluation_context, base,
615
662
  :uri_mappings => uri_mappings,
616
663
  :term_mappings => term_mappings,
617
664
  :vocab => default_vocabulary,
@@ -647,7 +694,7 @@ module RDF::RDFa
647
694
 
648
695
  # Establish current object literal [Step 11]
649
696
  if property
650
- properties = process_uris(element, property, evaluation_context,
697
+ properties = process_uris(element, property, evaluation_context, base,
651
698
  :uri_mappings => uri_mappings,
652
699
  :term_mappings => term_mappings,
653
700
  :vocab => default_vocabulary,
@@ -658,7 +705,7 @@ module RDF::RDFa
658
705
  false
659
706
  else
660
707
  add_debug(element, "Illegal predicate: #{p.inspect}")
661
- raise RDF::ReaderError, "predicate #{p.inspect} must be a URI" if @strict
708
+ raise RDF::ReaderError, "predicate #{p.inspect} must be a URI" if validate?
662
709
  true
663
710
  end
664
711
  end
@@ -667,45 +714,67 @@ module RDF::RDFa
667
714
  children_node_types = element.children.collect{|c| c.class}.uniq
668
715
 
669
716
  # the following 3 IF clauses should be mutually exclusive. Written as is to prevent extensive indentation.
670
- datatype = process_uri(element, datatype, evaluation_context,
717
+ datatype = process_uri(element, datatype, evaluation_context, base,
671
718
  :uri_mappings => uri_mappings,
672
719
  :term_mappings => term_mappings,
673
720
  :vocab => default_vocabulary,
674
721
  :restrictions => TERMorCURIEorAbsURI[@version]) unless datatype.to_s.empty?
675
- current_object_literal = if !datatype.to_s.empty? && datatype.to_s != RDF.XMLLiteral.to_s
676
- # typed literal
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"))
722
+ begin
723
+ current_object_literal = if !datatype.to_s.empty? && datatype.to_s != RDF.XMLLiteral.to_s
724
+ # typed literal
725
+ add_debug(element, "[Step 11] typed literal (#{datatype})")
726
+ RDF::Literal.new(content || element.inner_text.to_s, :datatype => datatype, :language => language, :validate => validate?, :canonicalize => canonicalize?)
727
+ elsif @version == :rdfa_1_1
728
+ if datatype.to_s == RDF.XMLLiteral.to_s
729
+ # XML Literal
730
+ add_debug(element, "[Step 11(1.1)] XML Literal: #{element.inner_html}")
731
+
732
+ # In order to maintain maximum portability of this literal, any children of the current node that are
733
+ # elements must have the current in scope XML namespace declarations (if any) declared on the
734
+ # serialized element using their respective attributes. Since the child element node could also
735
+ # declare new XML namespaces, the RDFa Processor must be careful to merge these together when
736
+ # generating the serialized element definition. For avoidance of doubt, any re-declarations on the
737
+ # child node must take precedence over declarations that were active on the current node.
738
+ begin
739
+ RDF::Literal.new(element.inner_html,
740
+ :datatype => RDF.XMLLiteral,
741
+ :language => language,
742
+ :namespaces => namespaces,
743
+ :validate => validate?,
744
+ :canonicalize => canonicalize?)
745
+ rescue ArgumentError => e
746
+ add_error(element, e.message)
747
+ end
748
+ else
749
+ # plain literal
750
+ add_debug(element, "[Step 11(1.1)] plain literal")
751
+ RDF::Literal.new(content || element.inner_text.to_s, :language => language, :validate => validate?, :canonicalize => canonicalize?)
752
+ end
685
753
  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"))
754
+ if content || (children_node_types == [Nokogiri::XML::Text]) || (element.children.length == 0) || datatype == ""
755
+ # plain literal
756
+ add_debug(element, "[Step 11 (1.0)] plain literal")
757
+ RDF::Literal.new(content || element.inner_text.to_s, :language => language, :validate => validate?, :canonicalize => canonicalize?)
758
+ elsif children_node_types != [Nokogiri::XML::Text] and (datatype == nil or datatype.to_s == RDF.XMLLiteral.to_s)
759
+ # XML Literal
760
+ add_debug(element, "[Step 11 (1.0)] XML Literal: #{element.inner_html}")
761
+ recurse = false
762
+ RDF::Literal.new(element.inner_html,
763
+ :datatype => RDF.XMLLiteral,
764
+ :language => language,
765
+ :namespaces => namespaces,
766
+ :validate => validate?,
767
+ :canonicalize => canonicalize?)
768
+ end
700
769
  end
770
+ rescue ArgumentError => e
771
+ add_error(element, e.message)
701
772
  end
702
773
 
703
774
  # add each property
704
775
  properties.each do |p|
705
776
  add_triple(element, new_subject, p, current_object_literal)
706
777
  end
707
- # SPEC CONFUSION: "the triple has been created" ==> there may be more than one
708
- # set the recurse flag above in the IF about xmlliteral, as it is the only place that can happen
709
778
  end
710
779
 
711
780
  if not skip and new_subject && !evaluation_context.incomplete_triples.empty?
@@ -727,22 +796,26 @@ module RDF::RDFa
727
796
  uri_mappings == evaluation_context.uri_mappings &&
728
797
  term_mappings == evaluation_context.term_mappings &&
729
798
  default_vocabulary == evaluation_context.default_vocabulary &&
799
+ base == evaluation_context.base
730
800
  new_ec = evaluation_context
731
801
  add_debug(element, "[Step 13] skip: reused ec")
732
802
  else
733
803
  new_ec = evaluation_context.clone
804
+ new_ec.base = base
734
805
  new_ec.language = language
735
806
  new_ec.uri_mappings = uri_mappings
807
+ new_ec.namespaces = namespaces
736
808
  new_ec.term_mappings = term_mappings
737
809
  new_ec.default_vocabulary = default_vocabulary
738
810
  add_debug(element, "[Step 13] skip: cloned ec")
739
811
  end
740
812
  else
741
813
  # create a new evaluation context
742
- new_ec = EvaluationContext.new(evaluation_context.base, @host_defaults)
814
+ new_ec = EvaluationContext.new(base, @host_defaults)
743
815
  new_ec.parent_subject = new_subject || evaluation_context.parent_subject
744
816
  new_ec.parent_object = current_object_resource || new_subject || evaluation_context.parent_subject
745
817
  new_ec.uri_mappings = uri_mappings
818
+ new_ec.namespaces = namespaces
746
819
  new_ec.incomplete_triples = incomplete_triples
747
820
  new_ec.language = language
748
821
  new_ec.term_mappings = term_mappings
@@ -758,13 +831,13 @@ module RDF::RDFa
758
831
  end
759
832
 
760
833
  # space-separated TERMorCURIEorAbsURI or SafeCURIEorCURIEorURI
761
- def process_uris(element, value, evaluation_context, options)
834
+ def process_uris(element, value, evaluation_context, base, options)
762
835
  return [] if value.to_s.empty?
763
836
  add_debug(element, "process_uris: #{value}")
764
- value.to_s.split(/\s+/).map {|v| process_uri(element, v, evaluation_context, options)}.compact
837
+ value.to_s.split(/\s+/).map {|v| process_uri(element, v, evaluation_context, base, options)}.compact
765
838
  end
766
839
 
767
- def process_uri(element, value, evaluation_context, options = {})
840
+ def process_uri(element, value, evaluation_context, base, options = {})
768
841
  return if value.nil?
769
842
  restrictions = options[:restrictions]
770
843
  add_debug(element, "process_uri: #{value}, restrictions = #{restrictions.inspect}")
@@ -797,20 +870,20 @@ module RDF::RDFa
797
870
  begin
798
871
  # AbsURI does not use xml:base
799
872
  if restrictions.include?(:absuri)
800
- uri = RDF::URI.intern(value)
873
+ uri = uri(value)
801
874
  unless uri.absolute?
802
875
  uri = nil
803
876
  raise RDF::ReaderError, "Relative URI #{value}"
804
877
  end
805
878
  else
806
- uri = evaluation_context.base.join(Addressable::URI.parse(value))
879
+ uri = uri(base, Addressable::URI.parse(value))
807
880
  end
808
881
  rescue Addressable::URI::InvalidURIError => e
809
- add_warning(element, "Malformed prefix #{value}", RDF::RDFA.UndefinedPrefixError)
882
+ add_warning(element, "Malformed prefix #{value}", RDF::RDFA.UnresolvedCURIE)
810
883
  rescue RDF::ReaderError => e
811
884
  add_debug(element, e.message)
812
885
  if value.to_s =~ /^\(^\w\):/
813
- add_warning(element, "Undefined prefix #{$1}", RDF::RDFA.UndefinedPrefixError)
886
+ add_warning(element, "Undefined prefix #{$1}", RDF::RDFA.UnresolvedCURIE)
814
887
  else
815
888
  add_warning(element, "Relative URI #{value}")
816
889
  end
@@ -828,17 +901,22 @@ module RDF::RDFa
828
901
  # <em>options[:term_mappings]</em>:: Term mappings
829
902
  # <em>options[:vocab]</em>:: Default vocabulary
830
903
  def process_term(element, value, options)
831
- case
832
- when options[:term_mappings].is_a?(Hash) && options[:term_mappings].has_key?(value.to_s.downcase)
833
- # If the term is in the local term mappings, use the associated URI.
834
- # XXX Spec Confusion: are terms always downcased? Or only for XHTML Vocab?
835
- options[:term_mappings][value.to_s.downcase]
836
- when options[:vocab]
904
+ if options[:term_mappings].is_a?(Hash)
905
+ # If the term is in the local term mappings, use the associated URI (case sensitive).
906
+ return uri(options[:term_mappings][value.to_s.to_sym]) if options[:term_mappings].has_key?(value.to_s.to_sym)
907
+
908
+ # Otherwise, check for case-insensitive match
909
+ options[:term_mappings].each_pair do |term, uri|
910
+ return uri(uri) if term.to_s.downcase == value.to_s.downcase
911
+ end
912
+ end
913
+
914
+ if options[:vocab]
837
915
  # Otherwise, if there is a local default vocabulary the URI is obtained by concatenating that value and the term.
838
- RDF::URI.intern(options[:vocab] + value)
916
+ uri(options[:vocab] + value)
839
917
  else
840
918
  # 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)
919
+ add_warning(element, "Term #{value} is not defined", RDF::RDFA.UnresolvedTerm)
842
920
  nil
843
921
  end
844
922
  end
@@ -856,12 +934,12 @@ module RDF::RDFa
856
934
  elsif curie.to_s.match(/^:/)
857
935
  add_debug(element, "curie_to_resource_or_bnode: default prefix: defined? #{!!uri_mappings[""]}, defaults: #{@host_defaults[:prefix]}")
858
936
  # Default prefix
859
- if uri_mappings[""]
860
- RDF::URI.intern(uri_mappings[""] + reference.to_s)
937
+ if uri_mappings[nil]
938
+ uri(uri_mappings[nil] + reference.to_s)
861
939
  elsif @host_defaults[:prefix]
862
- RDF::URI.intern(uri_mappings[@host_defaults[:prefix]] + reference.to_s)
940
+ uri(uri_mappings[@host_defaults[:prefix]] + reference.to_s)
863
941
  else
864
- #add_warning(element, "Default namespace prefix is not defined", RDF::RDFA.UndefinedPrefixError)
942
+ #add_warning(element, "Default namespace prefix is not defined", RDF::RDFA.UnresolvedCURIE)
865
943
  nil
866
944
  end
867
945
  elsif !curie.to_s.match(/:/)
@@ -870,14 +948,24 @@ module RDF::RDFa
870
948
  else
871
949
  # Prefixes always downcased
872
950
  prefix = prefix.to_s.downcase unless @version == :rdfa_1_0
873
- ns = uri_mappings[prefix.to_s]
951
+ add_debug(element, "curie_to_resource_or_bnode check for #{prefix.to_s.to_sym.inspect} in #{uri_mappings.inspect}")
952
+ ns = uri_mappings[prefix.to_s.to_sym]
874
953
  if ns
875
- RDF::URI.intern(ns + reference.to_s)
954
+ uri(ns + reference.to_s)
876
955
  else
877
- #add_debug(element, "curie_to_resource_or_bnode No namespace mapping for #{prefix}")
956
+ add_debug(element, "curie_to_resource_or_bnode No namespace mapping for #{prefix}")
878
957
  nil
879
958
  end
880
959
  end
881
960
  end
961
+
962
+ def uri(value, append = nil)
963
+ value = RDF::URI.new(value)
964
+ value = value.join(append) if append
965
+ value.validate! if validate?
966
+ value.canonicalize! if canonicalize?
967
+ value = RDF::URI.intern(value) if intern?
968
+ value
969
+ end
882
970
  end
883
971
  end