rdf-rdfxml 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +20 -0
- data/VERSION +1 -1
- data/lib/rdf/rdfxml/format.rb +2 -2
- data/lib/rdf/rdfxml/patches/graph_properties.rb +34 -0
- data/lib/rdf/rdfxml/patches/literal_hacks.rb +66 -0
- data/lib/rdf/rdfxml/patches/qname_hacks.rb +57 -0
- data/lib/rdf/rdfxml/patches/seq.rb +34 -0
- data/lib/rdf/rdfxml/patches/uri_hacks.rb +19 -0
- data/lib/rdf/rdfxml/reader.rb +10 -7
- data/lib/rdf/rdfxml/writer.rb +215 -114
- data/lib/rdf/rdfxml.rb +4 -0
- data/rdf-rdfxml.gemspec +17 -4
- data/spec/format_spec.rb +1 -1
- data/spec/graph_spec.rb +74 -0
- data/spec/literal_spec.rb +86 -0
- data/spec/rdf_escape_spec.rb +36 -0
- data/spec/rdf_helper.rb +2 -0
- data/spec/reader_spec.rb +7 -3
- data/spec/uri_spec.rb +61 -0
- data/spec/{xml_serializer_spec.rb → writer_spec.rb} +114 -110
- metadata +19 -6
data/History.txt
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
=== 0.0.3
|
2
|
+
* Added patches for the following:
|
3
|
+
* RDF::Graph#properties
|
4
|
+
* RDF::Graph#seq (Output rdf:Seq elements in order)
|
5
|
+
* RDF::Graph#type_of
|
6
|
+
* RDF::Literal.xmlliteral (Create literal and normalize XML)
|
7
|
+
* RDF::Literal#xmlliteral?
|
8
|
+
* RDF::Literal#anonymous? (missing from library)
|
9
|
+
* RDF::Literal#to_s (only one of @lang or ^^type, not both)
|
10
|
+
* RDF::URI#join (Don't add trailing '/')
|
11
|
+
* Reader fixes
|
12
|
+
* Writer complete
|
13
|
+
* Spec status
|
14
|
+
* Isomorphic XMLLiteral tests fail due to attribute order variation
|
15
|
+
* Reader parsing multi-line quite in NTriples test file fails due to lack of support in RDF::NTriples
|
16
|
+
* A couple of URI normalizations fail:
|
17
|
+
* should create <http://foo/> from <http://foo#> and ''
|
18
|
+
* should create <http://foo/bar> from <http://foo/bar#> and ''
|
19
|
+
* Writer test needs Turtle reader
|
20
|
+
|
1
21
|
=== 0.0.2
|
2
22
|
* Added specs from RdfContext
|
3
23
|
* Added array_hacks, nokogiri_hacks, and rdf_escape
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/lib/rdf/rdfxml/format.rb
CHANGED
@@ -3,8 +3,8 @@ module RDF::RDFXML
|
|
3
3
|
# RDFXML format specification.
|
4
4
|
#
|
5
5
|
# @example Obtaining an RDFXML format class
|
6
|
-
# RDF::Format.for(:rdf)
|
7
|
-
# RDF::Format.for(:
|
6
|
+
# RDF::Format.for(:rdf) # RDF::RDFXML::Format
|
7
|
+
# RDF::Format.for(:rdfxml) # RDF::RDFXML::Format
|
8
8
|
# RDF::Format.for("etc/foaf.xml")
|
9
9
|
# RDF::Format.for(:file_name => "etc/foaf.xml")
|
10
10
|
# RDF::Format.for(:file_extension => "xml")
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module RDF
|
2
|
+
class Graph
|
3
|
+
# Resource properties
|
4
|
+
#
|
5
|
+
# Properties arranged as a hash with the predicate Term as index to an array of resources or literals
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
# graph.load(':foo a :bar; rdfs:label "An example" .', "http://example.com/")
|
9
|
+
# graph.resources(URI.new("http://example.com/subject")) =>
|
10
|
+
# {
|
11
|
+
# "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" => [<http://example.com/#bar>],
|
12
|
+
# "http://example.com/#label" => ["An example"]
|
13
|
+
# }
|
14
|
+
def properties(subject, recalc = false)
|
15
|
+
@properties ||= {}
|
16
|
+
@properties.delete(subject.to_s) if recalc
|
17
|
+
@properties[subject.to_s] ||= begin
|
18
|
+
hash = Hash.new
|
19
|
+
self.query(:subject => subject) do |statement|
|
20
|
+
pred = statement.predicate.to_s
|
21
|
+
|
22
|
+
hash[pred] ||= []
|
23
|
+
hash[pred] << statement.object
|
24
|
+
end
|
25
|
+
hash
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get type(s) of subject, returns a list of symbols
|
30
|
+
def type_of(subject)
|
31
|
+
query(:subject => subject, :predicate => RDF.type).map {|st| st.object}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module RDF
|
2
|
+
class Literal
|
3
|
+
# Support for XML Literals
|
4
|
+
# Is this an XMLLiteral?
|
5
|
+
def xmlliteral?
|
6
|
+
datatype == RDF['XMLLiteral']
|
7
|
+
end
|
8
|
+
|
9
|
+
def anonymous?; false; end unless respond_to?(:anonymous?)
|
10
|
+
|
11
|
+
##
|
12
|
+
# Returns a string representation of this literal.
|
13
|
+
#
|
14
|
+
# @return [String]
|
15
|
+
def to_s
|
16
|
+
quoted = value # FIXME
|
17
|
+
output = "\"#{quoted}\""
|
18
|
+
output << "@#{language}" if has_language? && !has_datatype?
|
19
|
+
output << "^^<#{datatype}>" if has_datatype?
|
20
|
+
output
|
21
|
+
end
|
22
|
+
|
23
|
+
# Normalize an XML Literal, by adding necessary namespaces.
|
24
|
+
# This should be done as part of initialize
|
25
|
+
#
|
26
|
+
# namespaces is a hash of prefix => URIs
|
27
|
+
def self.xmlliteral(contents, options = {})
|
28
|
+
options[:namespaces] ||= {}
|
29
|
+
l = new("", :datatype => RDF["XMLLiteral"])
|
30
|
+
|
31
|
+
if contents.is_a?(String)
|
32
|
+
ns_hash = {}
|
33
|
+
options[:namespaces].each_pair do |prefix, uri|
|
34
|
+
attr = prefix.to_s.empty? ? "xmlns" : "xmlns:#{prefix}"
|
35
|
+
ns_hash[attr] = uri.to_s
|
36
|
+
end
|
37
|
+
ns_strs = []
|
38
|
+
ns_hash.each_pair {|a, u| ns_strs << "#{a}=\"#{u}\""}
|
39
|
+
|
40
|
+
# Add inherited namespaces to created root element so that they're inherited to sub-elements
|
41
|
+
contents = Nokogiri::XML::Document.parse("<foo #{ns_strs.join(" ")}>#{contents}</foo>").root.children
|
42
|
+
end
|
43
|
+
|
44
|
+
# Add already mapped namespaces and language
|
45
|
+
l.value = contents.map do |c|
|
46
|
+
if c.is_a?(Nokogiri::XML::Element)
|
47
|
+
c = Nokogiri::XML.parse(c.dup.to_s).root
|
48
|
+
# Gather namespaces from self and decendant nodes
|
49
|
+
c.traverse do |n|
|
50
|
+
ns = n.namespace
|
51
|
+
next unless ns
|
52
|
+
prefix = ns.prefix ? "xmlns:#{ns.prefix}" : "xmlns"
|
53
|
+
c[prefix] = ns.href.to_s unless c.namespaces[prefix]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Add lanuage
|
57
|
+
if options[:language] && c["lang"].to_s.empty?
|
58
|
+
c["xml:lang"] = options[:language]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
c.to_html(:save_with => Nokogiri::XML::Node::SaveOptions::NO_EMPTY_TAGS)
|
62
|
+
end.join("")
|
63
|
+
l
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module RDF
|
2
|
+
class URI
|
3
|
+
#unless defined?(:vocab)
|
4
|
+
def vocab
|
5
|
+
# Find vocabulary if not assigned
|
6
|
+
return @vocab if @vocab
|
7
|
+
|
8
|
+
Vocabulary.each do |vocab|
|
9
|
+
return self.vocab = vocab if to_s.index(vocab.to_uri.to_s) == 0
|
10
|
+
end
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def vocab=(value)
|
15
|
+
raise "Vocab #{value.inspect} is not a Vocabulary!" if value.is_a?(Array)
|
16
|
+
@vocab = value
|
17
|
+
end
|
18
|
+
|
19
|
+
def qname
|
20
|
+
@qname ||= if vocab
|
21
|
+
raise "Vocab #{vocab.inspect} is not a Vocabulary!" if vocab.is_a?(Array)
|
22
|
+
vocab_name = vocab.__name__.to_s.split('::').last.downcase
|
23
|
+
local_name = to_s[vocab.to_uri.to_s.size..-1]
|
24
|
+
vocab_name && local_name && [vocab_name.to_sym, local_name.to_sym]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
#end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Vocabulary
|
31
|
+
def self.[](property)
|
32
|
+
@prop_uri ||= {}
|
33
|
+
@prop_uri[property] ||= begin
|
34
|
+
uri = RDF::URI.new([to_s, property.to_s].join(''))
|
35
|
+
uri.vocab = self
|
36
|
+
uri
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def [](property)
|
41
|
+
@prop_uri ||= {}
|
42
|
+
@prop_uri[property] ||= begin
|
43
|
+
uri = RDF::URI.new([to_s, property.to_s].join(''))
|
44
|
+
uri.vocab = self
|
45
|
+
uri
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_uri
|
50
|
+
@uri ||= begin
|
51
|
+
uri = RDF::URI.new(to_s)
|
52
|
+
uri.vocab = self
|
53
|
+
uri
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rdf/rdfxml/patches/graph_properties'
|
2
|
+
module RDF
|
3
|
+
class Graph
|
4
|
+
# Returns ordered rdf:_n objects or rdf:first, rdf:rest for a given subject
|
5
|
+
def seq(subject)
|
6
|
+
props = properties(subject)
|
7
|
+
rdf_type = (props[RDF.type.to_s] || []).map {|t| t.to_s}
|
8
|
+
|
9
|
+
#puts "seq; #{rdf_type} #{rdf_type - [RDF_NS.Seq, RDF_NS.Bag, RDF_NS.Alt]}"
|
10
|
+
if !(rdf_type - [RDF.Seq, RDF.Bag, RDF.Alt]).empty?
|
11
|
+
props.keys.select {|k| k.match(/#{RDF.to_s}_(\d)$/)}.
|
12
|
+
sort_by {|i| i.sub(RDF._.to_s, "").to_i}.
|
13
|
+
map {|key| props[key]}.
|
14
|
+
flatten
|
15
|
+
elsif !self.query(:subject => subject, :predicate => RDF.first).empty?
|
16
|
+
# N3-style first/rest chain
|
17
|
+
list = []
|
18
|
+
while subject != RDF_NS.nil
|
19
|
+
props = properties(subject)
|
20
|
+
f = props[RDF.first.to_s]
|
21
|
+
if f.to_s.empty? || f.first == RDF.nil
|
22
|
+
subject = RDF.nil
|
23
|
+
else
|
24
|
+
list += f
|
25
|
+
subject = props[RDF.rest.to_s].first
|
26
|
+
end
|
27
|
+
end
|
28
|
+
list
|
29
|
+
else
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RDF
|
2
|
+
class URI
|
3
|
+
##
|
4
|
+
# Joins several URIs together.
|
5
|
+
#
|
6
|
+
# @param [Array<String, URI, #to_str>] uris
|
7
|
+
# @return [URI]
|
8
|
+
#
|
9
|
+
# GK -- don't add a "/" at the end of URIs, due to rdfcore/xmlbase/test002.rdf
|
10
|
+
def join(*uris)
|
11
|
+
result = @uri
|
12
|
+
uris.each do |uri|
|
13
|
+
# result.path += '/' unless result.path.match(/[\#\/]$/) || uri.to_s[0..0] == "#"
|
14
|
+
result = result.join(uri)
|
15
|
+
end
|
16
|
+
self.class.new(result)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/rdf/rdfxml/reader.rb
CHANGED
@@ -24,8 +24,6 @@ module RDF::RDFXML
|
|
24
24
|
$},
|
25
25
|
Regexp::EXTENDED)
|
26
26
|
|
27
|
-
XML_LITERAL = RDF['XMLLiteral']
|
28
|
-
|
29
27
|
# The Recursive Baggage
|
30
28
|
class EvaluationContext # :nodoc:
|
31
29
|
attr_reader :base
|
@@ -42,7 +40,6 @@ module RDF::RDFXML
|
|
42
40
|
@language = nil
|
43
41
|
@graph = graph
|
44
42
|
@li_counter = 0
|
45
|
-
@uri_mappings = {}
|
46
43
|
|
47
44
|
extract_from_element(element) if element
|
48
45
|
end
|
@@ -128,7 +125,7 @@ module RDF::RDFXML
|
|
128
125
|
super do
|
129
126
|
@debug = options[:debug]
|
130
127
|
@strict = options[:strict]
|
131
|
-
@base_uri = RDF::URI.
|
128
|
+
@base_uri = RDF::URI.new(options[:base_uri])
|
132
129
|
|
133
130
|
@id_mapping = Hash.new
|
134
131
|
|
@@ -360,7 +357,13 @@ module RDF::RDFXML
|
|
360
357
|
# Production literalPropertyElt
|
361
358
|
add_debug(child, "literalPropertyElt")
|
362
359
|
|
363
|
-
|
360
|
+
literal_opts = {}
|
361
|
+
if datatype
|
362
|
+
literal_opts[:datatype] = datatype
|
363
|
+
else
|
364
|
+
literal_opts[:language] = child_ec.language
|
365
|
+
end
|
366
|
+
literal = RDF::Literal.new(child.inner_html, literal_opts)
|
364
367
|
add_triple(child, subject, predicate, literal)
|
365
368
|
reify(id, child, subject, predicate, literal, ec) if id
|
366
369
|
elsif parseType == "Resource"
|
@@ -439,7 +442,7 @@ module RDF::RDFXML
|
|
439
442
|
raise RDF::ReaderError.new(warn) if @strict
|
440
443
|
end
|
441
444
|
|
442
|
-
object = RDF::Literal.
|
445
|
+
object = RDF::Literal.xmlliteral(child.children, :namespaces => child_ec.uri_mappings)
|
443
446
|
add_triple(child, subject, predicate, object)
|
444
447
|
elsif text_nodes.length == 0 && element_nodes.length == 0
|
445
448
|
# Production emptyPropertyElt
|
@@ -472,7 +475,7 @@ module RDF::RDFXML
|
|
472
475
|
|
473
476
|
# Attributes not in RDF.type
|
474
477
|
lit = RDF::Literal.new(val, :language => child_ec.language)
|
475
|
-
add_triple(child, resource, attr.uri
|
478
|
+
add_triple(child, resource, attr.uri, lit)
|
476
479
|
end
|
477
480
|
end
|
478
481
|
add_triple(child, subject, predicate, resource)
|