the-experimenters-rdf-rdfxml 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,16 @@
1
+ require 'nokogiri'
2
+ class Nokogiri::XML::Node
3
+ # URI of namespace + node_name
4
+ def uri
5
+ ns = self.namespace ? self.namespace.href : RDF::XML.to_s
6
+ RDF::URI.intern(ns + self.node_name)
7
+ end
8
+
9
+ def display_path
10
+ @display_path ||= case self
11
+ when Nokogiri::XML::Document then ""
12
+ when Nokogiri::XML::Element then parent ? "#{parent.display_path}/#{name}" : name
13
+ when Nokogiri::XML::Attr then "#{parent.display_path}@#{name}"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,646 @@
1
+ require 'nokogiri' # FIXME: Implement using different modules as in RDF::TriX
2
+
3
+ module RDF::RDFXML
4
+ ##
5
+ # An RDF/XML parser in Ruby
6
+ #
7
+ # Based on RDF/XML Syntax Specification: http://www.w3.org/TR/REC-rdf-syntax/
8
+ #
9
+ # @author [Gregg Kellogg](http://kellogg-assoc.com/)
10
+ class Reader < RDF::Reader
11
+ format Format
12
+
13
+ CORE_SYNTAX_TERMS = %w(RDF ID about parseType resource nodeID datatype).map {|n| "http://www.w3.org/1999/02/22-rdf-syntax-ns##{n}"}
14
+ OLD_TERMS = %w(aboutEach aboutEachPrefix bagID).map {|n| "http://www.w3.org/1999/02/22-rdf-syntax-ns##{n}"}
15
+
16
+ # The Recursive Baggage
17
+ class EvaluationContext # :nodoc:
18
+ attr_reader :base
19
+ attr :subject, true
20
+ attr :uri_mappings, true
21
+ attr :language, true
22
+ attr :graph, true
23
+ attr :li_counter, true
24
+
25
+ def initialize(base, element, graph, &cb)
26
+ # Initialize the evaluation context, [5.1]
27
+ self.base = RDF::URI.intern(base)
28
+ @uri_mappings = {}
29
+ @language = nil
30
+ @graph = graph
31
+ @li_counter = 0
32
+
33
+ extract_from_element(element, &cb) if element
34
+ end
35
+
36
+ # Clone existing evaluation context adding information from element
37
+ def clone(element, options = {}, &cb)
38
+ new_ec = EvaluationContext.new(@base, nil, @graph)
39
+ new_ec.uri_mappings = self.uri_mappings.clone
40
+ new_ec.language = self.language
41
+
42
+ new_ec.extract_from_element(element, &cb) if element
43
+
44
+ options.each_pair {|k, v| new_ec.send("#{k}=", v)}
45
+ new_ec
46
+ end
47
+
48
+ # Extract Evaluation Context from an element by looking at ancestors recurively
49
+ def extract_from_ancestors(el, &cb)
50
+ ancestors = el.ancestors
51
+ while ancestors.length > 0
52
+ a = ancestors.pop
53
+ next unless a.element?
54
+ extract_from_element(a, &cb)
55
+ end
56
+ extract_from_element(el, &cb)
57
+ end
58
+
59
+ # Extract Evaluation Context from an element
60
+ def extract_from_element(el, &cb)
61
+ b = el.attribute_with_ns("base", RDF::XML.to_s)
62
+ b = nil if b.respond_to?(:null?) && b.null? # to ensure FFI Pointer compatibility
63
+
64
+ lang = el.attribute_with_ns("lang", RDF::XML.to_s)
65
+ lang = nil if lang.respond_to?(:null?) && lang.null? # to make FFI Pointer compatibility
66
+
67
+ self.base = self.base.join(b) if b
68
+ self.language = lang if lang
69
+ self.uri_mappings.merge!(extract_mappings(el, &cb))
70
+ end
71
+
72
+ # Extract the XMLNS mappings from an element
73
+ def extract_mappings(element, &cb)
74
+ mappings = {}
75
+
76
+ # look for xmlns
77
+ element.namespaces.each do |attr_name,attr_value|
78
+ abbr, prefix = attr_name.to_s.split(":")
79
+ if abbr == "xmlns"
80
+ attr_value = self.base.to_s + attr_value if attr_value.match(/^\#/)
81
+ mappings[prefix] = attr_value
82
+ cb.call(prefix, attr_value) if block_given?
83
+ end
84
+ end
85
+ mappings
86
+ end
87
+
88
+ # Produce the next list entry for this context
89
+ def li_next
90
+ @li_counter += 1
91
+ predicate = RDF["_#{@li_counter}"]
92
+ end
93
+
94
+ # Set XML base. Ignore any fragment
95
+ def base=(b)
96
+ base = Addressable::URI.parse(b)
97
+ base.fragment = nil
98
+ @base = RDF::URI.intern(base)
99
+ end
100
+
101
+ def inspect
102
+ v = %w(base subject language).map {|a| "#{a}='#{self.send(a).nil? ? 'nil' : self.send(a)}'"}
103
+ v << "uri_mappings[#{uri_mappings.keys.length}]"
104
+ v.join(",")
105
+ end
106
+ end
107
+
108
+ ##
109
+ # Initializes the RDF/XML reader instance.
110
+ #
111
+ # @param [Nokogiri::XML::Document, IO, File, String] input
112
+ # the input stream to read
113
+ # @param [Hash{Symbol => Object}] options
114
+ # any additional options
115
+ # @option options [Encoding] :encoding (Encoding::UTF_8)
116
+ # the encoding of the input stream (Ruby 1.9+)
117
+ # @option options [Boolean] :validate (false)
118
+ # whether to validate the parsed statements and values
119
+ # @option options [Boolean] :canonicalize (false)
120
+ # whether to canonicalize parsed literals
121
+ # @option options [Boolean] :intern (true)
122
+ # whether to intern all parsed URIs
123
+ # @option options [Hash] :prefixes (Hash.new)
124
+ # the prefix mappings to use (not supported by all readers)
125
+ # @option options [#to_s] :base_uri (nil)
126
+ # the base URI to use when resolving relative URIs
127
+ # @option options [Array] :debug
128
+ # Array to place debug messages
129
+ # @return [reader]
130
+ # @yield [reader] `self`
131
+ # @yieldparam [RDF::Reader] reader
132
+ # @yieldreturn [void] ignored
133
+ # @raise [Error]:: Raises RDF::ReaderError if _validate_
134
+ def initialize(input = $stdin, options = {}, &block)
135
+ super do
136
+ @debug = options[:debug]
137
+ @base_uri = uri(options[:base_uri]) if options[:base_uri]
138
+
139
+ @doc = case input
140
+ when Nokogiri::XML::Document then input
141
+ else Nokogiri::XML.parse(input, @base_uri.to_s)
142
+ end
143
+
144
+ raise RDF::ReaderError, "Synax errors:\n#{@doc.errors}" if !@doc.errors.empty? && validate?
145
+ raise RDF::ReaderError, "Empty document" if (@doc.nil? || @doc.root.nil?) && validate?
146
+
147
+ block.call(self) if block_given?
148
+ end
149
+ end
150
+
151
+ # No need to rewind, as parsing is done in initialize
152
+ def rewind; end
153
+
154
+ # Document closed when read in initialize
155
+ def close; end
156
+
157
+ ##
158
+ # Iterates the given block for each RDF statement in the input.
159
+ #
160
+ # @yield [statement]
161
+ # @yieldparam [RDF::Statement] statement
162
+ # @return [void]
163
+ def each_statement(&block)
164
+ # Block called from add_statement
165
+ @callback = block
166
+
167
+ root = @doc.root
168
+
169
+ add_debug(root, "base_uri: #{@base_uri || 'nil'}")
170
+
171
+ rdf_nodes = root.xpath("//rdf:RDF", "rdf" => RDF.to_uri.to_s)
172
+ if rdf_nodes.length == 0
173
+ # If none found, root element may be processed as an RDF Node
174
+
175
+ ec = EvaluationContext.new(@base_uri, root, @graph) do |prefix, value|
176
+ prefix(prefix, value)
177
+ end
178
+
179
+ nodeElement(root, ec)
180
+ else
181
+ rdf_nodes.each do |node|
182
+ # XXX Skip this element if it's contained within another rdf:RDF element
183
+
184
+ # Extract base, lang and namespaces from parents to create proper evaluation context
185
+ ec = EvaluationContext.new(@base_uri, nil, @graph) do |prefix, value|
186
+ prefix(prefix, value)
187
+ end
188
+ ec.extract_from_ancestors(node)
189
+ node.children.each {|el|
190
+ next unless el.elem?
191
+ new_ec = ec.clone(el) do |prefix, value|
192
+ prefix(prefix, value)
193
+ end
194
+ nodeElement(el, new_ec)
195
+ }
196
+ end
197
+ end
198
+ end
199
+
200
+ ##
201
+ # Iterates the given block for each RDF triple in the input.
202
+ #
203
+ # @yield [subject, predicate, object]
204
+ # @yieldparam [RDF::Resource] subject
205
+ # @yieldparam [RDF::URI] predicate
206
+ # @yieldparam [RDF::Value] object
207
+ # @return [void]
208
+ def each_triple(&block)
209
+ each_statement do |statement|
210
+ block.call(*statement.to_triple)
211
+ end
212
+ end
213
+
214
+ private
215
+
216
+ # Keep track of allocated BNodes
217
+ def bnode(value = nil)
218
+ @bnode_cache ||= {}
219
+ @bnode_cache[value.to_s] ||= RDF::Node.new(value)
220
+ end
221
+
222
+ # Figure out the document path, if it is a Nokogiri::XML::Element or Attribute
223
+ def node_path(node)
224
+ case node
225
+ when Nokogiri::XML::Node then node.display_path
226
+ else node.to_s
227
+ end
228
+ end
229
+
230
+ # Add debug event to debug array, if specified
231
+ #
232
+ # @param [XML Node, any] node:: XML Node or string for showing context
233
+ # @param [String] message::
234
+ def add_debug(node, message)
235
+ puts "#{node_path(node)}: #{message}" if ::RDF::RDFXML::debug?
236
+ @debug << "#{node_path(node)}: #{message}" if @debug.is_a?(Array)
237
+ end
238
+
239
+ # add a statement, object can be literal or URI or bnode
240
+ #
241
+ # @param [Nokogiri::XML::Node, any] node:: XML Node or string for showing context
242
+ # @param [URI, BNode] subject:: the subject of the statement
243
+ # @param [URI] predicate:: the predicate of the statement
244
+ # @param [URI, BNode, Literal] object:: the object of the statement
245
+ # @return [Statement]:: Added statement
246
+ # @raise [RDF::ReaderError]:: Checks parameter types and raises if they are incorrect if validating.
247
+ def add_triple(node, subject, predicate, object)
248
+ statement = RDF::Statement.new(subject, predicate, object)
249
+ add_debug(node, "statement: #{statement}")
250
+ @callback.call(statement)
251
+ end
252
+
253
+ # XML nodeElement production
254
+ #
255
+ # @param [XML Element] el:: XMl Element to parse
256
+ # @param [EvaluationContext] ec:: Evaluation context
257
+ # @return [RDF::URI] subject:: The subject found for the node
258
+ # @raise [RDF::ReaderError]:: Raises Exception if validating
259
+ def nodeElement(el, ec)
260
+ # subject
261
+ subject = ec.subject || parse_subject(el, ec)
262
+
263
+ add_debug(el, "nodeElement, ec: #{ec.inspect}")
264
+ add_debug(el, "nodeElement, el: #{el.uri}")
265
+ add_debug(el, "nodeElement, subject: #{subject.nil? ? 'nil' : subject.to_s}")
266
+
267
+ unless el.uri.to_s == RDF.Description.to_s
268
+ add_triple(el, subject, RDF.type, el.uri)
269
+ end
270
+
271
+ # produce triples for attributes
272
+ el.attribute_nodes.each do |attr|
273
+ add_debug(el, "propertyAttr: #{attr.uri}='#{attr.value}'")
274
+ if attr.uri.to_s == RDF.type.to_s
275
+ # If there is an attribute a in propertyAttr with a.URI == rdf:type
276
+ # then u:=uri(identifier:=resolve(a.string-value))
277
+ # and the following triple is added to the graph:
278
+ u = ec.base.join(attr.value)
279
+ add_triple(attr, subject, RDF.type, u)
280
+ elsif is_propertyAttr?(attr)
281
+ # Attributes not RDF.type
282
+ predicate = attr.uri
283
+ lit = RDF::Literal.new(attr.value, :language => ec.language, :validate => validate?, :canonicalize => canonicalize?)
284
+ add_triple(attr, subject, predicate, lit)
285
+ end
286
+ end
287
+
288
+ # Handle the propertyEltList children events in document order
289
+ li_counter = 0 # this will increase for each li we iterate through
290
+ el.children.each do |child|
291
+ next unless child.elem?
292
+ child_ec = ec.clone(child) do |prefix, value|
293
+ prefix(prefix, value)
294
+ end
295
+ predicate = child.uri
296
+ add_debug(child, "propertyElt, predicate: #{predicate}")
297
+ propertyElementURI_check(child)
298
+
299
+ # Determine the content type of this property element
300
+ text_nodes = child.children.select {|e| e.text? && !e.blank?}
301
+ element_nodes = child.children.select {|c| c.element? }
302
+ add_debug(child, "#{text_nodes.length} text nodes, #{element_nodes.length} element nodes")
303
+ if element_nodes.length > 1
304
+ element_nodes.each do |node|
305
+ add_debug(child, " node: #{node.to_s}")
306
+ end
307
+ end
308
+
309
+ # List expansion
310
+ predicate = ec.li_next if predicate == RDF.li
311
+
312
+ # Productions based on set of attributes
313
+
314
+ # All remaining reserved XML Names (See Name in XML 1.0) are now removed from the set.
315
+ # These are, all attribute information items in the set with property [prefix] beginning with xml
316
+ # (case independent comparison) and all attribute information items with [prefix] property having
317
+ # no value and which have [local name] beginning with xml (case independent comparison) are removed.
318
+ # Note that the [base URI] accessor is computed by XML Base before any xml:base attribute information item
319
+ # is deleted.
320
+ attrs = {}
321
+ id = datatype = parseType = resourceAttr = nodeID = nil
322
+
323
+ child.attribute_nodes.each do |attr|
324
+ if attr.namespace.to_s.empty?
325
+ # The support for a limited set of non-namespaced names is REQUIRED and intended to allow
326
+ # RDF/XML documents specified in [RDF-MS] to remain valid;
327
+ # new documents SHOULD NOT use these unqualified attributes and applications
328
+ # MAY choose to warn when the unqualified form is seen in a document.
329
+ add_debug(el, "Unqualified attribute '#{attr}'")
330
+ #attrs[attr.to_s] = attr.value unless attr.to_s.match?(/^xml/)
331
+ elsif attr.namespace.href == RDF::XML.to_s
332
+ # No production. Lang and base elements already extracted
333
+ elsif attr.namespace.href == RDF.to_uri.to_s
334
+ case attr.name
335
+ when "ID" then id = attr.value
336
+ when "datatype" then datatype = attr.value
337
+ when "parseType" then parseType = attr.value
338
+ when "resource" then resourceAttr = attr.value
339
+ when "nodeID" then nodeID = attr.value
340
+ else attrs[attr] = attr.value
341
+ end
342
+ else
343
+ attrs[attr] = attr.value
344
+ end
345
+ end
346
+
347
+ if nodeID && resourceAttr
348
+ add_debug(el, "Cannot have rdf:nodeID and rdf:resource.")
349
+ raise RDF::ReaderError.new("Cannot have rdf:nodeID and rdf:resource.") if validate?
350
+ end
351
+
352
+ # Apply character transformations
353
+ id = id_check(el, RDF::NTriples.unescape(id), nil) if id
354
+ resourceAttr = RDF::NTriples.unescape(resourceAttr) if resourceAttr
355
+ nodeID = nodeID_check(el, RDF::NTriples.unescape(nodeID)) if nodeID
356
+
357
+ add_debug(child, "attrs: #{attrs.inspect}")
358
+ add_debug(child, "datatype: #{datatype}") if datatype
359
+ add_debug(child, "parseType: #{parseType}") if parseType
360
+ add_debug(child, "resource: #{resourceAttr}") if resourceAttr
361
+ add_debug(child, "nodeID: #{nodeID}") if nodeID
362
+ add_debug(child, "id: #{id}") if id
363
+
364
+ if attrs.empty? && datatype.nil? && parseType.nil? && element_nodes.length == 1
365
+ # Production resourcePropertyElt
366
+
367
+ new_ec = child_ec.clone(nil) do |prefix, value|
368
+ prefix(prefix, value)
369
+ end
370
+ new_node_element = element_nodes.first
371
+ add_debug(child, "resourcePropertyElt: #{node_path(new_node_element)}")
372
+ new_subject = nodeElement(new_node_element, new_ec)
373
+ add_triple(child, subject, predicate, new_subject)
374
+ elsif attrs.empty? && parseType.nil? && element_nodes.length == 0 && text_nodes.length > 0
375
+ # Production literalPropertyElt
376
+ add_debug(child, "literalPropertyElt")
377
+
378
+ literal_opts = {:validate => validate?, :canonicalize => canonicalize?}
379
+ if datatype
380
+ literal_opts[:datatype] = uri(datatype)
381
+ else
382
+ literal_opts[:language] = child_ec.language
383
+ end
384
+ literal = RDF::Literal.new(child.inner_html, literal_opts)
385
+ add_triple(child, subject, predicate, literal)
386
+ reify(id, child, subject, predicate, literal, ec) if id
387
+ elsif parseType == "Resource"
388
+ # Production parseTypeResourcePropertyElt
389
+ add_debug(child, "parseTypeResourcePropertyElt")
390
+
391
+ unless attrs.empty?
392
+ warn = "Resource Property with extra attributes: '#{attrs.inspect}'"
393
+ add_debug(child, warn)
394
+ raise RDF::ReaderError.new(warn) if validate?
395
+ end
396
+
397
+ # For element e with possibly empty element content c.
398
+ n = RDF::Node.new
399
+ add_triple(child, subject, predicate, n)
400
+
401
+ # Reification
402
+ reify(id, child, subject, predicate, n, child_ec) if id
403
+
404
+ # If the element content c is not empty, then use event n to create a new sequence of events as follows:
405
+ #
406
+ # start-element(URI := rdf:Description,
407
+ # subject := n,
408
+ # attributes := set())
409
+ # c
410
+ # end-element()
411
+ add_debug(child, "compose new sequence with rdf:Description")
412
+ node = child.clone
413
+ pt_attr = node.attribute("parseType")
414
+ node.namespace = pt_attr.namespace
415
+ node.attributes.keys.each {|a| node.remove_attribute(a)}
416
+ node.node_name = "Description"
417
+ new_ec = child_ec.clone(nil, :subject => n) do |prefix, value|
418
+ prefix(prefix, value)
419
+ end
420
+ nodeElement(node, new_ec)
421
+ elsif parseType == "Collection"
422
+ # Production parseTypeCollectionPropertyElt
423
+ add_debug(child, "parseTypeCollectionPropertyElt")
424
+
425
+ unless attrs.empty?
426
+ warn = "Resource Property with extra attributes: '#{attrs.inspect}'"
427
+ add_debug(child, warn)
428
+ raise RDF::ReaderError.new(warn) if validate?
429
+ end
430
+
431
+ # For element event e with possibly empty nodeElementList l. Set s:=list().
432
+ # For each element event f in l, n := bnodeid(identifier := generated-blank-node-id()) and append n to s to give a sequence of events.
433
+ s = element_nodes.map { RDF::Node.new }
434
+ n = s.first || RDF["nil"]
435
+ add_triple(child, subject, predicate, n)
436
+ reify(id, child, subject, predicate, n, child_ec) if id
437
+
438
+ # Add first/rest entries for all list elements
439
+ s.each_index do |i|
440
+ n = s[i]
441
+ o = s[i+1]
442
+ f = element_nodes[i]
443
+
444
+ new_ec = child_ec.clone(nil) do |prefix, value|
445
+ prefix(prefix, value)
446
+ end
447
+ object = nodeElement(f, new_ec)
448
+ add_triple(child, n, RDF.first, object)
449
+ add_triple(child, n, RDF.rest, o ? o : RDF.nil)
450
+ end
451
+ elsif parseType # Literal or Other
452
+ # Production parseTypeResourcePropertyElt
453
+ add_debug(child, parseType == "Literal" ? "parseTypeResourcePropertyElt" : "parseTypeOtherPropertyElt (#{parseType})")
454
+
455
+ unless attrs.empty?
456
+ warn = "Resource Property with extra attributes: '#{attrs.inspect}'"
457
+ add_debug(child, warn)
458
+ raise RDF::ReaderError.new(warn) if validate?
459
+ end
460
+
461
+ if resourceAttr
462
+ warn = "illegal rdf:resource"
463
+ add_debug(child, warn)
464
+ raise RDF::ReaderError.new(warn) if validate?
465
+ end
466
+
467
+ object = RDF::Literal.new(child.children, :datatype => RDF.XMLLiteral, :namespaces => child_ec.uri_mappings, :language => ec.language)
468
+ add_triple(child, subject, predicate, object)
469
+ elsif text_nodes.length == 0 && element_nodes.length == 0
470
+ # Production emptyPropertyElt
471
+ add_debug(child, "emptyPropertyElt")
472
+
473
+ if attrs.empty? && resourceAttr.nil? && nodeID.nil?
474
+ literal = RDF::Literal.new("", :language => ec.language)
475
+ add_triple(child, subject, predicate, literal)
476
+
477
+ # Reification
478
+ reify(id, child, subject, predicate, literal, child_ec) if id
479
+ else
480
+ if resourceAttr
481
+ resource = ec.base.join(resourceAttr)
482
+ elsif nodeID
483
+ resource = bnode(nodeID)
484
+ else
485
+ resource = RDF::Node.new
486
+ end
487
+
488
+ # produce triples for attributes
489
+ attrs.each_pair do |attr, val|
490
+ add_debug(el, "attr: #{attr.name}='#{val}'")
491
+
492
+ if attr.uri.to_s == RDF.type.to_s
493
+ add_triple(child, resource, RDF.type, val)
494
+ else
495
+ # Check for illegal attributes
496
+ next unless is_propertyAttr?(attr)
497
+
498
+ # Attributes not in RDF.type
499
+ lit = RDF::Literal.new(val, :language => child_ec.language)
500
+ add_triple(child, resource, attr.uri, lit)
501
+ end
502
+ end
503
+ add_triple(child, subject, predicate, resource)
504
+
505
+ # Reification
506
+ reify(id, child, subject, predicate, resource, child_ec) if id
507
+ end
508
+ end
509
+ end
510
+
511
+ # Return subject
512
+ subject
513
+ end
514
+
515
+ private
516
+ # Reify subject, predicate, and object given the EvaluationContext (ec) and current XMl element (el)
517
+ def reify(id, el, subject, predicate, object, ec)
518
+ add_debug(el, "reify, id: #{id}")
519
+ rsubject = ec.base.join("#" + id)
520
+ add_triple(el, rsubject, RDF.subject, subject)
521
+ add_triple(el, rsubject, RDF.predicate, predicate)
522
+ add_triple(el, rsubject, RDF.object, object)
523
+ add_triple(el, rsubject, RDF.type, RDF["Statement"])
524
+ end
525
+
526
+ # Figure out the subject from the element.
527
+ def parse_subject(el, ec)
528
+ old_property_check(el)
529
+
530
+ nodeElementURI_check(el)
531
+ about = el.attribute("about")
532
+ id = el.attribute("ID")
533
+ nodeID = el.attribute("nodeID")
534
+
535
+ if nodeID && about
536
+ add_debug(el, "Cannot have rdf:nodeID and rdf:about.")
537
+ raise RDF::ReaderError.new("Cannot have rdf:nodeID and rdf:about.") if validate?
538
+ elsif nodeID && id
539
+ add_debug(el, "Cannot have rdf:nodeID and rdf:ID.")
540
+ raise RDF::ReaderError.new("Cannot have rdf:nodeID and rdf:ID.") if validate?
541
+ end
542
+
543
+ case
544
+ when id
545
+ add_debug(el, "parse_subject, id: '#{RDF::NTriples.unescape(id.value)}'")
546
+ id_check(el, RDF::NTriples.unescape(id.value), ec.base) # Returns URI
547
+ when nodeID
548
+ # The value of rdf:nodeID must match the XML Name production
549
+ nodeID = nodeID_check(el, RDF::NTriples.unescape(nodeID.value))
550
+ add_debug(el, "parse_subject, nodeID: '#{nodeID}")
551
+ bnode(nodeID)
552
+ when about
553
+ about = RDF::NTriples.unescape(about.value)
554
+ add_debug(el, "parse_subject, about: '#{about}'")
555
+ ec.base.join(about)
556
+ else
557
+ add_debug(el, "parse_subject, BNode")
558
+ RDF::Node.new
559
+ end
560
+ end
561
+
562
+ # ID attribute must be an NCName
563
+ def id_check(el, id, base)
564
+ unless NC_REGEXP.match(id)
565
+ warn = "ID addtribute '#{id}' must be a NCName"
566
+ add_debug(el, warn)
567
+ raise RDF::ReaderError.new(warn) if validate?
568
+ end
569
+ # ID may only be specified once for the same URI
570
+ if base
571
+ uri = uri(base, "##{id}")
572
+ if prefix(id) && RDF::URI(prefix(id)) == uri
573
+ warn = "ID addtribute '#{id}' may only be defined once for the same URI"
574
+ add_debug(el, warn)
575
+ raise RDF::ReaderError.new(warn) if validate?
576
+ end
577
+
578
+ RDF::URI(prefix(id, uri))
579
+ # Returns URI, in this case
580
+ else
581
+ id
582
+ end
583
+ end
584
+
585
+ # nodeID must be an XML Name
586
+ # nodeID must pass Production rdf-id
587
+ def nodeID_check(el, nodeID)
588
+ if NC_REGEXP.match(nodeID)
589
+ nodeID
590
+ else
591
+ add_debug(el, "nodeID addtribute '#{nodeID}' must be an XML Name")
592
+ raise RDF::ReaderError.new("nodeID addtribute '#{nodeID}' must be a NCName") if validate?
593
+ nil
594
+ end
595
+ end
596
+
597
+ # Is this attribute a Property Attribute?
598
+ def is_propertyAttr?(attr)
599
+ if ([RDF.Description.to_s, RDF.li.to_s] + OLD_TERMS).include?(attr.uri.to_s)
600
+ warn = "Invalid use of rdf:#{attr.name}"
601
+ add_debug(attr, warn)
602
+ raise RDF::ReaderError.new(warn) if validate?
603
+ return false
604
+ end
605
+ !CORE_SYNTAX_TERMS.include?(attr.uri.to_s) && attr.namespace && attr.namespace.href != RDF::XML.to_s
606
+ end
607
+
608
+ # Check Node Element name
609
+ def nodeElementURI_check(el)
610
+ if (CORE_SYNTAX_TERMS + [RDF.li.to_s] + OLD_TERMS).include?(el.uri.to_s)
611
+ warn = "Invalid use of rdf:#{el.name}"
612
+ add_debug(el, warn)
613
+ raise RDF::ReaderError.new(warn) if validate?
614
+ end
615
+ end
616
+
617
+ # Check Property Element name
618
+ def propertyElementURI_check(el)
619
+ if (CORE_SYNTAX_TERMS + [RDF.Description.to_s] + OLD_TERMS).include?(el.uri.to_s)
620
+ warn = "Invalid use of rdf:#{el.name}"
621
+ add_debug(el, warn)
622
+ raise RDF::ReaderError.new(warn) if validate?
623
+ end
624
+ end
625
+
626
+ # Check for the use of an obsolete RDF property
627
+ def old_property_check(el)
628
+ el.attribute_nodes.each do |attr|
629
+ if OLD_TERMS.include?(attr.uri.to_s)
630
+ add_debug(el, "Obsolete attribute '#{attr.uri}'")
631
+ raise RDF::ReaderError.new("Obsolete attribute '#{attr.uri}'") if validate?
632
+ end
633
+ end
634
+ end
635
+
636
+ def uri(value, append = nil)
637
+ value = RDF::URI.new(value)
638
+ value = value.join(append) if append
639
+ value.validate! if validate?
640
+ value.canonicalize! if canonicalize?
641
+ value = RDF::URI.intern(value) if intern?
642
+ value
643
+ end
644
+
645
+ end
646
+ end