eeml 0.0.17 → 0.0.18
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -1
- data/CHANGELOG +10 -0
- data/lib/eeml/constants.rb +38 -7
- data/lib/eeml/environment.rb +1 -1
- data/lib/eeml/environment_builder.rb +17 -5
- data/lib/eeml/json_environment_parser_v100.rb +6 -6
- data/lib/eeml/json_output.rb +1 -1
- data/lib/eeml/libxml_eeml_output_v005.rb +3 -3
- data/lib/eeml/libxml_eeml_output_v051.rb +118 -0
- data/lib/eeml/libxml_eeml_parser_v005.rb +20 -19
- data/lib/eeml/libxml_eeml_parser_v051.rb +211 -0
- data/lib/eeml/output_registry.rb +4 -2
- data/lib/eeml.rb +1 -1
- data/test/data/doc_1_v1-0-0.json +14 -8
- data/test/data/eeml_datastream_051.xml +11 -0
- data/test/test_environment.rb +10 -0
- metadata +16 -4
data/.gitignore
CHANGED
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
commit 9835edb290ef16b274d9ab59e3c6adca2ce97fcf
|
2
|
+
Author: Levent Ali <lebreeze@gmail.com>
|
3
|
+
Date: Wed Jul 7 18:48:34 2010 +0100
|
4
|
+
|
5
|
+
Version 0.0.18
|
6
|
+
|
7
|
+
json v1.0.0 changed to have current_value, min, max and at at top level within a datastream
|
8
|
+
Added eeml 0.5.1 parser
|
9
|
+
|
10
|
+
|
1
11
|
commit 245dae9ae8e246d3f933106e70df4eadb33823fe
|
2
12
|
Author: Levent Ali <lebreeze@gmail.com>
|
3
13
|
Date: Fri Jul 2 16:03:27 2010 +0100
|
data/lib/eeml/constants.rb
CHANGED
@@ -1,18 +1,49 @@
|
|
1
1
|
module Eeml
|
2
2
|
module Constants
|
3
|
-
LOCAL_EEML5_SCHEMA_LOCATION = "schemas/eeml/005.xsd" # :nodoc:
|
4
|
-
EEML5_HREF = "http://www.eeml.org/xsd/005"
|
5
|
-
EEML5_VERSION = "5"
|
6
|
-
EEML5_SCHEMA_LOCATION = "http://www.eeml.org/xsd/005 http://www.eeml.org/xsd/005/005.xsd"
|
3
|
+
# LOCAL_EEML5_SCHEMA_LOCATION = "schemas/eeml/005.xsd" # :nodoc:
|
4
|
+
# EEML5_HREF = "http://www.eeml.org/xsd/005"
|
5
|
+
# EEML5_VERSION = "5"
|
6
|
+
# EEML5_SCHEMA_LOCATION = "http://www.eeml.org/xsd/005 http://www.eeml.org/xsd/005/005.xsd"
|
7
7
|
|
8
|
-
EEML5_NAMESPACE = ":#{EEML5_HREF}"
|
8
|
+
# EEML5_NAMESPACE = ":#{EEML5_HREF}"
|
9
9
|
XSI_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance"
|
10
10
|
|
11
|
-
EEML6_VERSION = "0.6-alpha1"
|
11
|
+
# EEML6_VERSION = "0.6-alpha1"
|
12
12
|
|
13
13
|
# Not calling this EEML as json is not part of the eeml spec
|
14
|
-
JSON_1_0_0_VERSION = "1.0.0"
|
14
|
+
# JSON_1_0_0_VERSION = "1.0.0"
|
15
|
+
|
15
16
|
# EEML6_RC1_VERSION = "0.6-rc1"
|
17
|
+
JSON_API = {}
|
18
|
+
EEML = {}
|
19
|
+
|
20
|
+
# This is what we called version 5
|
21
|
+
EEML["0.5.0"] =
|
22
|
+
{
|
23
|
+
:href => 'http://www.eeml.org/xsd/005',
|
24
|
+
:version => '5',
|
25
|
+
:schema_location => 'http://www.eeml.org/xsd/005 http://www.eeml.org/xsd/005/005.xsd'
|
26
|
+
}
|
27
|
+
|
28
|
+
# This is NEWER than version 5
|
29
|
+
EEML["0.5.1"] =
|
30
|
+
{
|
31
|
+
:href => 'http://www.eeml.org/xsd/0.5.1',
|
32
|
+
:version => '0.5.1',
|
33
|
+
:schema_location => 'http://www.eeml.org/xsd/0.5.1 http://www.eeml.org/xsd/0.5.1/0.5.1.xsd'
|
34
|
+
}
|
35
|
+
|
36
|
+
JSON_API["0.6-alpha"] =
|
37
|
+
{
|
38
|
+
:version => '0.6-alpha'
|
39
|
+
}
|
40
|
+
|
41
|
+
JSON_API["1.0.0"] =
|
42
|
+
{
|
43
|
+
:version => "1.0.0"
|
44
|
+
}
|
45
|
+
|
46
|
+
|
16
47
|
end
|
17
48
|
end
|
18
49
|
|
data/lib/eeml/environment.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'eeml/libxml_eeml_parser_v005'
|
2
|
+
require 'eeml/libxml_eeml_parser_v051'
|
2
3
|
require 'eeml/json_environment_parser_v005'
|
3
4
|
require 'eeml/json_environment_parser_v006'
|
4
5
|
require 'eeml/json_environment_parser_v100'
|
@@ -6,8 +7,19 @@ require 'eeml/json_environment_parser_v100'
|
|
6
7
|
module Eeml
|
7
8
|
class EnvironmentBuilder # :nodoc:
|
8
9
|
|
10
|
+
include LibXML
|
11
|
+
|
9
12
|
def self.build_from_xml(xml_str)
|
10
|
-
|
13
|
+
begin
|
14
|
+
xml = XML::Parser.string(xml_str).parse
|
15
|
+
if xml.root.namespaces.default.to_s == Constants::EEML['0.5.1'][:href]
|
16
|
+
parser = LibXMLEemlParserV051.new
|
17
|
+
else
|
18
|
+
parser = LibXMLEemlParserV005.new
|
19
|
+
end
|
20
|
+
rescue => e
|
21
|
+
parser = LibXMLEemlParserV005.new
|
22
|
+
end
|
11
23
|
return parser.make_environment_from_xml(xml_str)
|
12
24
|
end
|
13
25
|
|
@@ -18,14 +30,14 @@ module Eeml
|
|
18
30
|
|
19
31
|
def self.build_from_json(json_str)
|
20
32
|
json = JSON.parse(json_str)
|
21
|
-
if json["version"].to_i == Constants::
|
33
|
+
if json["version"].to_i == Constants::EEML['0.5.0'][:version].to_i
|
22
34
|
parser = JsonEnvironmentParserV005.new
|
23
|
-
elsif json["version"] == Constants::
|
35
|
+
elsif json["version"] == Constants::JSON_API['1.0.0'][:version]
|
24
36
|
parser = JsonEnvironmentParserV100.new
|
25
|
-
elsif json["version"].to_f == Constants::
|
37
|
+
elsif json["version"].to_f == Constants::JSON_API['0.6-alpha'][:version].to_f
|
26
38
|
parser = JsonEnvironmentParserV006.new
|
27
39
|
else
|
28
|
-
raise "Invalid version specification. Permitted versions are #{Constants::
|
40
|
+
raise "Invalid version specification. Permitted versions are #{Constants::EEML['0.5.0'][:version]}, #{Constants::JSON_API["0.6-alpha"][:version]} and #{Constants::JSON_API["1.0.0"][:version]}"
|
29
41
|
end
|
30
42
|
return parser.make_environment_from_hash(json)
|
31
43
|
end
|
@@ -52,18 +52,18 @@ module Eeml
|
|
52
52
|
datastream.identifier = datastream_hash['id']
|
53
53
|
datastream.tags = datastream_hash['tags'] unless datastream_hash['tags'].nil?
|
54
54
|
|
55
|
-
values_arr = datastream_hash["
|
55
|
+
#values_arr = datastream_hash["history"]
|
56
56
|
|
57
|
-
raise DataMissingValue if values_arr.nil?
|
57
|
+
#raise DataMissingValue if values_arr.nil?
|
58
58
|
|
59
|
-
values_arr.each do |v|
|
60
|
-
value = Value.new(:value =>
|
59
|
+
#values_arr.each do |v|
|
60
|
+
value = Value.new(:value => datastream_hash["current_value"],
|
61
61
|
:min_value => datastream_hash["min_value"],
|
62
62
|
:max_value => datastream_hash["max_value"],
|
63
|
-
:recorded_at =>
|
63
|
+
:recorded_at => datastream_hash["at"])
|
64
64
|
|
65
65
|
datastream.add_value(value)
|
66
|
-
end
|
66
|
+
#end
|
67
67
|
|
68
68
|
unit_hash = datastream_hash["unit"]
|
69
69
|
unless unit_hash.nil?
|
data/lib/eeml/json_output.rb
CHANGED
@@ -16,7 +16,7 @@ module Eeml
|
|
16
16
|
:website => environment.website,
|
17
17
|
:email => environment.email,
|
18
18
|
:icon => environment.icon,
|
19
|
-
:version =>
|
19
|
+
:version => EEML['0.5.0'][:version] }
|
20
20
|
|
21
21
|
environment_hash[:updated] = environment.updated.utc.iso8601 unless environment.updated.nil? #TODO: was retrieved_at
|
22
22
|
|
@@ -6,10 +6,10 @@ module Eeml
|
|
6
6
|
def to_eeml(environment)
|
7
7
|
doc = XML::Document.new
|
8
8
|
eeml = doc.root = XML::Node.new('eeml')
|
9
|
-
XML::Namespace.new(eeml, nil, Constants::
|
9
|
+
XML::Namespace.new(eeml, nil, Constants::EEML['0.5.0'][:href])
|
10
10
|
XML::Namespace.new(eeml, 'xsi', Constants::XSI_NAMESPACE)
|
11
|
-
eeml['version'] = Constants::
|
12
|
-
eeml['xsi:schemaLocation'] = Constants::
|
11
|
+
eeml['version'] = Constants::EEML['0.5.0'][:version]
|
12
|
+
eeml['xsi:schemaLocation'] = Constants::EEML['0.5.0'][:schema_location]
|
13
13
|
eeml << xml_node_for_environment(environment)
|
14
14
|
|
15
15
|
return doc.to_s(:encoding => XML::Encoding::UTF_8)
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Eeml
|
2
|
+
class LibXMLEemlOutputV051 # :nodoc:
|
3
|
+
include LibXML
|
4
|
+
|
5
|
+
@@eeml_version = Constants::EEML['0.5.1']
|
6
|
+
# main method. creates an EEML 0.5.1 document for the given environment.
|
7
|
+
def to_eeml(environment)
|
8
|
+
doc = XML::Document.new
|
9
|
+
eeml = doc.root = XML::Node.new('eeml')
|
10
|
+
XML::Namespace.new(eeml, nil, @@eeml_version[:href])
|
11
|
+
XML::Namespace.new(eeml, 'xsi', Constants::XSI_NAMESPACE)
|
12
|
+
eeml['version'] = @@eeml_version[:version]
|
13
|
+
eeml['xsi:schemaLocation'] = @@eeml_version[:schema_location]
|
14
|
+
eeml << xml_node_for_environment(environment)
|
15
|
+
return doc.to_s(:encoding => XML::Encoding::UTF_8)
|
16
|
+
end
|
17
|
+
|
18
|
+
def xml_node_for_environment(environment)
|
19
|
+
environment_node = XML::Node.new('environment')
|
20
|
+
|
21
|
+
#TODO: write all these strings out safely for xml
|
22
|
+
|
23
|
+
environment_node['updated'] = environment.updated.utc.iso8601 unless environment.updated.nil?
|
24
|
+
environment_node['id'] = environment.identifier.to_s unless environment.identifier.blank?
|
25
|
+
environment_node['creator'] = environment.creator.to_s unless environment.creator.blank?
|
26
|
+
|
27
|
+
unless environment.title.blank?
|
28
|
+
environment_node << title_node = XML::Node.new('title')
|
29
|
+
title_node << environment.title
|
30
|
+
end
|
31
|
+
|
32
|
+
unless environment.feed_url.blank?
|
33
|
+
environment_node << feed_node = XML::Node.new('feed')
|
34
|
+
feed_node << environment.feed_url
|
35
|
+
end
|
36
|
+
|
37
|
+
unless environment.status.blank?
|
38
|
+
environment_node << status_node = XML::Node.new('status')
|
39
|
+
status_node << environment.status
|
40
|
+
end
|
41
|
+
|
42
|
+
unless environment.description.blank?
|
43
|
+
environment_node << description_node = XML::Node.new('description')
|
44
|
+
description_node << environment.description
|
45
|
+
end
|
46
|
+
|
47
|
+
unless environment.icon.blank?
|
48
|
+
environment_node << icon_node = XML::Node.new('icon')
|
49
|
+
icon_node << environment.icon
|
50
|
+
end
|
51
|
+
|
52
|
+
unless environment.website.blank?
|
53
|
+
environment_node << website_node = XML::Node.new('website')
|
54
|
+
website_node << environment.website
|
55
|
+
end
|
56
|
+
|
57
|
+
unless environment.email.blank?
|
58
|
+
environment_node << email_node = XML::Node.new('email')
|
59
|
+
email_node << environment.email
|
60
|
+
end
|
61
|
+
|
62
|
+
unless environment.location.nil?
|
63
|
+
environment_node << location_node = XML::Node.new('location')
|
64
|
+
location_node['domain'] = environment.location.domain
|
65
|
+
location_node['exposure'] = environment.location.exposure unless environment.location.exposure.blank?
|
66
|
+
location_node['disposition'] = environment.location.disposition unless environment.location.disposition.blank?
|
67
|
+
|
68
|
+
unless environment.location.name.blank?
|
69
|
+
location_node << location_name_node = XML::Node.new('name')
|
70
|
+
location_name_node << environment.location.name
|
71
|
+
end
|
72
|
+
|
73
|
+
location_node << lat_node = XML::Node.new('lat')
|
74
|
+
lat_node << environment.location.latitude
|
75
|
+
|
76
|
+
location_node << lng_node = XML::Node.new('lon')
|
77
|
+
lng_node << environment.location.longitude
|
78
|
+
|
79
|
+
unless environment.location.elevation.blank?
|
80
|
+
location_node << elevation_node = XML::Node.new('ele')
|
81
|
+
elevation_node << environment.location.elevation
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
environment.datastreams.each do |datastream|
|
86
|
+
environment_node << datastream_to_xml_node(datastream)
|
87
|
+
end
|
88
|
+
|
89
|
+
return environment_node
|
90
|
+
end
|
91
|
+
|
92
|
+
def datastream_to_xml_node(datastream)
|
93
|
+
datastream_node = XML::Node.new('data')
|
94
|
+
datastream_node['id'] = datastream.identifier.to_s
|
95
|
+
|
96
|
+
datastream.tags.each do |tag|
|
97
|
+
tag_node = XML::Node.new('tag')
|
98
|
+
tag_node << tag
|
99
|
+
datastream_node << tag_node
|
100
|
+
end
|
101
|
+
|
102
|
+
datastream_node << value_node = XML::Node.new('current_value')
|
103
|
+
datastream_node << max_value_node = XML::Node.new('max_value', datastream.max_value.to_s) unless datastream.max_value.to_s.empty?
|
104
|
+
datastream_node << min_value_node = XML::Node.new('min_value', datastream.min_value.to_s) unless datastream.min_value.to_s.empty?
|
105
|
+
|
106
|
+
value_node << datastream.value.to_s
|
107
|
+
|
108
|
+
unless datastream.unit_value.to_s.empty? && datastream.unit_type.to_s.empty? && datastream.unit_symbol.to_s.empty?
|
109
|
+
datastream_node << unit_node = XML::Node.new('unit')
|
110
|
+
unit_node['type'] = datastream.unit_type.to_s unless datastream.unit_type.to_s.empty?
|
111
|
+
unit_node['symbol'] = datastream.unit_symbol.to_s unless datastream.unit_symbol.to_s.empty?
|
112
|
+
unit_node << datastream.unit_value.to_s unless datastream.unit_value.to_s.empty?
|
113
|
+
end
|
114
|
+
|
115
|
+
return datastream_node
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -5,6 +5,7 @@ module Eeml
|
|
5
5
|
include LibXML
|
6
6
|
include Exceptions
|
7
7
|
|
8
|
+
@@eeml_version = Constants::EEML['0.5.0']
|
8
9
|
#main method
|
9
10
|
|
10
11
|
#take an xml string, and create an Environment from it.
|
@@ -53,13 +54,13 @@ module Eeml
|
|
53
54
|
|
54
55
|
#multiple (zero or more)
|
55
56
|
def extract_environments_from_doc(doc)
|
56
|
-
env_nodes = doc.find('x:environment', "x:#{
|
57
|
+
env_nodes = doc.find('x:environment', "x:#{@@eeml_version[:href]}")
|
57
58
|
return env_nodes.map{|env_node| new_env = Environment.new; extract_environment_from_node(env_node, new_env)}
|
58
59
|
end
|
59
60
|
|
60
61
|
#single, mandatory
|
61
62
|
def extract_environment_from_doc(doc, env_to_populate)
|
62
|
-
env_node = find_first_node_or_fail(doc, 'x:environment', 'environment', "x:#{Constants::
|
63
|
+
env_node = find_first_node_or_fail(doc, 'x:environment', 'environment', "x:#{Constants::EEML['0.5.0'][:href]}")
|
63
64
|
return extract_environment_from_node(env_node, env_to_populate)
|
64
65
|
end
|
65
66
|
|
@@ -71,20 +72,20 @@ module Eeml
|
|
71
72
|
|
72
73
|
env.creator = env_node['creator']
|
73
74
|
|
74
|
-
env.title = optional_content(env_node, 'x:title', 'title', "x:#{
|
75
|
-
env.feed_url = optional_content(env_node, 'x:feed', 'feed', "x:#{
|
76
|
-
env.description = optional_content(env_node, 'x:description', 'description', "x:#{
|
77
|
-
env.website = optional_content(env_node, 'x:website', 'website', "x:#{
|
78
|
-
env.status = optional_content(env_node, 'x:status', 'status', "x:#{
|
79
|
-
env.email = optional_content(env_node, 'x:email', 'email', "x:#{
|
80
|
-
env.icon = optional_content(env_node, 'x:icon', 'icon', "x:#{
|
81
|
-
env.private = optional_content(env_node, 'x:private', 'private', "x:#{
|
75
|
+
env.title = optional_content(env_node, 'x:title', 'title', "x:#{@@eeml_version[:href]}")
|
76
|
+
env.feed_url = optional_content(env_node, 'x:feed', 'feed', "x:#{@@eeml_version[:href]}")
|
77
|
+
env.description = optional_content(env_node, 'x:description', 'description', "x:#{@@eeml_version[:href]}")
|
78
|
+
env.website = optional_content(env_node, 'x:website', 'website', "x:#{@@eeml_version[:href]}")
|
79
|
+
env.status = optional_content(env_node, 'x:status', 'status', "x:#{@@eeml_version[:href]}")
|
80
|
+
env.email = optional_content(env_node, 'x:email', 'email', "x:#{@@eeml_version[:href]}")
|
81
|
+
env.icon = optional_content(env_node, 'x:icon', 'icon', "x:#{@@eeml_version[:href]}")
|
82
|
+
env.private = optional_content(env_node, 'x:private', 'private', "x:#{@@eeml_version[:href]}")
|
82
83
|
|
83
84
|
#find_first_node_or_fail(env_node, 'x:location', 'location')
|
84
|
-
loc_node = env_node.find_first('x:location', "x:#{
|
85
|
+
loc_node = env_node.find_first('x:location', "x:#{@@eeml_version[:href]}")
|
85
86
|
env.location = extractLocation(loc_node) if loc_node
|
86
87
|
|
87
|
-
datastream_nodes = env_node.find('x:data', "x:#{
|
88
|
+
datastream_nodes = env_node.find('x:data', "x:#{@@eeml_version[:href]}")
|
88
89
|
# raise NoDataStreams.new, "no datastreams found" if datastream_nodes.empty?
|
89
90
|
env.datastreams = extractDataStreams(datastream_nodes) unless datastream_nodes.empty?
|
90
91
|
|
@@ -102,10 +103,10 @@ module Eeml
|
|
102
103
|
loc.domain = node['domain']
|
103
104
|
loc.disposition = node['disposition']
|
104
105
|
loc.exposure = node['exposure']
|
105
|
-
loc.name = optional_content(node, 'x:name', 'name', "x:#{
|
106
|
-
loc.latitude = optional_content(node, 'x:lat', 'lat', "x:#{
|
107
|
-
loc.longitude = optional_content(node, 'x:lon', 'lon', "x:#{
|
108
|
-
loc.elevation = optional_content(node, 'x:ele', 'ele', "x:#{
|
106
|
+
loc.name = optional_content(node, 'x:name', 'name', "x:#{@@eeml_version[:href]}")
|
107
|
+
loc.latitude = optional_content(node, 'x:lat', 'lat', "x:#{@@eeml_version[:href]}")
|
108
|
+
loc.longitude = optional_content(node, 'x:lon', 'lon', "x:#{@@eeml_version[:href]}")
|
109
|
+
loc.elevation = optional_content(node, 'x:ele', 'ele', "x:#{@@eeml_version[:href]}")
|
109
110
|
return loc
|
110
111
|
end
|
111
112
|
|
@@ -139,11 +140,11 @@ module Eeml
|
|
139
140
|
data = DataStream.new
|
140
141
|
raise MissingAttribute.new(node.name, 'id') if node['id'].nil?
|
141
142
|
data.identifier = node['id']
|
142
|
-
node.find('x:tag', "x:#{
|
143
|
+
node.find('x:tag', "x:#{@@eeml_version[:href]}").each do |tag_node|
|
143
144
|
data.tags << tag_node.content.strip
|
144
145
|
end
|
145
146
|
|
146
|
-
value_nodes = node.find('x:value', "x:#{
|
147
|
+
value_nodes = node.find('x:value', "x:#{@@eeml_version[:href]}")
|
147
148
|
raise exception_for_node(node, DataMissingValue, "Data node is missing value node.") if value_nodes.empty?
|
148
149
|
raise exception_for_node(node, DataHasMultipleValues, "Data node has multiple 'value' nodes.") if value_nodes.size > 1
|
149
150
|
|
@@ -156,7 +157,7 @@ module Eeml
|
|
156
157
|
|
157
158
|
data.add_value(value)
|
158
159
|
|
159
|
-
unit_nodes = node.find('x:unit', "x:#{
|
160
|
+
unit_nodes = node.find('x:unit', "x:#{@@eeml_version[:href]}")
|
160
161
|
raise exception_for_node(node, DataHasMultipleUnits, "Data node has multiple 'unit' nodes.") if unit_nodes.size > 1
|
161
162
|
|
162
163
|
unit_node = unit_nodes.first
|
@@ -0,0 +1,211 @@
|
|
1
|
+
require "parsedate.rb"
|
2
|
+
module Eeml
|
3
|
+
#a parser for xml eeml v051, implemented with LibXML
|
4
|
+
class LibXMLEemlParserV051 # :nodoc:
|
5
|
+
include LibXML
|
6
|
+
include Exceptions
|
7
|
+
|
8
|
+
@@eeml_version = Constants::EEML['0.5.1']
|
9
|
+
#main method
|
10
|
+
|
11
|
+
#take an xml string, and create an Environment from it.
|
12
|
+
#If an optional environment is given, that will be populated (overwritten) instead of a new environment.
|
13
|
+
def make_environment_from_xml(xml_str, given_environment = nil)
|
14
|
+
doc = parse_xml(xml_str)
|
15
|
+
raise MissingNamespace if doc.root.namespaces.namespace.blank?
|
16
|
+
env = given_environment || Environment.new
|
17
|
+
#TODO: what has to be reset in a given environment before passing it for re-population?
|
18
|
+
return extract_environment_from_doc(doc, env)
|
19
|
+
end
|
20
|
+
|
21
|
+
#take an xml string containing zero or more environment nodes, and create an array of Environment objects from it.
|
22
|
+
def make_environments_from_xml(xml_str)
|
23
|
+
doc = parse_xml(xml_str)
|
24
|
+
raise MissingNamespace if doc.root.namespaces.namespace.blank?
|
25
|
+
return extract_environments_from_doc(doc)
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def parse_xml(xml_str)
|
31
|
+
errors = []
|
32
|
+
#http://libxml.rubyforge.org/rdoc/classes/LibXML/XML/Error.html
|
33
|
+
#TODO: is the error handler set up per thread? (XML::Error.set_handler)
|
34
|
+
XML::Error.set_handler { |error| errors << error }
|
35
|
+
|
36
|
+
#TODO: performance - is this expensive?
|
37
|
+
#TODO: are these configurations per-thread? If they're global (e.g. class variables) then we shouldn't be setting them here.
|
38
|
+
XML.default_line_numbers=true
|
39
|
+
|
40
|
+
parser = XML::Parser.string(xml_str)
|
41
|
+
begin
|
42
|
+
doc = parser.parse
|
43
|
+
rescue XML::Error => e
|
44
|
+
#note: errors var available here, too.
|
45
|
+
raise BadXML, "Malformed xml: #{e.class}: #{e}", e.backtrace
|
46
|
+
end
|
47
|
+
#validation?
|
48
|
+
# seems we have to recreate our XML::Schema object on each invocation
|
49
|
+
# else libxml segfaults very quickly
|
50
|
+
#doc.validate_schema(XML::Schema.from_string(IO.read(LOCAL_EEML5_SCHEMA_LOCATION)))
|
51
|
+
return doc
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
#multiple (zero or more)
|
56
|
+
def extract_environments_from_doc(doc)
|
57
|
+
env_nodes = doc.find('x:environment', "x:#{@@eeml_version[:href]}")
|
58
|
+
return env_nodes.map{|env_node| new_env = Environment.new; extract_environment_from_node(env_node, new_env)}
|
59
|
+
end
|
60
|
+
|
61
|
+
#single, mandatory
|
62
|
+
def extract_environment_from_doc(doc, env_to_populate)
|
63
|
+
env_node = find_first_node_or_fail(doc, 'x:environment', 'environment', "x:#{@@eeml_version[:href]}")
|
64
|
+
return extract_environment_from_node(env_node, env_to_populate)
|
65
|
+
end
|
66
|
+
|
67
|
+
#single, from node (everyone uses this to get the work done)
|
68
|
+
def extract_environment_from_node(env_node, env_to_populate)
|
69
|
+
env = env_to_populate
|
70
|
+
env.identifier = env_node['id']
|
71
|
+
env.updated = Time.gm(*ParseDate.parsedate(env_node['updated'])).utc if !env_node['updated'].nil?
|
72
|
+
|
73
|
+
env.creator = env_node['creator']
|
74
|
+
|
75
|
+
env.title = optional_content(env_node, 'x:title', 'title', "x:#{@@eeml_version[:href]}")
|
76
|
+
env.feed_url = optional_content(env_node, 'x:feed', 'feed', "x:#{@@eeml_version[:href]}")
|
77
|
+
env.description = optional_content(env_node, 'x:description', 'description', "x:#{@@eeml_version[:href]}")
|
78
|
+
env.website = optional_content(env_node, 'x:website', 'website', "x:#{@@eeml_version[:href]}")
|
79
|
+
env.status = optional_content(env_node, 'x:status', 'status', "x:#{@@eeml_version[:href]}")
|
80
|
+
env.email = optional_content(env_node, 'x:email', 'email', "x:#{@@eeml_version[:href]}")
|
81
|
+
env.icon = optional_content(env_node, 'x:icon', 'icon', "x:#{@@eeml_version[:href]}")
|
82
|
+
env.private = optional_content(env_node, 'x:private', 'private', "x:#{@@eeml_version[:href]}")
|
83
|
+
|
84
|
+
#find_first_node_or_fail(env_node, 'x:location', 'location')
|
85
|
+
loc_node = env_node.find_first('x:location', "x:#{@@eeml_version[:href]}")
|
86
|
+
env.location = extractLocation(loc_node) if loc_node
|
87
|
+
|
88
|
+
datastream_nodes = env_node.find('x:data', "x:#{@@eeml_version[:href]}")
|
89
|
+
# raise NoDataStreams.new, "no datastreams found" if datastream_nodes.empty?
|
90
|
+
env.datastreams = extractDataStreams(datastream_nodes) unless datastream_nodes.empty?
|
91
|
+
|
92
|
+
return env
|
93
|
+
end
|
94
|
+
|
95
|
+
def extractLocation(node)
|
96
|
+
#<location domain="physical" exposure="outdoor" disposition="mobile">
|
97
|
+
# <lat>50.1</lat>
|
98
|
+
# <lon>48.7</lon>
|
99
|
+
# <ele>1.34</ele>
|
100
|
+
#</location>
|
101
|
+
raise "given nil node" if node.nil?
|
102
|
+
loc = Location.new
|
103
|
+
loc.domain = node['domain']
|
104
|
+
loc.disposition = node['disposition']
|
105
|
+
loc.exposure = node['exposure']
|
106
|
+
loc.name = optional_content(node, 'x:name', 'name', "x:#{@@eeml_version[:href]}")
|
107
|
+
loc.latitude = optional_content(node, 'x:lat', 'lat', "x:#{@@eeml_version[:href]}")
|
108
|
+
loc.longitude = optional_content(node, 'x:lon', 'lon', "x:#{@@eeml_version[:href]}")
|
109
|
+
loc.elevation = optional_content(node, 'x:ele', 'ele', "x:#{@@eeml_version[:href]}")
|
110
|
+
return loc
|
111
|
+
end
|
112
|
+
|
113
|
+
#return an array (TODO: or a hash?) of DataStream objects from the given list of data nodes
|
114
|
+
def extractDataStreams(nodes)
|
115
|
+
#<data id="blah1">...</data><data id="blah2">...</data>
|
116
|
+
dataStreams = []
|
117
|
+
nodes.each do |node|
|
118
|
+
dataStreams << extractDataStream(node)
|
119
|
+
end
|
120
|
+
return dataStreams
|
121
|
+
end
|
122
|
+
|
123
|
+
#builds and returns a detailed exception of the given class, for problems concerning the given node (or its missing children)
|
124
|
+
#details include node's name and line number (zero if not available)
|
125
|
+
def exception_for_node(node, exception_class, message)
|
126
|
+
ex = exception_class.new(message)
|
127
|
+
ex.line_num = node.line_num
|
128
|
+
ex.node_name = node_name_or_root(node)
|
129
|
+
return ex
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
def extractDataStream(node)
|
134
|
+
#<data id="0">
|
135
|
+
#<tag>some_tag</tag>
|
136
|
+
#<tag>another_tag</tag>
|
137
|
+
#<current_value>0</current_value>
|
138
|
+
#<min_value>0.0</min_value>
|
139
|
+
#<max_value>1022.0</max_value>
|
140
|
+
#<unit symbol="C" type="basicSI">Celsius</unit>
|
141
|
+
#</data>
|
142
|
+
data = DataStream.new
|
143
|
+
raise MissingAttribute.new(node.name, 'id') if node['id'].nil?
|
144
|
+
data.identifier = node['id']
|
145
|
+
node.find('x:tag', "x:#{@@eeml_version[:href]}").each do |tag_node|
|
146
|
+
data.tags << tag_node.content.strip
|
147
|
+
end
|
148
|
+
|
149
|
+
value_nodes = node.find('x:current_value', "x:#{@@eeml_version[:href]}")
|
150
|
+
raise exception_for_node(node, DataMissingValue, "Data node is missing value node.") if value_nodes.empty?
|
151
|
+
raise exception_for_node(node, DataHasMultipleValues, "Data node has multiple 'value' nodes.") if value_nodes.size > 1
|
152
|
+
|
153
|
+
value_node = value_nodes.first
|
154
|
+
|
155
|
+
max_value_node = node.find_first('x:max_value', "x:#{@@eeml_version[:href]}")
|
156
|
+
min_value_node = node.find_first('x:min_value', "x:#{@@eeml_version[:href]}")
|
157
|
+
|
158
|
+
value = Value.new
|
159
|
+
value.min_value = min_value_node.content if min_value_node
|
160
|
+
value.max_value = max_value_node.content if max_value_node
|
161
|
+
value.value = value_node.content.strip
|
162
|
+
|
163
|
+
data.add_value(value)
|
164
|
+
|
165
|
+
unit_nodes = node.find('x:unit', "x:#{@@eeml_version[:href]}")
|
166
|
+
raise exception_for_node(node, DataHasMultipleUnits, "Data node has multiple 'unit' nodes.") if unit_nodes.size > 1
|
167
|
+
|
168
|
+
unit_node = unit_nodes.first
|
169
|
+
unless unit_node.nil?
|
170
|
+
data.unit_symbol = unit_node['symbol']
|
171
|
+
data.unit_type = unit_node['type']
|
172
|
+
data.unit_value = unit_node.content.strip
|
173
|
+
end
|
174
|
+
|
175
|
+
return data
|
176
|
+
end
|
177
|
+
|
178
|
+
#Helpers ------------------------------------------------------------------
|
179
|
+
#Consider mixing these in to the libxml parser for more readable code
|
180
|
+
|
181
|
+
#raises MissingNode if the node isn't there
|
182
|
+
def mandatory_content(base_node, xpath, description, nslist = nil)
|
183
|
+
node = base_node.find_first(xpath, nslist)
|
184
|
+
raise(MissingNode.new(node_name_or_root(base_node), description, xpath)) if node.nil?
|
185
|
+
return node.content
|
186
|
+
end
|
187
|
+
|
188
|
+
#returns the node's content, or the given default if the node isn't there (default itself defaults to nil)
|
189
|
+
#description isn't used, but keeps our signature same as mandatory_content(), up to that point.
|
190
|
+
def optional_content(base_node, xpath, description, nslist = nil, default = nil)
|
191
|
+
node = base_node.find_first(xpath, nslist)
|
192
|
+
return node.nil? ? default : node.content
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
#get the name of the given node if it is a node, or 'root' if it is a doc.
|
197
|
+
#for use only for error messages
|
198
|
+
def node_name_or_root(node)
|
199
|
+
node.respond_to?(:name) ? node.name : 'root'
|
200
|
+
end
|
201
|
+
|
202
|
+
def find_first_node_or_fail(base_node, xpath, description, nslist = nil)
|
203
|
+
node = base_node.find_first(xpath, nslist)
|
204
|
+
raise(MissingNode.new(node_name_or_root(base_node), description, xpath)) if node.nil?
|
205
|
+
return node
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
data/lib/eeml/output_registry.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
require 'eeml/libxml_eeml_output_v005'
|
2
|
+
require 'eeml/libxml_eeml_output_v051'
|
2
3
|
require 'eeml/json_output'
|
3
4
|
|
4
5
|
module Eeml
|
5
6
|
class OutputRegistry # :nodoc:
|
6
7
|
#look at the given xml, build and return a new v005 or 006 parser, accordingly
|
7
|
-
def self.get_xml_output_for(version = Constants::
|
8
|
+
def self.get_xml_output_for(version = Constants::EEML['0.5.0'][:version])
|
9
|
+
return LibXMLEemlOutputV051.new if version == Constants::EEML['0.5.1'][:version]
|
8
10
|
LibXMLEemlOutputV005.new
|
9
11
|
end
|
10
12
|
|
11
|
-
def self.get_json_output_for(version = Constants::
|
13
|
+
def self.get_json_output_for(version = Constants::EEML['0.5.0'][:version])
|
12
14
|
JsonOutput.new
|
13
15
|
end
|
14
16
|
|
data/lib/eeml.rb
CHANGED
data/test/data/doc_1_v1-0-0.json
CHANGED
@@ -1,15 +1,21 @@
|
|
1
1
|
{"datastreams":[
|
2
|
-
{
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
2
|
+
{
|
3
|
+
"tags":["tagD0"],
|
4
|
+
"current_value":"0",
|
5
|
+
"at":"2009-02-11T10:56:56Z",
|
6
|
+
"min_value":"-9999.0",
|
7
|
+
"max_value":"1022.0",
|
8
|
+
"unit":{"type":"basicSI","label":"Celsius","symbol":"C"},
|
9
|
+
"id":"0"
|
10
|
+
},
|
11
|
+
{
|
12
|
+
"current_value":"33",
|
13
|
+
"at":"2009-02-11T10:56:55Z",
|
9
14
|
"min_value":"0.0","max_value":"1023.0",
|
10
15
|
"id":"1"},
|
11
16
|
{"tags":["tagD2a","tagD2b","tagD2c"],
|
12
|
-
"
|
17
|
+
"current_value":"42.1",
|
18
|
+
"at":"2009-02-11T10:55:10Z",
|
13
19
|
"min_value":"23.4","max_value":"1021.0",
|
14
20
|
"id":"2"}
|
15
21
|
],
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<eeml xmlns="http://www.eeml.org/xsd/0.5.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="0.5.1" xsi:schemaLocation="http://www.eeml.org/xsd/0.5.1 http://www.eeml.org/xsd/0.5.1/0.5.1.xsd">
|
3
|
+
<environment>
|
4
|
+
<data id="0">
|
5
|
+
<tag>sometag</tag>
|
6
|
+
<current_value>65</current_value>
|
7
|
+
<max_value>100.0</max_value>
|
8
|
+
<min_value>4.0</min_value>
|
9
|
+
</data>
|
10
|
+
</environment>
|
11
|
+
</eeml>
|
data/test/test_environment.rb
CHANGED
@@ -566,6 +566,16 @@ class TestEnvironment < Test::Unit::TestCase
|
|
566
566
|
assert_equal expected_xml, xml_output
|
567
567
|
end
|
568
568
|
|
569
|
+
test "should output to eeml 0.5.1 ok" do
|
570
|
+
env = create_env_from_xml_file('eeml_datastream_051.xml')
|
571
|
+
xml_output = env.to_eeml('0.5.1')
|
572
|
+
assert_not_nil xml_output
|
573
|
+
|
574
|
+
expected_xml = File.read('test/data/eeml_datastream_051.xml')
|
575
|
+
assert_equal expected_xml, xml_output
|
576
|
+
|
577
|
+
end
|
578
|
+
|
569
579
|
implement "output - check that 'feed' url is correctly assembled" do
|
570
580
|
end
|
571
581
|
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eeml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 59
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
9
|
+
- 18
|
10
|
+
version: 0.0.18
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Neill Bogie
|
@@ -16,16 +17,18 @@ autorequire:
|
|
16
17
|
bindir: bin
|
17
18
|
cert_chain: []
|
18
19
|
|
19
|
-
date: 2010-07-
|
20
|
+
date: 2010-07-20 00:00:00 +01:00
|
20
21
|
default_executable:
|
21
22
|
dependencies:
|
22
23
|
- !ruby/object:Gem::Dependency
|
23
24
|
name: libxml-ruby
|
24
25
|
prerelease: false
|
25
26
|
requirement: &id001 !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
26
28
|
requirements:
|
27
29
|
- - ">="
|
28
30
|
- !ruby/object:Gem::Version
|
31
|
+
hash: 21
|
29
32
|
segments:
|
30
33
|
- 1
|
31
34
|
- 1
|
@@ -37,9 +40,11 @@ dependencies:
|
|
37
40
|
name: json
|
38
41
|
prerelease: false
|
39
42
|
requirement: &id002 !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
40
44
|
requirements:
|
41
45
|
- - ">="
|
42
46
|
- !ruby/object:Gem::Version
|
47
|
+
hash: 1
|
43
48
|
segments:
|
44
49
|
- 1
|
45
50
|
- 4
|
@@ -76,7 +81,9 @@ files:
|
|
76
81
|
- lib/eeml/json_environment_parser_v100.rb
|
77
82
|
- lib/eeml/json_output.rb
|
78
83
|
- lib/eeml/libxml_eeml_output_v005.rb
|
84
|
+
- lib/eeml/libxml_eeml_output_v051.rb
|
79
85
|
- lib/eeml/libxml_eeml_parser_v005.rb
|
86
|
+
- lib/eeml/libxml_eeml_parser_v051.rb
|
80
87
|
- lib/eeml/output_registry.rb
|
81
88
|
- schemas/eeml/005.xsd
|
82
89
|
- test/data/.gitignore
|
@@ -91,6 +98,7 @@ files:
|
|
91
98
|
- test/data/doc_1_v6_private.json
|
92
99
|
- test/data/doc_2.xml
|
93
100
|
- test/data/doc_2_expected.json
|
101
|
+
- test/data/eeml_datastream_051.xml
|
94
102
|
- test/data/list.xml
|
95
103
|
- test/data/minimal.xml
|
96
104
|
- test/data/no_namespace.xml
|
@@ -110,23 +118,27 @@ rdoc_options:
|
|
110
118
|
require_paths:
|
111
119
|
- lib
|
112
120
|
required_ruby_version: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
113
122
|
requirements:
|
114
123
|
- - ">="
|
115
124
|
- !ruby/object:Gem::Version
|
125
|
+
hash: 3
|
116
126
|
segments:
|
117
127
|
- 0
|
118
128
|
version: "0"
|
119
129
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
120
131
|
requirements:
|
121
132
|
- - ">="
|
122
133
|
- !ruby/object:Gem::Version
|
134
|
+
hash: 3
|
123
135
|
segments:
|
124
136
|
- 0
|
125
137
|
version: "0"
|
126
138
|
requirements: []
|
127
139
|
|
128
140
|
rubyforge_project:
|
129
|
-
rubygems_version: 1.3.
|
141
|
+
rubygems_version: 1.3.7
|
130
142
|
signing_key:
|
131
143
|
specification_version: 3
|
132
144
|
summary: Simple little library for programmatically manipulating EEML documents.
|