rdf-rdfa 0.3.7 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +71 -2
- data/VERSION +1 -1
- data/lib/rdf/rdfa.rb +0 -2
- data/lib/rdf/rdfa/reader.rb +346 -322
- data/lib/rdf/rdfa/reader/nokogiri.rb +274 -0
- data/lib/rdf/rdfa/reader/rexml.rb +300 -0
- metadata +77 -32
- data/lib/rdf/rdfa/patches/literal_hacks.rb +0 -156
- data/lib/rdf/rdfa/patches/nokogiri_hacks.rb +0 -22
data/README
CHANGED
@@ -11,7 +11,7 @@ RDF::RDFa parses [RDFa][RDFa 1.1 Core] into statements or triples.
|
|
11
11
|
* Fully compliant RDFa 1.1 parser.
|
12
12
|
* Template-based Writer to generate XHTML+RDFa.
|
13
13
|
* Writer uses user-replacable [Haml][Haml]-based templates to generate RDFa.
|
14
|
-
* Uses Nokogiri for parsing HTML/SVG
|
14
|
+
* If available, Uses Nokogiri for parsing HTML/SVG, falls back to REXML otherwise (and for JRuby)
|
15
15
|
* [RDFa tests][RDFa-test-suite] use SPARQL for most tests due to Rasqal limitations. Other tests compare directly against N-triples.
|
16
16
|
|
17
17
|
Install with 'gem install rdf-rdfa'
|
@@ -20,6 +20,10 @@ Install with 'gem install rdf-rdfa'
|
|
20
20
|
RDFa is an evolving standard, undergoing some substantial recent changes partly due to perceived competition
|
21
21
|
with Microdata. As a result, the RDF Webapps working group is currently looking at changes in the processing model for RDFa. These changes are now being tracked in {RDF::RDFa::Reader}:
|
22
22
|
|
23
|
+
#### RDFa 1.1 Lite
|
24
|
+
This version fully supports the limited syntax of [RDFa Lite 1.1][]. This includes the ability to use
|
25
|
+
@property exclusively.
|
26
|
+
|
23
27
|
#### Remove RDFa Profiles
|
24
28
|
RDFa Profiles were a mechanism added to allow groups of terms and prefixes to be defined in an external resource and loaded to affect the processing of an RDFa document. This introduced a problem for some implementations needing to perform a cross-origin GET in order to retrieve the profiles. The working group elected to drop support for user-defined RDFa Profiles (the default profiles defined by RDFa Core and host languages still apply) and replace it with an inference regime using vocabularies. Parsing of @profile has been removed from this version.
|
25
29
|
|
@@ -81,6 +85,66 @@ defines a playlist with an ordered set of tracks. RDFa adds the @inlist attribut
|
|
81
85
|
|
82
86
|
This basically does the same thing, but places each track in an rdf:List in the defined order.
|
83
87
|
|
88
|
+
#### Property relations
|
89
|
+
The @property attribute has been updated to allow for creating URI references as well as object literals.
|
90
|
+
|
91
|
+
1. If an element contains @property but no @rel, @datatype or @content and it contains a resource attribute (such as @href, @src, or @resource)
|
92
|
+
1. Generate an IRI object. Furthermore, sub-elements do not chain, i.e., the subject in effect when the @property is processed is also in effect for sub-elements.
|
93
|
+
2. Otherwise, generate a literal as before.
|
94
|
+
|
95
|
+
For example:
|
96
|
+
|
97
|
+
<a vocab="http://schema.org" property="url" href="http://example.com">
|
98
|
+
<span property="title">NBA Eastern Conference ...</span>
|
99
|
+
</a>
|
100
|
+
|
101
|
+
results in
|
102
|
+
|
103
|
+
<> schema:url <http://example.com>;
|
104
|
+
schema:title "NBA Eastern Conference".
|
105
|
+
|
106
|
+
#### Magnetic @about/@typeof
|
107
|
+
The @typeof attribute has changed; previously, it always created a new subject, either using a resource from @about, @resource and so forth. This has long been a source of errors for people using RDFa. The new rules cause @typeof to bind to a subject if used with @about, otherwise, to an object, if either used alone, or in combination with some other resource attribute (such as @href, @src or @resource).
|
108
|
+
|
109
|
+
For example:
|
110
|
+
|
111
|
+
<div typeof="foaf:Person" about="http://greggkellogg.net/foaf#me">
|
112
|
+
<p property="name">Gregg Kellogg</span>
|
113
|
+
<a rel="knows" typeof="foaf:Person" href="http://manu.sporny.org/#this">
|
114
|
+
<span property="name">Manu Sporny</span>
|
115
|
+
</a>
|
116
|
+
</div>
|
117
|
+
|
118
|
+
results in
|
119
|
+
|
120
|
+
<http://greggkellogg.net/foaf#me> a foaf:Person;
|
121
|
+
foaf:name "Gregg Kellogg";
|
122
|
+
foaf:knows <http://manu.sporny.org/#this> .
|
123
|
+
<http://manu.sporny.org/#this> a foaf:Person;
|
124
|
+
foaf:name "Manu Sporny" .
|
125
|
+
|
126
|
+
Note that if the explicit @href is not present, i.e.,
|
127
|
+
|
128
|
+
<div typeof="foaf:Person" about="http://greggkellogg.net/foaf#me">
|
129
|
+
<p property="name">Gregg Kellogg</span>
|
130
|
+
<a href="knows" typeof="foaf:Person">
|
131
|
+
<span property="name">Manu Sporny</span>
|
132
|
+
</a>
|
133
|
+
</div>
|
134
|
+
|
135
|
+
this results in
|
136
|
+
|
137
|
+
<http://greggkellogg.net/foaf#me> a foaf:Person;
|
138
|
+
foaf:name "Gregg Kellogg";
|
139
|
+
foaf:knows [
|
140
|
+
a foaf:Person;
|
141
|
+
foaf:name "Manu Sporny"
|
142
|
+
].
|
143
|
+
|
144
|
+
|
145
|
+
#### Property chaining
|
146
|
+
If used without @rel, but with @typeof and a resource attribute, @property will cause chaining to another object just like @rel. The effect of this and other changes is to allow pretty much all RDFa to be marked up using just @property; @rel/@rev is no longer required. Although, @rel and @rev have useful features that @property does not, so it's worth keeping them in your toolkit.
|
147
|
+
|
84
148
|
## Usage
|
85
149
|
|
86
150
|
### Reading RDF data in the RDFa format
|
@@ -297,9 +361,11 @@ The template hash defines four Haml templates:
|
|
297
361
|
}
|
298
362
|
|
299
363
|
## Dependencies
|
364
|
+
* [Ruby](http://ruby-lang.org/) (>= 1.9) or (>= 1.8.1 with [Backports][])
|
300
365
|
* [RDF.rb](http://rubygems.org/gems/rdf) (>= 0.3.1)
|
301
|
-
* [Nokogiri](http://rubygems.org/gems/nokogiri) (>= 1.3.3)
|
302
366
|
* [Haml](https://rubygems.org/gems/haml) (>= 3.0.0)
|
367
|
+
* [HTMLEntities](https://rubygems.org/gems/htmlentities) ('>= 4.3.0')
|
368
|
+
* Soft dependency on [Nokogiri](http://rubygems.org/gems/nokogiri) (>= 1.3.3)
|
303
369
|
|
304
370
|
## Documentation
|
305
371
|
Full documentation available on [Rubydoc.info][RDFa doc]
|
@@ -313,6 +379,8 @@ Full documentation available on [Rubydoc.info][RDFa doc]
|
|
313
379
|
* {RDF::RDFa::SVG}
|
314
380
|
Asserts :svg format, image/svg+xml mime-type and .svg file extension.
|
315
381
|
* {RDF::RDFa::Reader}
|
382
|
+
* {RDF::RDFa::Reader::Nokogiri}
|
383
|
+
* {RDF::RDFa::Reader::REXML}
|
316
384
|
* {RDF::RDFa::Profile}
|
317
385
|
* {RDF::RDFa::Writer}
|
318
386
|
|
@@ -373,6 +441,7 @@ see <http://unlicense.org/> or the accompanying {file:UNLICENSE} file.
|
|
373
441
|
[YARD-GS]: http://rubydoc.info/docs/yard/file/docs/GettingStarted.md
|
374
442
|
[PDD]: http://lists.w3.org/Archives/Public/public-rdf-ruby/2010May/0013.html
|
375
443
|
[RDFa 1.1 Core]: http://www.w3.org/TR/2011/WD-rdfa-core-20110331/ "RDFa 1.1 Core"
|
444
|
+
[RDFa Lite 1.1]: http://www.w3.org/2010/02/rdfa/drafts/2011/ED-rdfa-lite-20111030/ "RDFa Lite 1.1"
|
376
445
|
[XHTML+RDFa 1.1]: http://www.w3.org/TR/2011/WD-xhtml-rdfa-20110331/ "XHTML+RDFa 1.1"
|
377
446
|
[RDFa-test-suite]: http://rdfa.digitalbazaar.com/test-suite/ "RDFa test suite"
|
378
447
|
[RDFa doc]: http://rubydoc.info/github/gkellogg/rdf-rdfa/frames
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.8
|
data/lib/rdf/rdfa.rb
CHANGED
@@ -25,8 +25,6 @@ module RDF
|
|
25
25
|
module RDFa
|
26
26
|
require 'rdf/rdfa/format'
|
27
27
|
require 'rdf/rdfa/vocab'
|
28
|
-
require 'rdf/rdfa/patches/literal_hacks'
|
29
|
-
require 'rdf/rdfa/patches/nokogiri_hacks'
|
30
28
|
require 'rdf/rdfa/patches/string_hacks'
|
31
29
|
autoload :Expansion, 'rdf/rdfa/expansion'
|
32
30
|
autoload :Profile, 'rdf/rdfa/profile'
|
data/lib/rdf/rdfa/reader.rb
CHANGED
@@ -1,10 +1,24 @@
|
|
1
|
-
|
1
|
+
begin
|
2
|
+
raise LoadError, "not with java" if RUBY_PLATFORM == "java"
|
3
|
+
require 'nokogiri'
|
4
|
+
rescue LoadError => e
|
5
|
+
:rexml
|
6
|
+
end
|
2
7
|
require 'rdf/ntriples'
|
8
|
+
require 'rdf/xsd'
|
3
9
|
|
4
10
|
module RDF::RDFa
|
5
11
|
##
|
6
12
|
# An RDFa parser in Ruby
|
7
13
|
#
|
14
|
+
# This class supports [Nokogiri][] for HTML
|
15
|
+
# processing, and will automatically select the most performant
|
16
|
+
# implementation (Nokogiri or LibXML) that is available. If need be, you
|
17
|
+
# can explicitly override the used implementation by passing in a
|
18
|
+
# `:library` option to `Reader.new` or `Reader.open`.
|
19
|
+
#
|
20
|
+
# [Nokogiri]: http://nokogiri.org/
|
21
|
+
#
|
8
22
|
# Based on processing rules described here:
|
9
23
|
# @see http://www.w3.org/TR/rdfa-syntax/#s_model RDFa 1.0
|
10
24
|
# @see http://www.w3.org/TR/2011/WD-rdfa-core-20110331/ RDFa Core 1.1
|
@@ -174,7 +188,7 @@ module RDF::RDFa
|
|
174
188
|
|
175
189
|
def inspect
|
176
190
|
v = ['base', 'parent_subject', 'parent_object', 'language', 'default_vocabulary'].map do |a|
|
177
|
-
"#{a}
|
191
|
+
"#{a}=#{self.send(a).inspect}"
|
178
192
|
end
|
179
193
|
v << "uri_mappings[#{uri_mappings.keys.length}]"
|
180
194
|
v << "incomplete_triples[#{incomplete_triples.length}]"
|
@@ -184,27 +198,22 @@ module RDF::RDFa
|
|
184
198
|
end
|
185
199
|
end
|
186
200
|
|
201
|
+
# Returns the XML implementation module for this reader instance.
|
202
|
+
#
|
203
|
+
# @attr_reader [Module]
|
204
|
+
attr_reader :implementation
|
205
|
+
|
187
206
|
##
|
188
207
|
# Initializes the RDFa reader instance.
|
189
208
|
#
|
190
|
-
# @param [
|
209
|
+
# @param [IO, File, String] input
|
191
210
|
# the input stream to read
|
192
211
|
# @param [Hash{Symbol => Object}] options
|
193
|
-
# any additional options
|
194
|
-
# @option options [
|
195
|
-
#
|
196
|
-
# @option options [Boolean] :validate (false)
|
197
|
-
# whether to validate the parsed statements and values
|
198
|
-
# @option options [Boolean] :canonicalize (false)
|
199
|
-
# whether to canonicalize parsed literals
|
212
|
+
# any additional options (see `RDF::Reader#initialize`)
|
213
|
+
# @option options [Symbol] :library
|
214
|
+
# One of :nokogiri or :rexml. If nil/unspecified uses :nokogiri if available, :rexml otherwise.
|
200
215
|
# @option options [Boolean] :expand (false)
|
201
216
|
# whether to perform RDFS expansion on the resulting graph
|
202
|
-
# @option options [Boolean] :intern (true)
|
203
|
-
# whether to intern all parsed URIs
|
204
|
-
# @option options [Hash] :prefixes (Hash.new)
|
205
|
-
# the prefix mappings to use (not supported by all readers)
|
206
|
-
# @option options [#to_s] :base_uri (nil)
|
207
|
-
# the base URI to use when resolving relative URIs
|
208
217
|
# @option options [:xml1, :xhtml1, :xhtml5, :html4, :html5, :svg] :host_language (:xhtml1)
|
209
218
|
# Host Language
|
210
219
|
# @option options [:"rdfa1.0", :"rdfa1.1"] :version (:"rdfa1.1")
|
@@ -224,33 +233,33 @@ module RDF::RDFa
|
|
224
233
|
super do
|
225
234
|
@debug = options[:debug]
|
226
235
|
|
227
|
-
detect_host_language_version(input, options)
|
228
|
-
|
229
236
|
@processor_graph = options[:processor_graph]
|
230
237
|
|
231
|
-
@
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
# Otherwise, default is utf-8
|
239
|
-
options[:encoding] ||= 'utf-8'
|
240
|
-
|
241
|
-
case @host_language
|
242
|
-
when :html4, :html5
|
243
|
-
Nokogiri::HTML.parse(input, base_uri.to_s, options[:encoding])
|
238
|
+
@library = case options[:library]
|
239
|
+
when nil
|
240
|
+
# Use Nokogiri when available, and REXML otherwise:
|
241
|
+
(defined?(::Nokogiri) && RUBY_PLATFORM != 'java') ? :nokogiri : :rexml
|
242
|
+
when :nokogiri, :rexml
|
243
|
+
options[:library]
|
244
244
|
else
|
245
|
-
|
246
|
-
end
|
245
|
+
raise ArgumentError.new("expected :rexml or :nokogiri, but got #{options[:library].inspect}")
|
247
246
|
end
|
248
|
-
|
249
|
-
|
247
|
+
|
248
|
+
require "rdf/rdfa/reader/#{@library}"
|
249
|
+
@implementation = case @library
|
250
|
+
when :nokogiri then Nokogiri
|
251
|
+
when :rexml then REXML
|
252
|
+
end
|
253
|
+
self.extend(@implementation)
|
254
|
+
|
255
|
+
detect_host_language_version(input, options)
|
256
|
+
initialize_xml(input, options) rescue raise RDF::ReaderError.new($!.message)
|
257
|
+
|
258
|
+
if (root.nil? && validate?)
|
250
259
|
add_error(nil, "Empty document", RDF::RDFA.DocumentError)
|
251
260
|
raise RDF::ReaderError, "Empty Document"
|
252
261
|
end
|
253
|
-
add_warning(nil, "Syntax errors:\n#{
|
262
|
+
add_warning(nil, "Syntax errors:\n#{doc_errors}", RDF::RDFA.DocumentError) if !doc_errors.empty? && validate?
|
254
263
|
|
255
264
|
# Section 4.2 RDFa Host Language Conformance
|
256
265
|
#
|
@@ -276,96 +285,12 @@ module RDF::RDFa
|
|
276
285
|
@host_defaults[:profiles] = [XML_RDFA_PROFILE, XHTML_RDFA_PROFILE]
|
277
286
|
end
|
278
287
|
|
279
|
-
add_info(@doc, "version = #{@version}, host_language = #{@host_language}")
|
288
|
+
add_info(@doc, "version = #{@version}, host_language = #{@host_language}, library = #{@library}")
|
280
289
|
|
281
290
|
block.call(self) if block_given?
|
282
291
|
end
|
283
292
|
end
|
284
293
|
|
285
|
-
# Determine the host language and/or version from options and the input document
|
286
|
-
def detect_host_language_version(input, options)
|
287
|
-
@host_language = options[:host_language] ? options[:host_language].to_sym : nil
|
288
|
-
@version = options[:version] ? options[:version].to_sym : nil
|
289
|
-
return if @host_language && @version
|
290
|
-
|
291
|
-
# Snif version based on input
|
292
|
-
case input
|
293
|
-
when Nokogiri::XML::Document, Nokogiri::HTML::Document
|
294
|
-
doc_type_string = input.doctype.to_s
|
295
|
-
version_attr = input.root && input.root.attribute("version").to_s
|
296
|
-
root_element = input.root.name.downcase
|
297
|
-
root_namespace = input.root.namespace.to_s
|
298
|
-
root_attrs = input.root.attributes
|
299
|
-
content_type = case
|
300
|
-
when root_element == "html" && input.is_a?(Nokogiri::HTML::Document)
|
301
|
-
"text/html"
|
302
|
-
when root_element == "html" && input.is_a?(Nokogiri::XML::Document)
|
303
|
-
"application/xhtml+html"
|
304
|
-
end
|
305
|
-
else
|
306
|
-
content_type = input.content_type if input.respond_to?(:content_type)
|
307
|
-
|
308
|
-
# Determine from head of document
|
309
|
-
head = if input.respond_to?(:read)
|
310
|
-
input.rewind
|
311
|
-
string = input.read(1000)
|
312
|
-
input.rewind
|
313
|
-
string.to_s
|
314
|
-
else
|
315
|
-
input.to_s[0..1000]
|
316
|
-
end
|
317
|
-
|
318
|
-
doc_type_string = head.match(%r(<!DOCTYPE[^>]*>)m).to_s
|
319
|
-
root = head.match(%r(<[^!\?>]*>)m).to_s
|
320
|
-
root_element = root.match(%r(^<(\S+)[ >])) ? $1 : ""
|
321
|
-
version_attr = root.match(/version\s+=\s+(\S+)[\s">]/m) ? $1 : ""
|
322
|
-
head_element = head.match(%r(<head.*<\/head>)mi)
|
323
|
-
head_doc = Nokogiri::HTML.parse(head_element.to_s)
|
324
|
-
|
325
|
-
# May determine content-type and/or charset from meta
|
326
|
-
# Easist way is to parse head into a document and iterate
|
327
|
-
# of CSS matches
|
328
|
-
head_doc.css("meta").each do |e|
|
329
|
-
if e.attr("http-equiv").to_s.downcase == 'content-type'
|
330
|
-
content_type, e = e.attr("content").to_s.downcase.split(";")
|
331
|
-
options[:encoding] = $1.downcase if e.to_s =~ /charset=([^\s]*)$/i
|
332
|
-
elsif e.attr("charset")
|
333
|
-
options[:encoding] = e.attr("charset").to_s.downcase
|
334
|
-
end
|
335
|
-
end
|
336
|
-
end
|
337
|
-
|
338
|
-
# Already using XML parser, determine from DOCTYPE and/or root element
|
339
|
-
@version ||= :"rdfa1.0" if doc_type_string =~ /RDFa 1\.0/
|
340
|
-
@version ||= :"rdfa1.0" if version_attr =~ /RDFa 1\.0/
|
341
|
-
@version ||= :"rdfa1.1" if version_attr =~ /RDFa 1\.1/
|
342
|
-
@version ||= :"rdfa1.1"
|
343
|
-
|
344
|
-
@host_language ||= case content_type
|
345
|
-
when "application/xml" then :xml1
|
346
|
-
when "image/svg+xml" then :svg
|
347
|
-
when "text/html"
|
348
|
-
case doc_type_string
|
349
|
-
when /html 4/i then :html4
|
350
|
-
when /xhtml/i then :xhtml1
|
351
|
-
when /html/i then :html5
|
352
|
-
end
|
353
|
-
when "application/xhtml+xml"
|
354
|
-
case doc_type_string
|
355
|
-
when /html 4/i then :html4
|
356
|
-
when /xhtml/i then :xhtml1
|
357
|
-
when /html/i then :xhtml5
|
358
|
-
end
|
359
|
-
else
|
360
|
-
case root_element
|
361
|
-
when /svg/i then :svg
|
362
|
-
when /html/i then :html4
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
@host_language ||= :xml1
|
367
|
-
end
|
368
|
-
|
369
294
|
##
|
370
295
|
# Iterates the given block for each RDF statement in the input.
|
371
296
|
#
|
@@ -414,17 +339,14 @@ module RDF::RDFa
|
|
414
339
|
@bnode_cache[value.to_s] ||= RDF::Node.new(value)
|
415
340
|
end
|
416
341
|
|
417
|
-
# Figure out the document path, if it is
|
342
|
+
# Figure out the document path, if it is an Element or Attribute
|
418
343
|
def node_path(node)
|
419
|
-
"<#{base_uri}
|
420
|
-
when Nokogiri::XML::Node then node.display_path
|
421
|
-
else node.to_s
|
422
|
-
end
|
344
|
+
"<#{base_uri}>#{node.respond_to?(:display_path) ? node.display_path : node}"
|
423
345
|
end
|
424
346
|
|
425
347
|
# Add debug event to debug array, if specified
|
426
348
|
#
|
427
|
-
# @param [
|
349
|
+
# @param [#display_path, #to_s] node:: XML Node or string for showing context
|
428
350
|
# @param [String] message::
|
429
351
|
# @yieldreturn [String] appended to message, to allow for lazy-evaulation of message
|
430
352
|
def add_debug(node, message = "")
|
@@ -464,7 +386,7 @@ module RDF::RDFa
|
|
464
386
|
|
465
387
|
# add a statement, object can be literal or URI or bnode
|
466
388
|
#
|
467
|
-
# @param [
|
389
|
+
# @param [#display_path, #to_s] node:: XML Node or string for showing context
|
468
390
|
# @param [RDF::URI, RDF::BNode] subject:: the subject of the statement
|
469
391
|
# @param [RDF::URI] predicate:: the predicate of the statement
|
470
392
|
# @param [URI, RDF::BNode, RDF::Literal] object:: the object of the statement
|
@@ -478,16 +400,7 @@ module RDF::RDFa
|
|
478
400
|
|
479
401
|
# Parsing an RDFa document (this is *not* the recursive method)
|
480
402
|
def parse_whole_document(doc, base)
|
481
|
-
|
482
|
-
case @host_language
|
483
|
-
when :xhtml1, :xhtml5, :html4, :html5
|
484
|
-
base_el = doc.at_css("html>head>base")
|
485
|
-
base = base_el.attribute("href").to_s.split("#").first if base_el
|
486
|
-
else
|
487
|
-
xml_base = doc.root.attribute_with_ns("base", RDF::XML.to_s)
|
488
|
-
base = xml_base if xml_base
|
489
|
-
end
|
490
|
-
|
403
|
+
base = doc_base(base)
|
491
404
|
if (base)
|
492
405
|
# Strip any fragment from base
|
493
406
|
base = base.to_s.split("#").first
|
@@ -500,8 +413,8 @@ module RDF::RDFa
|
|
500
413
|
|
501
414
|
if @version != :"rdfa1.0"
|
502
415
|
# Process default vocabularies
|
503
|
-
process_profile(
|
504
|
-
add_debug(
|
416
|
+
process_profile(root, @host_defaults[:profiles]) do |which, value|
|
417
|
+
add_debug(root) { "parse_whole_document, #{which}: #{value.inspect}"}
|
505
418
|
case which
|
506
419
|
when :uri_mappings then evaluation_context.uri_mappings.merge!(value)
|
507
420
|
when :term_mappings then evaluation_context.term_mappings.merge!(value)
|
@@ -510,7 +423,7 @@ module RDF::RDFa
|
|
510
423
|
end
|
511
424
|
end
|
512
425
|
|
513
|
-
traverse(
|
426
|
+
traverse(root, evaluation_context)
|
514
427
|
add_debug("", "parse_whole_doc: traversal complete'")
|
515
428
|
end
|
516
429
|
|
@@ -521,33 +434,33 @@ module RDF::RDFa
|
|
521
434
|
profiles.
|
522
435
|
map {|uri| uri(uri).normalize}.
|
523
436
|
each do |uri|
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
437
|
+
# Don't try to open ourselves!
|
438
|
+
if base_uri == uri
|
439
|
+
add_debug(element) {"process_profile: skip recursive profile <#{uri}>"}
|
440
|
+
next
|
441
|
+
end
|
529
442
|
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
443
|
+
old_debug = RDF::RDFa.debug?
|
444
|
+
begin
|
445
|
+
add_info(element, "process_profile: load <#{uri}>")
|
446
|
+
RDF::RDFa.debug = false
|
447
|
+
profile = Profile.find(uri)
|
448
|
+
rescue Exception => e
|
449
|
+
RDF::RDFa.debug = old_debug
|
450
|
+
add_error(element, e.message, RDF::RDFA.ProfileReferenceError)
|
451
|
+
raise # In case we're not in strict mode, we need to be sure processing stops
|
452
|
+
ensure
|
453
|
+
RDF::RDFa.debug = old_debug
|
454
|
+
end
|
542
455
|
|
543
|
-
|
544
|
-
|
545
|
-
|
456
|
+
# Add URI Mappings to prefixes
|
457
|
+
profile.prefixes.each_pair do |prefix, value|
|
458
|
+
prefix(prefix, value)
|
459
|
+
end
|
460
|
+
yield :uri_mappings, profile.prefixes unless profile.prefixes.empty?
|
461
|
+
yield :term_mappings, profile.terms unless profile.terms.empty?
|
462
|
+
yield :default_vocabulary, profile.vocabulary if profile.vocabulary
|
546
463
|
end
|
547
|
-
yield :uri_mappings, profile.prefixes unless profile.prefixes.empty?
|
548
|
-
yield :term_mappings, profile.terms unless profile.terms.empty?
|
549
|
-
yield :default_vocabulary, profile.vocabulary if profile.vocabulary
|
550
|
-
end
|
551
464
|
end
|
552
465
|
|
553
466
|
# Extract the XMLNS mappings from an element
|
@@ -558,15 +471,20 @@ module RDF::RDFa
|
|
558
471
|
# and the URI is not processed in any way; in particular if it is a relative path it is
|
559
472
|
# not resolved against the current base.
|
560
473
|
ns_defs = {}
|
561
|
-
element.
|
562
|
-
|
474
|
+
element.namespaces.each do |prefix, href|
|
475
|
+
prefix = nil if prefix == "xmlns"
|
476
|
+
add_debug("extract_mappings") { "ns: #{prefix}: #{href}"}
|
477
|
+
ns_defs[prefix] = href
|
563
478
|
end
|
564
479
|
|
565
480
|
# HTML parsing doesn't create namespace_definitions
|
566
481
|
if ns_defs.empty?
|
567
482
|
ns_defs = {}
|
568
|
-
element.attributes.each do |
|
569
|
-
|
483
|
+
element.attributes.each do |attr, href|
|
484
|
+
next unless attr =~ /^xmlns(?:\:(.+))?/
|
485
|
+
prefix = $1
|
486
|
+
add_debug("extract_mappings") { "ns(attr): #{prefix}: #{href}"}
|
487
|
+
ns_defs[prefix] = href.to_s
|
570
488
|
end
|
571
489
|
end
|
572
490
|
|
@@ -624,6 +542,7 @@ module RDF::RDFa
|
|
624
542
|
recurse = true
|
625
543
|
skip = false
|
626
544
|
new_subject = nil
|
545
|
+
typed_resource = nil
|
627
546
|
current_object_resource = nil
|
628
547
|
uri_mappings = evaluation_context.uri_mappings.clone
|
629
548
|
namespaces = evaluation_context.namespaces.clone
|
@@ -633,58 +552,39 @@ module RDF::RDFa
|
|
633
552
|
default_vocabulary = evaluation_context.default_vocabulary
|
634
553
|
list_mapping = evaluation_context.list_mapping
|
635
554
|
|
636
|
-
|
637
|
-
attrs = element.attributes
|
638
|
-
|
639
|
-
about = attrs['about']
|
640
|
-
src = attrs['src']
|
641
|
-
resource = attrs['resource']
|
642
|
-
href = attrs['href']
|
643
|
-
vocab = attrs['vocab']
|
644
|
-
xml_base = element.attribute_with_ns("base", RDF::XML.to_s)
|
555
|
+
xml_base = element.base
|
645
556
|
base = xml_base.to_s if xml_base && ![:xhtml1, :xhtml5, :html4, :html5].include?(@host_language)
|
646
557
|
base ||= evaluation_context.base
|
647
558
|
|
648
559
|
# Pull out the attributes needed for the skip test.
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
560
|
+
attrs = {}
|
561
|
+
%w(
|
562
|
+
about
|
563
|
+
content
|
564
|
+
data
|
565
|
+
datatype
|
566
|
+
datetime
|
567
|
+
href
|
568
|
+
inlist
|
569
|
+
property
|
570
|
+
rel
|
571
|
+
resource
|
572
|
+
rev
|
573
|
+
src
|
574
|
+
typeof
|
575
|
+
vocab
|
576
|
+
).each do |a|
|
577
|
+
attrs[a.to_sym] = element.attributes[a].to_s.strip if element.attributes[a]
|
578
|
+
end
|
662
579
|
|
663
|
-
add_debug(element)
|
664
|
-
attrs = {
|
665
|
-
:about => about,
|
666
|
-
:src => src,
|
667
|
-
:resource => resource,
|
668
|
-
:href => href,
|
669
|
-
:vocab => vocab,
|
670
|
-
:base => xml_base,
|
671
|
-
:property => property,
|
672
|
-
:typeof => typeof,
|
673
|
-
:datatype => datatype,
|
674
|
-
:rel => rel,
|
675
|
-
:rev => rev,
|
676
|
-
:inlist => inlist,
|
677
|
-
}.select {|k,v| v}
|
678
|
-
|
679
|
-
"attrs " + attrs.map {|a| "#{a.first}: #{a.last}"}.join(", ")
|
680
|
-
end unless attrs.empty?
|
580
|
+
add_debug(element) {"attrs " + attrs.inspect} unless attrs.empty?
|
681
581
|
|
682
582
|
# Default vocabulary [7.5 Step 2]
|
683
583
|
# Next the current element is examined for any change to the default vocabulary via @vocab.
|
684
584
|
# If @vocab is present and contains a value, its value updates the local default vocabulary.
|
685
585
|
# If the value is empty, then the local default vocabulary must be reset to the Host Language defined default.
|
686
|
-
|
687
|
-
default_vocabulary = if vocab.
|
586
|
+
if attrs[:vocab]
|
587
|
+
default_vocabulary = if attrs[:vocab].empty?
|
688
588
|
# Set default_vocabulary to host language default
|
689
589
|
add_debug(element) {
|
690
590
|
"[Step 3] reset default_vocaulary to #{@host_defaults.fetch(:vocabulary, nil).inspect}"
|
@@ -692,9 +592,9 @@ module RDF::RDFa
|
|
692
592
|
@host_defaults.fetch(:vocabulary, nil)
|
693
593
|
else
|
694
594
|
# Generate a triple indicating that the vocabulary is used
|
695
|
-
add_triple(element, base, RDF::RDFA.hasVocabulary, uri(vocab))
|
595
|
+
add_triple(element, base, RDF::RDFA.hasVocabulary, uri(attrs[:vocab]))
|
696
596
|
|
697
|
-
uri(vocab)
|
597
|
+
uri(attrs[:vocab])
|
698
598
|
end
|
699
599
|
add_debug(element) {
|
700
600
|
"[Step 2] default_vocaulary: #{default_vocabulary.inspect}"
|
@@ -707,33 +607,17 @@ module RDF::RDFa
|
|
707
607
|
extract_mappings(element, uri_mappings, namespaces)
|
708
608
|
|
709
609
|
# Language information [7.5 Step 4]
|
710
|
-
|
711
|
-
# If both the lang attribute in no namespace and the lang attribute in the XML namespace are set
|
712
|
-
# on an element, user agents must use the lang attribute in the XML namespace, and the lang
|
713
|
-
# attribute in no namespace must be ignored for the purposes of determining the element's
|
714
|
-
# language.
|
715
|
-
language = case
|
716
|
-
when @doc.is_a?(Nokogiri::HTML::Document) && element.attributes["xml:lang"]
|
717
|
-
element.attributes["xml:lang"].to_s
|
718
|
-
when @doc.is_a?(Nokogiri::HTML::Document) && element.attributes["lang"]
|
719
|
-
element.attributes["lang"].to_s
|
720
|
-
when element.at_xpath("@xml:lang", "xml" => RDF::XML["uri"].to_s)
|
721
|
-
element.at_xpath("@xml:lang", "xml" => RDF::XML["uri"].to_s).to_s
|
722
|
-
when element.at_xpath("@lang")
|
723
|
-
element.at_xpath("@lang").to_s
|
724
|
-
else
|
725
|
-
language
|
726
|
-
end
|
610
|
+
language = element.language || language
|
727
611
|
language = nil if language.to_s.empty?
|
728
|
-
add_debug(element
|
612
|
+
add_debug(element) {"HTML5 [3.2.3.3] lang: #{language.inspect}"} if language
|
729
613
|
|
730
614
|
# rels and revs
|
731
|
-
rels = process_uris(element, rel, evaluation_context, base,
|
615
|
+
rels = process_uris(element, attrs[:rel], evaluation_context, base,
|
732
616
|
:uri_mappings => uri_mappings,
|
733
617
|
:term_mappings => term_mappings,
|
734
618
|
:vocab => default_vocabulary,
|
735
619
|
:restrictions => TERMorCURIEorAbsURI.fetch(@version, []))
|
736
|
-
revs = process_uris(element, rev, evaluation_context, base,
|
620
|
+
revs = process_uris(element, attrs[:rev], evaluation_context, base,
|
737
621
|
:uri_mappings => uri_mappings,
|
738
622
|
:term_mappings => term_mappings,
|
739
623
|
:vocab => default_vocabulary,
|
@@ -743,64 +627,152 @@ module RDF::RDFa
|
|
743
627
|
"rels: #{rels.join(" ")}, revs: #{revs.join(" ")}"
|
744
628
|
end unless (rels + revs).empty?
|
745
629
|
|
746
|
-
if !(rel || rev)
|
630
|
+
if !(attrs[:rel] || attrs[:rev])
|
747
631
|
# Establishing a new subject if no rel/rev [7.5 Step 5]
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
end
|
632
|
+
|
633
|
+
if @version == :"rdfa1.0"
|
634
|
+
new_subject = if attrs[:about]
|
635
|
+
process_uri(element, attrs[:about], evaluation_context, base,
|
636
|
+
:uri_mappings => uri_mappings,
|
637
|
+
:restrictions => SafeCURIEorCURIEorURI.fetch(@version, []))
|
638
|
+
elsif attrs[:resource]
|
639
|
+
process_uri(element, attrs[:resource], evaluation_context, base,
|
640
|
+
:uri_mappings => uri_mappings,
|
641
|
+
:restrictions => SafeCURIEorCURIEorURI.fetch(@version, []))
|
642
|
+
elsif attrs[:href] || attrs[:src]
|
643
|
+
process_uri(element, (attrs[:href] || attrs[:src]), evaluation_context, base, :restrictions => [:uri])
|
644
|
+
end
|
762
645
|
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
646
|
+
# If no URI is provided by a resource attribute, then the first match from the following rules
|
647
|
+
# will apply:
|
648
|
+
new_subject ||= if [:xhtml1, :xhtml5, :html4, :html5].include?(@host_language) && element.name =~ /^(head|body)$/
|
649
|
+
# From XHTML+RDFa 1.1:
|
650
|
+
# if no URI is provided, then first check to see if the element is the head or body element.
|
651
|
+
# If it is, then act as if there is an empty @about present, and process it according to the rule for @about.
|
652
|
+
uri(base)
|
653
|
+
elsif element == root && base
|
654
|
+
# if the element is the root element of the document, then act as if there is an empty @about present,
|
655
|
+
# and process it according to the rule for @about, above;
|
656
|
+
uri(base)
|
657
|
+
elsif attrs[:typeof]
|
658
|
+
RDF::Node.new
|
659
|
+
else
|
660
|
+
# otherwise, if parent object is present, new subject is set to the value of parent object.
|
661
|
+
skip = true unless attrs[:property]
|
662
|
+
evaluation_context.parent_object
|
663
|
+
end
|
664
|
+
|
665
|
+
# if the @typeof attribute is present, set typed resource to new subject
|
666
|
+
typed_resource = new_subject if attrs[:typeof]
|
778
667
|
else
|
779
|
-
#
|
780
|
-
|
781
|
-
|
668
|
+
# If the current element contains the @property attribute, but does not contain the @content or the @datatype attribute
|
669
|
+
if attrs[:property] && !(attrs[:content] || attrs[:datatype]) && evaluation_context.incomplete_triples.empty?
|
670
|
+
new_subject = process_uri(element, attrs[:about], evaluation_context, base,
|
671
|
+
:uri_mappings => uri_mappings,
|
672
|
+
:restrictions => SafeCURIEorCURIEorURI.fetch(@version, [])) if attrs[:about]
|
673
|
+
|
674
|
+
# if the @typeof attribute is present, set typed resource to new subject
|
675
|
+
typed_resource = new_subject if attrs[:typeof]
|
676
|
+
|
677
|
+
# If no URI is provided by a resource attribute, then the first match from the following rules
|
678
|
+
# will apply:
|
679
|
+
new_subject ||= if [:xhtml1, :xhtml5, :html4, :html5].include?(@host_language) && element.name =~ /^(head|body)$/
|
680
|
+
# From XHTML+RDFa 1.1:
|
681
|
+
# if no URI is provided, then first check to see if the element is the head or body element.
|
682
|
+
# If it is, then act as if there is an empty @about present, and process it according to the rule for @about.
|
683
|
+
uri(base)
|
684
|
+
elsif element == root && base
|
685
|
+
# if the element is the root element of the document, then act as if there is an empty @about present,
|
686
|
+
# and process it according to the rule for @about, above;
|
687
|
+
uri(base)
|
688
|
+
else
|
689
|
+
# otherwise, if parent object is present, new subject is set to the value of parent object.
|
690
|
+
evaluation_context.parent_object
|
691
|
+
end
|
692
|
+
|
693
|
+
if attrs[:typeof]
|
694
|
+
typed_resource ||= if attrs[:resource]
|
695
|
+
process_uri(element, attrs[:resource], evaluation_context, base,
|
696
|
+
:uri_mappings => uri_mappings,
|
697
|
+
:restrictions => SafeCURIEorCURIEorURI.fetch(@version, []))
|
698
|
+
elsif attrs[:href] || attrs[:src]
|
699
|
+
process_uri(element, (attrs[:href] || attrs[:src]), evaluation_context, base, :restrictions => [:uri])
|
700
|
+
else
|
701
|
+
# if none of these are present, the value of typed resource is set to a newly defined bnode.
|
702
|
+
RDF::Node.new
|
703
|
+
end
|
704
|
+
|
705
|
+
# The value of the current object resource is set to the value of typed resource.
|
706
|
+
current_object_resource = typed_resource
|
707
|
+
end
|
708
|
+
else
|
709
|
+
# otherwise (ie, the @property element is not present)
|
710
|
+
|
711
|
+
new_subject = if attrs[:about]
|
712
|
+
process_uri(element, attrs[:about], evaluation_context, base,
|
713
|
+
:uri_mappings => uri_mappings,
|
714
|
+
:restrictions => SafeCURIEorCURIEorURI.fetch(@version, []))
|
715
|
+
elsif attrs[:resource]
|
716
|
+
process_uri(element, attrs[:resource], evaluation_context, base,
|
717
|
+
:uri_mappings => uri_mappings,
|
718
|
+
:restrictions => SafeCURIEorCURIEorURI.fetch(@version, []))
|
719
|
+
elsif attrs[:href] || attrs[:src]
|
720
|
+
process_uri(element, (attrs[:href] || attrs[:src]), evaluation_context, base, :restrictions => [:uri])
|
721
|
+
end
|
722
|
+
|
723
|
+
# If no URI is provided by a resource attribute, then the first match from the following rules
|
724
|
+
# will apply:
|
725
|
+
new_subject ||= if [:xhtml1, :xhtml5, :html4, :html5].include?(@host_language) && element.name =~ /^(head|body)$/
|
726
|
+
# From XHTML+RDFa 1.1:
|
727
|
+
# if no URI is provided, then first check to see if the element is the head or body element.
|
728
|
+
# If it is, then act as if there is an empty @about present, and process it according to the rule for @about.
|
729
|
+
uri(base)
|
730
|
+
elsif element == root && base
|
731
|
+
# if the element is the root element of the document, then act as if there is an empty @about present,
|
732
|
+
# and process it according to the rule for @about, above;
|
733
|
+
uri(base)
|
734
|
+
elsif attrs[:typeof]
|
735
|
+
RDF::Node.new
|
736
|
+
else
|
737
|
+
# otherwise, if parent object is present, new subject is set to the value of parent object.
|
738
|
+
# Additionally, if @property is not present then the skip element flag is set to 'true'.
|
739
|
+
skip = true unless attrs[:property]
|
740
|
+
evaluation_context.parent_object
|
741
|
+
end
|
742
|
+
|
743
|
+
# if @typeof is present, set the typed resource to the value of new subject</code>
|
744
|
+
typed_resource ||= new_subject if attrs[:typeof]
|
745
|
+
end
|
782
746
|
end
|
783
|
-
|
747
|
+
|
748
|
+
add_debug(element) {
|
749
|
+
"[Step 5] new_subject: #{new_subject.to_ntriples rescue 'nil'}, " +
|
750
|
+
"typed_resource: #{typed_resource.to_ntriples rescue 'nil'}, " +
|
751
|
+
"skip = #{skip}"
|
752
|
+
}
|
784
753
|
else
|
785
754
|
# [7.5 Step 6]
|
786
755
|
# If the current element does contain a @rel or @rev attribute, then the next step is to
|
787
756
|
# establish both a value for new subject and a value for current object resource:
|
788
|
-
new_subject = process_uri(element, about, evaluation_context, base,
|
757
|
+
new_subject = process_uri(element, attrs[:about], evaluation_context, base,
|
789
758
|
:uri_mappings => uri_mappings,
|
790
759
|
:restrictions => SafeCURIEorCURIEorURI.fetch(@version, []))
|
791
|
-
new_subject ||= process_uri(element, src, evaluation_context, base,
|
760
|
+
new_subject ||= process_uri(element, attrs[:src], evaluation_context, base,
|
792
761
|
:uri_mappings => uri_mappings,
|
793
762
|
:restrictions => [:uri]) if @version == :"rdfa1.0"
|
794
763
|
|
764
|
+
# if the @typeof attribute is present, set typed resource to new subject
|
765
|
+
typed_resource = new_subject if attrs[:typeof]
|
766
|
+
|
795
767
|
# If no URI is provided then the first match from the following rules will apply
|
796
|
-
new_subject ||= if element ==
|
768
|
+
new_subject ||= if element == root && base
|
797
769
|
uri(base)
|
798
770
|
elsif [:xhtml1, :xhtml5, :html4, :html5].include?(@host_language) && element.name =~ /^(head|body)$/
|
799
771
|
# From XHTML+RDFa 1.1:
|
800
772
|
# if no URI is provided, then first check to see if the element is the head or body element.
|
801
773
|
# If it is, then act as if there is an empty @about present, and process it according to the rule for @about.
|
802
774
|
uri(base)
|
803
|
-
elsif
|
775
|
+
elsif attrs[:typeof] && @version == :"rdfa1.0"
|
804
776
|
RDF::Node.new
|
805
777
|
else
|
806
778
|
# if it's null, it's null and nothing changes
|
@@ -809,32 +781,49 @@ module RDF::RDFa
|
|
809
781
|
end
|
810
782
|
|
811
783
|
# Then the current object resource is set to the URI obtained from the first match from the following rules:
|
812
|
-
current_object_resource = if resource
|
813
|
-
process_uri(element, resource, evaluation_context, base,
|
784
|
+
current_object_resource = if attrs[:resource]
|
785
|
+
process_uri(element, attrs[:resource], evaluation_context, base,
|
814
786
|
:uri_mappings => uri_mappings,
|
815
787
|
:restrictions => SafeCURIEorCURIEorURI.fetch(@version, []))
|
816
|
-
elsif href
|
817
|
-
process_uri(element, href, evaluation_context, base,
|
788
|
+
elsif attrs[:href]
|
789
|
+
process_uri(element, attrs[:href], evaluation_context, base,
|
818
790
|
:restrictions => [:uri])
|
819
|
-
elsif src && @version != :"rdfa1.0"
|
820
|
-
process_uri(element, src, evaluation_context, base,
|
791
|
+
elsif attrs[:src] && @version != :"rdfa1.0"
|
792
|
+
process_uri(element, attrs[:src], evaluation_context, base,
|
821
793
|
:restrictions => [:uri])
|
794
|
+
elsif attrs[:typeof] && !attrs[:about] && @version != :"rdfa1.0"
|
795
|
+
# otherwise, if @typeof is present and @about is not and the incomplete triples
|
796
|
+
# within the current context is empty, use a newly created bnode
|
797
|
+
RDF::Node.new
|
822
798
|
end
|
823
799
|
|
824
|
-
|
800
|
+
# and also set the value typed resource to this bnode
|
801
|
+
if attrs[:typeof]
|
802
|
+
if @version == :"rdfa1.0"
|
803
|
+
typed_resource = new_subject
|
804
|
+
else
|
805
|
+
typed_resource = current_object_resource if !attrs[:about]
|
806
|
+
end
|
807
|
+
end
|
808
|
+
|
809
|
+
add_debug(element) {
|
810
|
+
"[Step 6] new_subject: #{new_subject}, " +
|
811
|
+
"current_object_resource = #{current_object_resource.nil? ? 'nil' : current_object_resource} " +
|
812
|
+
"typed_resource: #{typed_resource.to_ntriples rescue 'nil'}, "
|
813
|
+
}
|
825
814
|
end
|
826
815
|
|
827
816
|
# Process @typeof if there is a subject [Step 7]
|
828
|
-
if
|
817
|
+
if typed_resource
|
829
818
|
# Typeof is TERMorCURIEorAbsURIs
|
830
|
-
types = process_uris(element, typeof, evaluation_context, base,
|
819
|
+
types = process_uris(element, attrs[:typeof], evaluation_context, base,
|
831
820
|
:uri_mappings => uri_mappings,
|
832
821
|
:term_mappings => term_mappings,
|
833
822
|
:vocab => default_vocabulary,
|
834
823
|
:restrictions => TERMorCURIEorAbsURI.fetch(@version, []))
|
835
|
-
add_debug(element, "typeof: #{typeof}")
|
824
|
+
add_debug(element, "[Step 7] typeof: #{attrs[:typeof]}")
|
836
825
|
types.each do |one_type|
|
837
|
-
add_triple(element,
|
826
|
+
add_triple(element, typed_resource, RDF["type"], one_type)
|
838
827
|
end
|
839
828
|
end
|
840
829
|
|
@@ -855,16 +844,17 @@ module RDF::RDFa
|
|
855
844
|
#
|
856
845
|
# If the current element has a @inlist attribute, add the property to the
|
857
846
|
# list associated with that property, creating a new list if necessary.
|
858
|
-
if new_subject
|
847
|
+
if new_subject && current_object_resource && (attrs[:rel] || attrs[:rev])
|
848
|
+
add_debug(element) {"[Step 9] rels: #{rels.inspect} revs: #{revs.inspect}"}
|
859
849
|
rels.each do |r|
|
860
|
-
if inlist
|
850
|
+
if attrs[:inlist]
|
861
851
|
# If the current list mapping does not contain a list associated with this IRI,
|
862
852
|
# instantiate a new list
|
863
853
|
unless list_mapping[r]
|
864
854
|
list_mapping[r] = RDF::List.new
|
865
855
|
add_debug(element) {"list(#{r}): create #{list_mapping[r].inspect}"}
|
866
856
|
end
|
867
|
-
add_debug(element
|
857
|
+
add_debug(element) {"[Step 9] add #{current_object_resource.to_ntriples} to #{r} #{list_mapping[r].inspect}"}
|
868
858
|
list_mapping[r] << current_object_resource
|
869
859
|
else
|
870
860
|
add_triple(element, new_subject, r, current_object_resource)
|
@@ -874,7 +864,7 @@ module RDF::RDFa
|
|
874
864
|
revs.each do |r|
|
875
865
|
add_triple(element, current_object_resource, r, new_subject)
|
876
866
|
end
|
877
|
-
elsif rel || rev
|
867
|
+
elsif attrs[:rel] || attrs[:rev]
|
878
868
|
# Incomplete triples and bnode creation [Step 10]
|
879
869
|
add_debug(element) {"[Step 10] incompletes: rels: #{rels}, revs: #{revs}"}
|
880
870
|
current_object_resource = RDF::Node.new
|
@@ -884,7 +874,7 @@ module RDF::RDFa
|
|
884
874
|
# lists: Save into list, don't generate triple
|
885
875
|
|
886
876
|
rels.each do |r|
|
887
|
-
if inlist
|
877
|
+
if attrs[:inlist]
|
888
878
|
# If the current list mapping does not contain a list associated with this IRI,
|
889
879
|
# instantiate a new list
|
890
880
|
unless list_mapping[r]
|
@@ -906,8 +896,8 @@ module RDF::RDFa
|
|
906
896
|
#
|
907
897
|
# If the current element has a @inlist attribute, add the property to the
|
908
898
|
# list associated with that property, creating a new list if necessary.
|
909
|
-
if property
|
910
|
-
properties = process_uris(element, property, evaluation_context, base,
|
899
|
+
if attrs[:property]
|
900
|
+
properties = process_uris(element, attrs[:property], evaluation_context, base,
|
911
901
|
:uri_mappings => uri_mappings,
|
912
902
|
:term_mappings => term_mappings,
|
913
903
|
:vocab => default_vocabulary,
|
@@ -917,27 +907,23 @@ module RDF::RDFa
|
|
917
907
|
if p.is_a?(RDF::URI)
|
918
908
|
false
|
919
909
|
else
|
920
|
-
|
910
|
+
add_warning(element, "[Step 11] predicate #{p.to_ntriples} must be a URI")
|
921
911
|
true
|
922
912
|
end
|
923
913
|
end
|
924
914
|
|
925
|
-
|
926
|
-
children_node_types = element.children.collect{|c| c.class}.uniq
|
927
|
-
|
928
|
-
# the following 3 IF clauses should be mutually exclusive. Written as is to prevent extensive indentation.
|
929
|
-
datatype = process_uri(element, datatype, evaluation_context, base,
|
915
|
+
datatype = process_uri(element, attrs[:datatype], evaluation_context, base,
|
930
916
|
:uri_mappings => uri_mappings,
|
931
917
|
:term_mappings => term_mappings,
|
932
918
|
:vocab => default_vocabulary,
|
933
|
-
:restrictions => TERMorCURIEorAbsURI.fetch(@version, [])) unless datatype.to_s.empty?
|
919
|
+
:restrictions => TERMorCURIEorAbsURI.fetch(@version, [])) unless attrs[:datatype].to_s.empty?
|
934
920
|
begin
|
935
|
-
|
921
|
+
current_property_value = if datatype && datatype != RDF.XMLLiteral
|
936
922
|
# typed literal
|
937
923
|
add_debug(element, "[Step 11] typed literal (#{datatype})")
|
938
|
-
RDF::Literal.new(content || element.inner_text.to_s, :datatype => datatype, :language => language, :validate => validate?, :canonicalize => canonicalize?)
|
924
|
+
RDF::Literal.new(attrs[:content] || element.inner_text.to_s, :datatype => datatype, :language => language, :validate => validate?, :canonicalize => canonicalize?)
|
939
925
|
elsif @version == :"rdfa1.1"
|
940
|
-
if datatype
|
926
|
+
if datatype == RDF.XMLLiteral
|
941
927
|
# XML Literal
|
942
928
|
add_debug(element) {"[Step 11(1.1)] XML Literal: #{element.inner_html}"}
|
943
929
|
|
@@ -948,35 +934,73 @@ module RDF::RDFa
|
|
948
934
|
# generating the serialized element definition. For avoidance of doubt, any re-declarations on the
|
949
935
|
# child node must take precedence over declarations that were active on the current node.
|
950
936
|
begin
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
937
|
+
c14nxl = element.children.c14nxl(
|
938
|
+
:library => @library,
|
939
|
+
:language => language,
|
940
|
+
:namespaces => {nil => XHTML}.merge(namespaces))
|
941
|
+
RDF::Literal.new(c14nxl,
|
942
|
+
:library => @library,
|
943
|
+
:datatype => RDF.XMLLiteral,
|
944
|
+
:validate => validate?,
|
945
|
+
:canonicalize => canonicalize?)
|
957
946
|
rescue ArgumentError => e
|
958
947
|
add_error(element, e.message)
|
959
948
|
end
|
949
|
+
elsif attrs[:datetime]
|
950
|
+
# Lexically scan value and assign appropriate type, otherwise, leave untyped
|
951
|
+
v = element.attribute('datetime').to_s
|
952
|
+
datatype = %w(Date Time DateTime Duration).map {|t| RDF::Literal.const_get(t)}.detect do |dt|
|
953
|
+
v.match(dt::GRAMMAR)
|
954
|
+
end || RDF::Literal
|
955
|
+
add_debug(element) {"[Step 11(1.1)] datetime literal: #{v.class}"}
|
956
|
+
datatype.new(v)
|
957
|
+
elsif attrs[:content]
|
958
|
+
# plain literal
|
959
|
+
add_debug(element, "[Step 11(1.1)] plain literal (content)")
|
960
|
+
RDF::Literal.new(attrs[:content], :language => language, :validate => validate?, :canonicalize => canonicalize?)
|
961
|
+
elsif attrs[:value]
|
962
|
+
# plain literal
|
963
|
+
add_debug(element, "[Step 11(1.1)] plain literal (value)")
|
964
|
+
RDF::Literal.new(attrs[:value], :validate => validate?, :canonicalize => canonicalize?)
|
965
|
+
elsif (attrs[:resource] || attrs[:href] || attrs[:src] || attrs[:data]) &&
|
966
|
+
!(attrs[:rel] || attrs[:rev]) &&
|
967
|
+
evaluation_context.incomplete_triples.empty? &&
|
968
|
+
@version != :"rdfa1.0"
|
969
|
+
if attrs[:resource]
|
970
|
+
add_debug(element, "[Step 11(1.1)] IRI literal (resource)")
|
971
|
+
process_uri(element, attrs[:resource], evaluation_context, base,
|
972
|
+
:uri_mappings => uri_mappings,
|
973
|
+
:restrictions => SafeCURIEorCURIEorURI.fetch(@version, []))
|
974
|
+
else
|
975
|
+
add_debug(element, "[Step 11(1.1)] IRI literal (href/src/data)")
|
976
|
+
process_uri(element, (attrs[:href] || attrs[:src] || attrs[:data]), evaluation_context, base, :restrictions => [:uri])
|
977
|
+
end
|
978
|
+
elsif typed_resource && !attrs[:about] && evaluation_context.incomplete_triples.empty? && @version != :"rdfa1.0"
|
979
|
+
add_debug(element, "[Step 11(1.1)] typed_resource")
|
980
|
+
typed_resource
|
960
981
|
else
|
961
982
|
# plain literal
|
962
|
-
add_debug(element, "[Step 11(1.1)] plain literal")
|
963
|
-
RDF::Literal.new(
|
983
|
+
add_debug(element, "[Step 11(1.1)] plain literal (inner text)")
|
984
|
+
RDF::Literal.new(element.inner_text.to_s, :language => language, :validate => validate?, :canonicalize => canonicalize?)
|
964
985
|
end
|
965
986
|
else
|
966
|
-
if
|
987
|
+
if element.text_content? || (element.children.length == 0) || attrs[:datatype] == ""
|
967
988
|
# plain literal
|
968
989
|
add_debug(element, "[Step 11 (1.0)] plain literal")
|
969
|
-
RDF::Literal.new(content || element.inner_text.to_s, :language => language, :validate => validate?, :canonicalize => canonicalize?)
|
970
|
-
elsif
|
990
|
+
RDF::Literal.new(attrs[:content] || element.inner_text.to_s, :language => language, :validate => validate?, :canonicalize => canonicalize?)
|
991
|
+
elsif !element.text_content? and (datatype == nil or datatype.to_s == RDF.XMLLiteral.to_s)
|
971
992
|
# XML Literal
|
972
993
|
add_debug(element) {"[Step 11 (1.0)] XML Literal: #{element.inner_html}"}
|
973
994
|
recurse = false
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
995
|
+
c14nxl = element.children.c14nxl(
|
996
|
+
:library => @library,
|
997
|
+
:language => language,
|
998
|
+
:namespaces => {nil => XHTML}.merge(namespaces))
|
999
|
+
RDF::Literal.new(c14nxl,
|
1000
|
+
:library => @library,
|
1001
|
+
:datatype => RDF.XMLLiteral,
|
1002
|
+
:validate => validate?,
|
1003
|
+
:canonicalize => canonicalize?)
|
980
1004
|
end
|
981
1005
|
end
|
982
1006
|
rescue ArgumentError => e
|
@@ -986,22 +1010,22 @@ module RDF::RDFa
|
|
986
1010
|
# add each property
|
987
1011
|
properties.each do |p|
|
988
1012
|
# Lists: If element has an @inlist attribute, add the value to a list
|
989
|
-
if inlist
|
1013
|
+
if attrs[:inlist]
|
990
1014
|
# If the current list mapping does not contain a list associated with this IRI,
|
991
1015
|
# instantiate a new list
|
992
1016
|
unless list_mapping[p]
|
993
1017
|
list_mapping[p] = RDF::List.new
|
994
1018
|
add_debug(element) {"[Step 11] lists(#{p}): create #{list_mapping[p].inspect}"}
|
995
1019
|
end
|
996
|
-
add_debug(element) {"[Step 11] add #{
|
997
|
-
list_mapping[p] <<
|
1020
|
+
add_debug(element) {"[Step 11] add #{current_property_value.to_ntriples} to #{p.to_ntriples} #{list_mapping[p].inspect}"}
|
1021
|
+
list_mapping[p] << current_property_value
|
998
1022
|
elsif new_subject
|
999
|
-
add_triple(element, new_subject, p,
|
1023
|
+
add_triple(element, new_subject, p, current_property_value)
|
1000
1024
|
end
|
1001
1025
|
end
|
1002
1026
|
end
|
1003
1027
|
|
1004
|
-
if
|
1028
|
+
if !skip and new_subject && !evaluation_context.incomplete_triples.empty?
|
1005
1029
|
# Complete the incomplete triples from the evaluation context [Step 12]
|
1006
1030
|
add_debug(element) do
|
1007
1031
|
"[Step 12] complete incomplete triples: " +
|
@@ -1061,7 +1085,7 @@ module RDF::RDFa
|
|
1061
1085
|
|
1062
1086
|
element.children.each do |child|
|
1063
1087
|
# recurse only if it's an element
|
1064
|
-
traverse(child, new_ec) if child.
|
1088
|
+
traverse(child, new_ec) if child.element?
|
1065
1089
|
end
|
1066
1090
|
|
1067
1091
|
# Step 14: after traversing through child elements, for each list associated with
|