eeml 0.0.17 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.
|