rdf-n3 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +1 -0
- data/History.txt +9 -0
- data/README.rdoc +4 -2
- data/Rakefile +37 -2
- data/VERSION +1 -1
- data/example.rb +1 -1
- data/lib/rdf/n3.rb +12 -5
- data/lib/rdf/n3/format.rb +0 -1
- data/lib/rdf/n3/patches/array_hacks.rb +46 -124
- data/lib/rdf/n3/patches/graph_properties.rb +34 -0
- data/lib/rdf/n3/patches/literal_hacks.rb +23 -0
- data/lib/rdf/n3/patches/literal_normalization.rb +120 -0
- data/lib/rdf/n3/patches/qname_hacks.rb +57 -0
- data/lib/rdf/n3/patches/rdf_escape.rb +3 -3
- data/lib/rdf/n3/patches/seq.rb +34 -0
- data/lib/rdf/n3/patches/uri_hacks.rb +19 -0
- data/lib/rdf/n3/reader.rb +110 -68
- data/lib/rdf/n3/reader/n3_grammar.rb +3876 -0
- data/lib/rdf/n3/{vocabulary.rb → vocab.rb} +0 -0
- data/lib/rdf/n3/writer.rb +444 -0
- data/rdf-n3.gemspec +38 -15
- data/script/console +8 -0
- data/script/parse +49 -0
- data/spec/cwm_spec.rb +13 -5
- data/spec/format_spec.rb +21 -0
- data/spec/literal_spec.rb +382 -0
- data/spec/matchers.rb +101 -0
- data/spec/n3reader_spec.rb +253 -185
- data/spec/rdf_helper.rb +115 -89
- data/spec/spec_helper.rb +39 -0
- data/spec/swap_spec.rb +24 -10
- data/spec/swap_test/n3parser.yml +193 -0
- data/spec/swap_test/regression.yml +226 -0
- data/spec/turtle_spec.rb +23 -8
- data/spec/writer_spec.rb +250 -0
- metadata +80 -22
- data/spec/swap_helper.rb +0 -136
- data/spec/triple_spec.rb +0 -236
data/.yardopts
CHANGED
data/History.txt
CHANGED
@@ -1,2 +1,11 @@
|
|
1
|
+
=== 0.0.2
|
2
|
+
* N3 parsing and Turtle serialization substantially complete.
|
3
|
+
* A little more work needed on some tests and some lingering issues in RDF.rb to be resolved.
|
4
|
+
* Added script/console and script/parse
|
5
|
+
* Updates to reader to bring it in line with other readers. Implement uri() and ns() as helper functions for constructing URIs.
|
6
|
+
* Literal_normalization to override RDF::Literal.initialize and create Literal#valid?
|
7
|
+
* rdf_escape Literals when serializing via to_s
|
8
|
+
* Remove trailing "#" from URIs when normalizing.
|
9
|
+
|
1
10
|
=== 0.0.1
|
2
11
|
* First port from RdfContext version 0.5.4
|
data/README.rdoc
CHANGED
@@ -10,6 +10,8 @@ RDF::N3 is an Notation-3 (n3-rdf) parser for Ruby using the RDF.rb library suite
|
|
10
10
|
RDF::N3 parses Notation-3, Turtle and N-Triples into statements or triples. It also serializes to Turtle.
|
11
11
|
|
12
12
|
* Fully compliant N3-rdf parser (N3-rdf level)
|
13
|
+
* Also parses Turtle and N-Triples
|
14
|
+
* Turtle serializer
|
13
15
|
|
14
16
|
Install with 'gem install rdf-n3'
|
15
17
|
|
@@ -25,8 +27,8 @@ Instantiate a parser and parse source, specifying type and base-URL
|
|
25
27
|
end
|
26
28
|
|
27
29
|
== Dependencies
|
28
|
-
* [RDF.rb](http://rubygems.org/gems/rdf) (>= 0.
|
29
|
-
* [Treetop](http://rubygems.org/gems/treetop) (>= 1.4.0)
|
30
|
+
* [RDF.rb](http://rubygems.org/gems/rdf) (>= 0.2.0)
|
31
|
+
* [Treetop](http://rubygems.org/gems/treetop) (>= 1.4.0)
|
30
32
|
|
31
33
|
== Resources:
|
32
34
|
* Distiller[http://kellogg-assoc/distiller]
|
data/Rakefile
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
require 'yard'
|
2
3
|
|
3
4
|
begin
|
4
5
|
gem 'jeweler'
|
@@ -12,10 +13,13 @@ begin
|
|
12
13
|
gemspec.email = "gregg@kellogg-assoc.com"
|
13
14
|
gemspec.homepage = "http://github.com/gkellogg/rdf-rdfa"
|
14
15
|
gemspec.authors = ["Gregg Kellogg"]
|
15
|
-
gemspec.add_dependency('rdf', '>= 0.
|
16
|
+
gemspec.add_dependency('rdf', '>= 0.2.0')
|
17
|
+
gemspec.add_dependency('treetop', '>= 1.4.0')
|
16
18
|
gemspec.add_development_dependency('rspec')
|
17
19
|
gemspec.add_development_dependency('rdf-spec')
|
18
|
-
gemspec.add_development_dependency('
|
20
|
+
gemspec.add_development_dependency('rdf-rdfxml', '>= 0.2.0')
|
21
|
+
gemspec.add_development_dependency('rdf-isomorphic')
|
22
|
+
gemspec.add_development_dependency('yard')
|
19
23
|
gemspec.extra_rdoc_files = %w(README.rdoc History.txt AUTHORS)
|
20
24
|
end
|
21
25
|
Jeweler::GemcutterTasks.new
|
@@ -43,4 +47,35 @@ Spec::Rake::SpecTask.new("doc:spec") do |spec|
|
|
43
47
|
spec.spec_opts = ["--format", "html:doc/spec.html"]
|
44
48
|
end
|
45
49
|
|
50
|
+
YARD::Rake::YardocTask.new do |t|
|
51
|
+
t.files = %w(lib/**/*.rb README.rdoc History.txt AUTHORS) # optional
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "Generate test manifest yaml"
|
55
|
+
namespace :spec do
|
56
|
+
task :prepare do
|
57
|
+
$:.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
58
|
+
require 'rdf/rdfxml'
|
59
|
+
require 'rdf/n3'
|
60
|
+
require 'spec/rdf_helper'
|
61
|
+
require 'fileutils'
|
62
|
+
|
63
|
+
yaml = File.join(SWAP_DIR, "n3parser.yml")
|
64
|
+
FileUtils.rm_f(yaml)
|
65
|
+
RdfHelper::TestCase.to_yaml(SWAP_TEST, SWAP_DIR, yaml)
|
66
|
+
|
67
|
+
yaml = File.join(SWAP_DIR, "regression.yml")
|
68
|
+
FileUtils.rm_f(yaml)
|
69
|
+
RdfHelper::TestCase.to_yaml(CWM_TEST, SWAP_DIR, yaml)
|
70
|
+
|
71
|
+
yaml = File.join(TURTLE_DIR, "manifest.yml")
|
72
|
+
FileUtils.rm_f(yaml)
|
73
|
+
RdfHelper::TestCase.to_yaml(TURTLE_TEST, TURTLE_DIR, yaml)
|
74
|
+
|
75
|
+
yaml = File.join(TURTLE_DIR, "manifest-bad.yml")
|
76
|
+
FileUtils.rm_f(yaml)
|
77
|
+
RdfHelper::TestCase.to_yaml(TURTLE_TEST, TURTLE_DIR, yaml)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
46
81
|
task :default => :spec
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
data/example.rb
CHANGED
data/lib/rdf/n3.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
$:.unshift(File.
|
1
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..')))
|
2
2
|
require 'rdf'
|
3
3
|
|
4
4
|
module RDF
|
@@ -20,11 +20,18 @@ module RDF
|
|
20
20
|
#
|
21
21
|
# @author [Gregg Kellogg](http://kellogg-assoc.com/)
|
22
22
|
module N3
|
23
|
-
require 'n3/format'
|
24
|
-
require 'n3/vocab'
|
25
|
-
require 'n3/patches/array_hacks'
|
26
|
-
require 'n3/patches/
|
23
|
+
require 'rdf/n3/format'
|
24
|
+
require 'rdf/n3/vocab'
|
25
|
+
require 'rdf/n3/patches/array_hacks'
|
26
|
+
require 'rdf/n3/patches/literal_hacks'
|
27
|
+
require 'rdf/n3/patches/literal_normalization'
|
28
|
+
require 'rdf/n3/patches/graph_properties'
|
29
|
+
require 'rdf/n3/patches/qname_hacks'
|
30
|
+
require 'rdf/n3/patches/rdf_escape'
|
31
|
+
require 'rdf/n3/patches/seq'
|
32
|
+
require 'rdf/n3/patches/uri_hacks'
|
27
33
|
autoload :Reader, 'rdf/n3/reader'
|
28
34
|
autoload :VERSION, 'rdf/n3/version'
|
35
|
+
autoload :Writer, 'rdf/n3/writer'
|
29
36
|
end
|
30
37
|
end
|
data/lib/rdf/n3/format.rb
CHANGED
@@ -4,7 +4,6 @@ module RDF::N3
|
|
4
4
|
#
|
5
5
|
# @example Obtaining an RDFa format class
|
6
6
|
# RDF::Format.for(:n3) #=> RDF::N3::Format
|
7
|
-
# RDF::Format.for(:ttl) #=> RDF::N3::Format
|
8
7
|
# RDF::Format.for("etc/foaf.ttl")
|
9
8
|
# RDF::Format.for("etc/foaf.n3")
|
10
9
|
# RDF::Format.for(:file_name => "etc/foaf.ttl")
|
@@ -1,131 +1,53 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
"\x1" => '\u0001',
|
10
|
-
"\x2" => '\u0002',
|
11
|
-
"\x3" => '\u0003',
|
12
|
-
"\x4" => '\u0004',
|
13
|
-
"\x5" => '\u0005',
|
14
|
-
"\x6" => '\u0006',
|
15
|
-
"\x7" => '\u0007',
|
16
|
-
"\b" => '\b',
|
17
|
-
"\t" => '\t',
|
18
|
-
"\n" => '\n',
|
19
|
-
"\xb" => '\u000B',
|
20
|
-
"\f" => '\f',
|
21
|
-
"\r" => '\r',
|
22
|
-
"\xe" => '\u000E',
|
23
|
-
"\xf" => '\u000F',
|
24
|
-
"\x10" => '\u0010',
|
25
|
-
"\x11" => '\u0011',
|
26
|
-
"\x12" => '\u0012',
|
27
|
-
"\x13" => '\u0013',
|
28
|
-
"\x14" => '\u0014',
|
29
|
-
"\x15" => '\u0015',
|
30
|
-
"\x16" => '\u0016',
|
31
|
-
"\x17" => '\u0017',
|
32
|
-
"\x18" => '\u0018',
|
33
|
-
"\x19" => '\u0019',
|
34
|
-
"\x1a" => '\u001A',
|
35
|
-
"\x1b" => '\u001B',
|
36
|
-
"\x1c" => '\u001C',
|
37
|
-
"\x1d" => '\u001D',
|
38
|
-
"\x1e" => '\u001E',
|
39
|
-
"\x1f" => '\u001F',
|
40
|
-
'"' => '\"',
|
41
|
-
'\\' => '\\\\',
|
42
|
-
'/' => '/',
|
43
|
-
} # :nodoc:
|
44
|
-
|
45
|
-
if defined?(::Encoding)
|
46
|
-
# Funky way to define constant, but if parsed in 1.8 it generates an 'invalid regular expression' error otherwise
|
47
|
-
eval %(ESCAPE_RE = %r([\u{80}-\u{10ffff}]))
|
48
|
-
else
|
49
|
-
ESCAPE_RE = %r(
|
50
|
-
[\xc2-\xdf][\x80-\xbf] |
|
51
|
-
[\xe0-\xef][\x80-\xbf]{2} |
|
52
|
-
[\xf0-\xf4][\x80-\xbf]{3}
|
53
|
-
)nx
|
54
|
-
end
|
55
|
-
|
56
|
-
# Convert a UTF8 encoded Ruby string _string_ to an escaped string, encoded with
|
57
|
-
# UTF16 big endian characters as \U????, and return it.
|
58
|
-
#
|
59
|
-
# \\:: Backslash
|
60
|
-
# \':: Single quote
|
61
|
-
# \":: Double quot
|
62
|
-
# \n:: ASCII Linefeed
|
63
|
-
# \r:: ASCII Carriage Return
|
64
|
-
# \t:: ASCCII Horizontal Tab
|
65
|
-
# \uhhhh:: character in BMP with Unicode value U+hhhh
|
66
|
-
# \U00hhhhhh:: character in plane 1-16 with Unicode value U+hhhhhh
|
67
|
-
def rdf_escape
|
68
|
-
string = self + '' # XXX workaround: avoid buffer sharing
|
69
|
-
string.gsub!(/["\\\/\x0-\x1f]/) { RDF_MAP[$&] }
|
70
|
-
if defined?(::Encoding)
|
71
|
-
string.force_encoding(Encoding::UTF_8)
|
72
|
-
string.gsub!(ESCAPE_RE) { |c|
|
73
|
-
s = c.dump.sub(/\"\\u\{(.+)\}\"/, '\1').upcase
|
74
|
-
(s.length <= 4 ? "\\u0000"[0,6-s.length] : "\\U00000000"[0,10-s.length]) + s
|
75
|
-
}
|
76
|
-
string.force_encoding(Encoding::ASCII_8BIT)
|
1
|
+
class Array
|
2
|
+
# http://wiki.rubygarden.org/Ruby/page/show/ArrayPermute
|
3
|
+
# Permute an array, and call a block for each permutation
|
4
|
+
# Author: Paul Battley
|
5
|
+
def permute(prefixed=[])
|
6
|
+
if (length < 2)
|
7
|
+
# there are no elements left to permute
|
8
|
+
yield(prefixed + self)
|
77
9
|
else
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
10
|
+
# recursively permute the remaining elements
|
11
|
+
each_with_index do |e, i|
|
12
|
+
(self[0,i]+self[(i+1)..-1]).permute(prefixed+[e]) { |a| yield a }
|
13
|
+
end
|
82
14
|
end
|
83
|
-
|
84
|
-
end
|
15
|
+
end unless Array.method_defined?(:permute)
|
85
16
|
|
86
|
-
#
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
?n => "\n",
|
95
|
-
?r => "\r",
|
96
|
-
?t => "\t",
|
97
|
-
?u => nil,
|
98
|
-
})
|
17
|
+
# Converts the array to a comma-separated sentence where the last element is joined by the connector word. Options:
|
18
|
+
# * <tt>:words_connector</tt> - The sign or word used to join the elements in arrays with two or more elements (default: ", ")
|
19
|
+
# * <tt>:two_words_connector</tt> - The sign or word used to join the elements in arrays with two elements (default: " and ")
|
20
|
+
# * <tt>:last_word_connector</tt> - The sign or word used to join the last element in arrays with three or more elements (default: ", and ")
|
21
|
+
def to_sentence(options = {})
|
22
|
+
default_words_connector = ", "
|
23
|
+
default_two_words_connector = " and "
|
24
|
+
default_last_word_connector = ", and "
|
99
25
|
|
100
|
-
|
101
|
-
|
102
|
-
(
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
end
|
109
|
-
|
110
|
-
# Reverse operation of escape
|
111
|
-
# From JSON parser
|
112
|
-
def rdf_unescape
|
113
|
-
return '' if self.empty?
|
114
|
-
string = self.gsub(UNESCAPE_RE) do |c|
|
115
|
-
case c[1,1]
|
116
|
-
when 'U'
|
117
|
-
raise RdfException, "Long Unicode escapes no supported in Ruby 1.8" unless defined?(::Encoding)
|
118
|
-
eval(c.sub(/\\U00(\h+)/, '"\u{\1}"'))
|
119
|
-
when 'u'
|
120
|
-
bytes = [c[2, 2].to_i(16), c[4, 2].to_i(16)]
|
121
|
-
Iconv.new('utf-8', 'utf-16').iconv(bytes.pack("C*"))
|
26
|
+
# Try to emulate to_senteces previous to 2.3
|
27
|
+
if options.has_key?(:connector) || options.has_key?(:skip_last_comma)
|
28
|
+
::ActiveSupport::Deprecation.warn(":connector has been deprecated. Use :words_connector instead", caller) if options.has_key? :connector
|
29
|
+
::ActiveSupport::Deprecation.warn(":skip_last_comma has been deprecated. Use :last_word_connector instead", caller) if options.has_key? :skip_last_comma
|
30
|
+
|
31
|
+
skip_last_comma = options.delete :skip_last_comma
|
32
|
+
if connector = options.delete(:connector)
|
33
|
+
options[:last_word_connector] ||= skip_last_comma ? connector : ", #{connector}"
|
122
34
|
else
|
123
|
-
|
35
|
+
options[:last_word_connector] ||= skip_last_comma ? default_two_words_connector : default_last_word_connector
|
124
36
|
end
|
125
37
|
end
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
38
|
+
|
39
|
+
# options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
|
40
|
+
options = {:words_connector => default_words_connector, :two_words_connector => default_two_words_connector, :last_word_connector => default_last_word_connector}.merge(options)
|
41
|
+
|
42
|
+
case length
|
43
|
+
when 0
|
44
|
+
""
|
45
|
+
when 1
|
46
|
+
self[0].to_s
|
47
|
+
when 2
|
48
|
+
"#{self[0]}#{options[:two_words_connector]}#{self[1]}"
|
49
|
+
else
|
50
|
+
"#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
|
51
|
+
end
|
52
|
+
end unless Array.method_defined?(:to_sentence)
|
53
|
+
end
|
@@ -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,23 @@
|
|
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.to_s.rdf_escape}\""
|
18
|
+
output << "@#{language}" if has_language? && !has_datatype?
|
19
|
+
output << "^^<#{datatype}>" if has_datatype?
|
20
|
+
output
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
autoload :Date, 'date'
|
2
|
+
autoload :DateTime, 'date'
|
3
|
+
autoload :Time, 'time'
|
4
|
+
|
5
|
+
module RDF
|
6
|
+
class Literal
|
7
|
+
##
|
8
|
+
# Re-define initialize/new to call _normalize_ on value.
|
9
|
+
# @param [Object]
|
10
|
+
# @option options [Symbol] :language (nil)
|
11
|
+
# @option options [URI] :datatype (nil)
|
12
|
+
# @option options[Hash] :namespaces ({})
|
13
|
+
def initialize_with_normalization(value, options = {})
|
14
|
+
initialize_without_normalization(value, options)
|
15
|
+
normalize(options)
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method :initialize_without_normalization, :initialize
|
19
|
+
alias_method :initialize, :initialize_with_normalization
|
20
|
+
|
21
|
+
def valid?
|
22
|
+
case datatype
|
23
|
+
when XSD.boolean then %w(1 true 0 false).include?(value.to_s.downcase)
|
24
|
+
when XSD.decimal then !!value.to_s.match(/^[\+\-]?\d+(\.\d*)?$/)
|
25
|
+
when XSD.double then !!value.to_s.match(/^[\+\-]?\d+(\.\d*([eE][\+\-]?\d+)?)?$/)
|
26
|
+
when XSD.integer then !!value.to_s.match(/^[\+\-]?\d+$/)
|
27
|
+
else true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
# Normalize literal value
|
34
|
+
#
|
35
|
+
# Options is a hash passed to initialize
|
36
|
+
def normalize(options = {})
|
37
|
+
return unless valid? # Only normalize valid value
|
38
|
+
|
39
|
+
@value = case datatype
|
40
|
+
when XSD.boolean then %(1 true).include?(@value.to_s.downcase) ? "true" : "false"
|
41
|
+
when XSD.integer then @value.to_i.to_s
|
42
|
+
when XSD.decimal then normalize_decimal(@value, options)
|
43
|
+
when XSD.double then normalize_double(@value, options)
|
44
|
+
when XSD.time then @value.is_a?(Time) ? @value.strftime("%H:%M:%S%Z").sub(/\+00:00|UTC/, "Z") : @value.to_s
|
45
|
+
when XSD.dateTime then @value.is_a?(DateTime) ? @value.strftime("%Y-%m-%dT%H:%M:%S%Z").sub(/\+00:00|UTC/, "Z") : @value.to_s
|
46
|
+
when XSD.date then @value.is_a?(Date) ? @value.strftime("%Y-%m-%d%Z").sub(/\+00:00|UTC/, "Z") : @value.to_s
|
47
|
+
when RDF.XMLLiteral then normalize_xmlliteral(@value, options)
|
48
|
+
else @value.to_s
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def normalize_decimal(contents, options)
|
53
|
+
# Can't use simple %f transformation do to special requirements from N3 tests in representation
|
54
|
+
i, f = contents.to_s.split(".")
|
55
|
+
f = f.to_s[0,16] # Truncate after 15 decimal places
|
56
|
+
i.sub!(/^\+?0+(\d)$/, '\1')
|
57
|
+
f.sub!(/0*$/, '')
|
58
|
+
f = "0" if f.empty?
|
59
|
+
"#{i}.#{f}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def normalize_double(contents, options)
|
63
|
+
i, f, e = ("%.16E" % contents.to_f).split(/[\.E]/)
|
64
|
+
f.sub!(/0*$/, '')
|
65
|
+
f = "0" if f.empty?
|
66
|
+
e.sub!(/^\+?0+(\d)$/, '\1')
|
67
|
+
"#{i}.#{f}E#{e}"
|
68
|
+
end
|
69
|
+
|
70
|
+
# Normalize an XML Literal, by adding necessary namespaces.
|
71
|
+
# This should be done as part of initialize
|
72
|
+
#
|
73
|
+
# namespaces is a hash of prefix => URIs
|
74
|
+
def normalize_xmlliteral(contents, options = {})
|
75
|
+
options[:namespaces] ||= {}
|
76
|
+
|
77
|
+
begin
|
78
|
+
# Only normalize if Nokogiri is included
|
79
|
+
require 'nokogiri' unless defined?(Nokogiri)
|
80
|
+
rescue LoadError => e
|
81
|
+
contents.to_s # No normalization
|
82
|
+
end
|
83
|
+
|
84
|
+
if contents.is_a?(String)
|
85
|
+
ns_hash = {}
|
86
|
+
options[:namespaces].each_pair do |prefix, uri|
|
87
|
+
attr = prefix.to_s.empty? ? "xmlns" : "xmlns:#{prefix}"
|
88
|
+
ns_hash[attr] = uri.to_s
|
89
|
+
end
|
90
|
+
ns_strs = []
|
91
|
+
ns_hash.each_pair {|a, u| ns_strs << "#{a}=\"#{u}\""}
|
92
|
+
|
93
|
+
# Add inherited namespaces to created root element so that they're inherited to sub-elements
|
94
|
+
contents = Nokogiri::XML::Document.parse("<foo #{ns_strs.join(" ")}>#{contents}</foo>").root.children
|
95
|
+
end
|
96
|
+
|
97
|
+
# Add already mapped namespaces and language
|
98
|
+
contents.map do |c|
|
99
|
+
if c.is_a?(Nokogiri::XML::Element)
|
100
|
+
c = Nokogiri::XML.parse(c.dup.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::NO_EMPTY_TAGS)).root
|
101
|
+
# Gather namespaces from self and decendant nodes
|
102
|
+
c.traverse do |n|
|
103
|
+
ns = n.namespace
|
104
|
+
next unless ns
|
105
|
+
prefix = ns.prefix ? "xmlns:#{ns.prefix}" : "xmlns"
|
106
|
+
c[prefix] = ns.href.to_s unless c.namespaces[prefix]
|
107
|
+
end
|
108
|
+
|
109
|
+
# Add lanuage
|
110
|
+
if options[:language] && c["lang"].to_s.empty?
|
111
|
+
c["xml:lang"] = options[:language]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
c.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::NO_EMPTY_TAGS)
|
115
|
+
end.join("")
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class NormalizationError < IOError; end
|
120
|
+
end
|