rdf-rdfa 0.3.7 → 0.3.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|