eeml 0.0.34 → 0.0.35
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 +9 -0
- data/README +4 -2
- data/lib/eeml.rb +1 -1
- data/lib/eeml/constants.rb +8 -0
- data/lib/eeml/environment.rb +10 -0
- data/lib/eeml/environment_builder.rb +3 -0
- data/lib/eeml/json_environment_parser_v100.rb +9 -0
- data/lib/eeml/libxml_eeml_parser_v052.rb +232 -0
- data/schemas/eeml/0.5.2.xsd +167 -0
- data/test/data/environment_minimal_052.xml +8 -0
- data/test/test_environment.rb +12 -1
- metadata +25 -10
data/.gitignore
ADDED
data/README
CHANGED
@@ -4,8 +4,10 @@
|
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
7
|
-
Library for simplifying the creation and manipulation of EEML documents,
|
8
|
-
|
7
|
+
Library for simplifying the creation and manipulation of EEML documents,
|
8
|
+
primarily intended for use with pachube.com. Provides parsing of EEML documents
|
9
|
+
into ruby objects that can be used programmatically. Also provides parsing and
|
10
|
+
output of the JSON format used by pachube.com.
|
9
11
|
|
10
12
|
== USAGE
|
11
13
|
|
data/lib/eeml.rb
CHANGED
data/lib/eeml/constants.rb
CHANGED
@@ -33,6 +33,14 @@ module Eeml
|
|
33
33
|
:schema_location => 'http://www.eeml.org/xsd/0.5.1 http://www.eeml.org/xsd/0.5.1/0.5.1.xsd'
|
34
34
|
}
|
35
35
|
|
36
|
+
# This is NEWER than version 5
|
37
|
+
EEML["0.5.2"] =
|
38
|
+
{
|
39
|
+
:href => 'http://www.eeml.org/xsd/0.5.2',
|
40
|
+
:versions => '0.5.2',
|
41
|
+
:schema_location => 'http://www.eeml.org/xsd/0.5.2 http://www.eeml.org/xsd/0.5.2/0.5.2.xsd'
|
42
|
+
}
|
43
|
+
|
36
44
|
JSON_API["0.6-alpha"] =
|
37
45
|
{
|
38
46
|
:versions => ['0.6', '0.6-alpha']
|
data/lib/eeml/environment.rb
CHANGED
@@ -93,12 +93,22 @@ module Eeml
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
+
class Owner
|
97
|
+
attr_accessor :login, :url
|
98
|
+
|
99
|
+
def initialize(options = {})
|
100
|
+
@login = options[:login]
|
101
|
+
@url = options[:url]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
96
105
|
# This class represents the main point of entry to this library. In general we will be creating instances of this class, either
|
97
106
|
# by manually specifying the parameters, or probably more commonly, by passing in either an EEML or JSON formatted string which
|
98
107
|
# will be parsed to initialize the object.
|
99
108
|
class Environment
|
100
109
|
attr_accessor :identifier, :updated, :creator
|
101
110
|
attr_accessor :title, :description, :feed_url, :website, :email, :icon, :status
|
111
|
+
attr_accessor :owner
|
102
112
|
attr_accessor :location
|
103
113
|
attr_accessor :csv_version
|
104
114
|
attr_accessor :datastreams
|
@@ -2,6 +2,7 @@ require 'eeml/csv_parser_v1'
|
|
2
2
|
require 'eeml/csv_parser_v2'
|
3
3
|
require 'eeml/libxml_eeml_parser_v005'
|
4
4
|
require 'eeml/libxml_eeml_parser_v051'
|
5
|
+
require 'eeml/libxml_eeml_parser_v052'
|
5
6
|
require 'eeml/json_environment_parser_v005'
|
6
7
|
require 'eeml/json_environment_parser_v006'
|
7
8
|
require 'eeml/json_environment_parser_v100'
|
@@ -16,6 +17,8 @@ module Eeml
|
|
16
17
|
xml = XML::Parser.string(xml_str).parse
|
17
18
|
if xml.root.namespaces.default.to_s == Constants::EEML['0.5.1'][:href]
|
18
19
|
parser = LibXMLEemlParserV051.new
|
20
|
+
elsif xml.root.namespaces.default.to_s == Constants::EEML['0.5.2'][:href]
|
21
|
+
parser = LibXMLEemlParserV052.new
|
19
22
|
else
|
20
23
|
parser = LibXMLEemlParserV005.new
|
21
24
|
end
|
@@ -18,6 +18,8 @@ module Eeml
|
|
18
18
|
|
19
19
|
env.tags = env_hash['tags'] unless env_hash['tags'].nil?
|
20
20
|
|
21
|
+
env.owner = buildOwner(env_hash)
|
22
|
+
|
21
23
|
env.location = buildLocation(env_hash)
|
22
24
|
|
23
25
|
env.add_datastreams(buildDatastreams(env_hash))
|
@@ -32,6 +34,13 @@ module Eeml
|
|
32
34
|
|
33
35
|
private
|
34
36
|
|
37
|
+
def buildOwner(env_hash)
|
38
|
+
owner_hash = env_hash["owner"]
|
39
|
+
return if owner_hash.nil?
|
40
|
+
Owner.new(:login => owner_hash["login"],
|
41
|
+
:url => owner_hash["url"])
|
42
|
+
end
|
43
|
+
|
35
44
|
def buildLocation(env_hash)
|
36
45
|
location_hash = env_hash["location"]
|
37
46
|
return if location_hash.nil?
|
@@ -0,0 +1,232 @@
|
|
1
|
+
require "parsedate.rb"
|
2
|
+
module Eeml
|
3
|
+
#a parser for xml eeml v052, implemented with LibXML
|
4
|
+
class LibXMLEemlParserV052 # :nodoc:
|
5
|
+
include LibXML
|
6
|
+
include Exceptions
|
7
|
+
|
8
|
+
@@eeml_version = Constants::EEML['0.5.2']
|
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(strip_content(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
|
+
#multiple (zero or more)
|
55
|
+
def extract_environments_from_doc(doc)
|
56
|
+
env_nodes = doc.find('x:environment', "x:#{@@eeml_version[:href]}")
|
57
|
+
return env_nodes.map{|env_node| new_env = Environment.new; extract_environment_from_node(env_node, new_env)}
|
58
|
+
end
|
59
|
+
|
60
|
+
#single, mandatory
|
61
|
+
def extract_environment_from_doc(doc, env_to_populate)
|
62
|
+
env_node = find_first_node_or_fail(doc, 'x:environment', 'environment', "x:#{@@eeml_version[:href]}")
|
63
|
+
return extract_environment_from_node(env_node, env_to_populate)
|
64
|
+
end
|
65
|
+
|
66
|
+
#single, from node (everyone uses this to get the work done)
|
67
|
+
def extract_environment_from_node(env_node, env_to_populate)
|
68
|
+
env = env_to_populate
|
69
|
+
env.identifier = env_node['id']
|
70
|
+
env.updated = Time.parse(env_node['updated']) if !env_node['updated'].nil?
|
71
|
+
|
72
|
+
env.creator = env_node['creator']
|
73
|
+
|
74
|
+
env.title = optional_content(env_node, 'x:title', 'title', "x:#{@@eeml_version[:href]}")
|
75
|
+
env.feed_url = optional_content(env_node, 'x:feed', 'feed', "x:#{@@eeml_version[:href]}")
|
76
|
+
env.description = optional_content(env_node, 'x:description', 'description', "x:#{@@eeml_version[:href]}")
|
77
|
+
env.website = optional_content(env_node, 'x:website', 'website', "x:#{@@eeml_version[:href]}")
|
78
|
+
env.status = optional_content(env_node, 'x:status', 'status', "x:#{@@eeml_version[:href]}")
|
79
|
+
env.email = optional_content(env_node, 'x:email', 'email', "x:#{@@eeml_version[:href]}")
|
80
|
+
env.icon = optional_content(env_node, 'x:icon', 'icon', "x:#{@@eeml_version[:href]}")
|
81
|
+
env.private = (optional_content(env_node, 'x:private', 'private', "x:#{@@eeml_version[:href]}") == "true")
|
82
|
+
|
83
|
+
owner_node = env_node.find_first('x:owner', "x:#{@@eeml_version[:href]}")
|
84
|
+
env.owner = extractOwner(owner_node) if owner_node
|
85
|
+
|
86
|
+
#find_first_node_or_fail(env_node, 'x:location', 'location')
|
87
|
+
loc_node = env_node.find_first('x:location', "x:#{@@eeml_version[:href]}")
|
88
|
+
env.location = extractLocation(loc_node) if loc_node
|
89
|
+
|
90
|
+
env_node.find('x:tag', "x:#{@@eeml_version[:href]}").each do |tag_node|
|
91
|
+
env.tags << tag_node.content.strip
|
92
|
+
end
|
93
|
+
|
94
|
+
datastream_nodes = env_node.find('x:data', "x:#{@@eeml_version[:href]}")
|
95
|
+
# raise NoDataStreams.new, "no datastreams found" if datastream_nodes.empty?
|
96
|
+
env.add_datastreams(extractDataStreams(datastream_nodes)) unless datastream_nodes.empty?
|
97
|
+
|
98
|
+
return env
|
99
|
+
end
|
100
|
+
|
101
|
+
def extractOwner(node)
|
102
|
+
#<owner>
|
103
|
+
# <login>bob</login>
|
104
|
+
# <url>http://pachube.com/users/bob</url>
|
105
|
+
#</owner>
|
106
|
+
raise "given nil node" if node.nil?
|
107
|
+
owner = Owner.new
|
108
|
+
owner.login = optional_content(node, 'x:login', 'login', "x:#{@eeml_version[:href]}")
|
109
|
+
owner.url = optional_content(node, 'x:url', 'url', "x:#{@eeml_version[:href]}")
|
110
|
+
return owner
|
111
|
+
end
|
112
|
+
|
113
|
+
def extractLocation(node)
|
114
|
+
#<location domain="physical" exposure="outdoor" disposition="mobile">
|
115
|
+
# <lat>50.1</lat>
|
116
|
+
# <lon>48.7</lon>
|
117
|
+
# <ele>1.34</ele>
|
118
|
+
#</location>
|
119
|
+
raise "given nil node" if node.nil?
|
120
|
+
loc = Location.new
|
121
|
+
loc.domain = node['domain']
|
122
|
+
loc.disposition = node['disposition']
|
123
|
+
loc.exposure = node['exposure']
|
124
|
+
loc.name = optional_content(node, 'x:name', 'name', "x:#{@@eeml_version[:href]}")
|
125
|
+
loc.latitude = optional_content(node, 'x:lat', 'lat', "x:#{@@eeml_version[:href]}")
|
126
|
+
loc.longitude = optional_content(node, 'x:lon', 'lon', "x:#{@@eeml_version[:href]}")
|
127
|
+
loc.elevation = optional_content(node, 'x:ele', 'ele', "x:#{@@eeml_version[:href]}")
|
128
|
+
return loc
|
129
|
+
end
|
130
|
+
|
131
|
+
#return an array (TODO: or a hash?) of DataStream objects from the given list of data nodes
|
132
|
+
def extractDataStreams(nodes)
|
133
|
+
#<data id="blah1">...</data><data id="blah2">...</data>
|
134
|
+
dataStreams = []
|
135
|
+
nodes.each do |node|
|
136
|
+
dataStreams << extractDataStream(node)
|
137
|
+
end
|
138
|
+
return dataStreams
|
139
|
+
end
|
140
|
+
|
141
|
+
#builds and returns a detailed exception of the given class, for problems concerning the given node (or its missing children)
|
142
|
+
#details include node's name and line number (zero if not available)
|
143
|
+
def exception_for_node(node, exception_class, message)
|
144
|
+
ex = exception_class.new(message)
|
145
|
+
ex.line_num = node.line_num
|
146
|
+
ex.node_name = node_name_or_root(node)
|
147
|
+
return ex
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
def extractDataStream(node)
|
152
|
+
#<data id="0">
|
153
|
+
#<tag>some_tag</tag>
|
154
|
+
#<tag>another_tag</tag>
|
155
|
+
#<current_value>0</current_value>
|
156
|
+
#<min_value>0.0</min_value>
|
157
|
+
#<max_value>1022.0</max_value>
|
158
|
+
#<unit symbol="C" type="basicSI">Celsius</unit>
|
159
|
+
#</data>
|
160
|
+
data = DataStream.new
|
161
|
+
raise MissingAttribute.new(node.name, 'id') if node['id'].nil?
|
162
|
+
data.identifier = node['id']
|
163
|
+
node.find('x:tag', "x:#{@@eeml_version[:href]}").each do |tag_node|
|
164
|
+
data.tags << tag_node.content.strip
|
165
|
+
end
|
166
|
+
|
167
|
+
value_nodes = node.find('x:current_value', "x:#{@@eeml_version[:href]}")
|
168
|
+
# raise exception_for_node(node, DataMissingValue, "Data node is missing current_value node.") if value_nodes.empty?
|
169
|
+
raise exception_for_node(node, DataHasMultipleValues, "Data node has multiple 'value' nodes.") if value_nodes.size > 1
|
170
|
+
|
171
|
+
value_node = value_nodes.first
|
172
|
+
|
173
|
+
max_value_node = node.find_first('x:max_value', "x:#{@@eeml_version[:href]}")
|
174
|
+
min_value_node = node.find_first('x:min_value', "x:#{@@eeml_version[:href]}")
|
175
|
+
|
176
|
+
value = Value.new
|
177
|
+
value.min_value = min_value_node.content if min_value_node
|
178
|
+
value.max_value = max_value_node.content if max_value_node
|
179
|
+
if value_node
|
180
|
+
value.value = value_node.content.strip
|
181
|
+
value.recorded_at = value_node['at'] unless value_node['at'].blank?
|
182
|
+
end
|
183
|
+
|
184
|
+
data.add_value(value)
|
185
|
+
|
186
|
+
unit_nodes = node.find('x:unit', "x:#{@@eeml_version[:href]}")
|
187
|
+
raise exception_for_node(node, DataHasMultipleUnits, "Data node has multiple 'unit' nodes.") if unit_nodes.size > 1
|
188
|
+
|
189
|
+
unit_node = unit_nodes.first
|
190
|
+
unless unit_node.nil?
|
191
|
+
data.unit_symbol = unit_node['symbol']
|
192
|
+
data.unit_type = unit_node['type']
|
193
|
+
data.unit_value = unit_node.content.strip
|
194
|
+
end
|
195
|
+
|
196
|
+
return data
|
197
|
+
end
|
198
|
+
|
199
|
+
#Helpers ------------------------------------------------------------------
|
200
|
+
#Consider mixing these in to the libxml parser for more readable code
|
201
|
+
|
202
|
+
#raises MissingNode if the node isn't there
|
203
|
+
def mandatory_content(base_node, xpath, description, nslist = nil)
|
204
|
+
node = base_node.find_first(xpath, nslist)
|
205
|
+
raise(MissingNode.new(node_name_or_root(base_node), description, xpath)) if node.nil?
|
206
|
+
return node.content
|
207
|
+
end
|
208
|
+
|
209
|
+
#returns the node's content, or the given default if the node isn't there (default itself defaults to nil)
|
210
|
+
#description isn't used, but keeps our signature same as mandatory_content(), up to that point.
|
211
|
+
def optional_content(base_node, xpath, description, nslist = nil, default = nil)
|
212
|
+
node = base_node.find_first(xpath, nslist)
|
213
|
+
return node.nil? ? default : node.content
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
#get the name of the given node if it is a node, or 'root' if it is a doc.
|
218
|
+
#for use only for error messages
|
219
|
+
def node_name_or_root(node)
|
220
|
+
node.respond_to?(:name) ? node.name : 'root'
|
221
|
+
end
|
222
|
+
|
223
|
+
def find_first_node_or_fail(base_node, xpath, description, nslist = nil)
|
224
|
+
node = base_node.find_first(xpath, nslist)
|
225
|
+
raise(MissingNode.new(node_name_or_root(base_node), description, xpath)) if node.nil?
|
226
|
+
return node
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
|
@@ -0,0 +1,167 @@
|
|
1
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
2
|
+
<xsd:schema xmlns="http://www.eeml.org/xsd/0.5.2" elementFormDefault="qualified" targetNamespace="http://www.eeml.org/xsd/0.5.2" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
3
|
+
<xsd:element name="eeml">
|
4
|
+
<xsd:complexType>
|
5
|
+
<xsd:choice>
|
6
|
+
<xsd:element maxOccurs="unbounded" name="environment">
|
7
|
+
<xsd:complexType>
|
8
|
+
<xsd:sequence>
|
9
|
+
<xsd:element minOccurs="0" name="title" type="xsd:string" />
|
10
|
+
<xsd:element minOccurs="0" name="feed" type="xsd:anyURI" />
|
11
|
+
<xsd:element minOccurs="0" name="status">
|
12
|
+
<xsd:simpleType>
|
13
|
+
<xsd:restriction base="xsd:string">
|
14
|
+
<xsd:enumeration value="frozen" />
|
15
|
+
<xsd:enumeration value="live" />
|
16
|
+
</xsd:restriction>
|
17
|
+
</xsd:simpleType>
|
18
|
+
</xsd:element>
|
19
|
+
<xsd:element minOccurs="0" name="private">
|
20
|
+
<xsd:simpleType>
|
21
|
+
<xsd:restriction base="xsd:string">
|
22
|
+
<xsd:enumeration value="true" />
|
23
|
+
<xsd:enumeration value="false" />
|
24
|
+
</xsd:restriction>
|
25
|
+
</xsd:simpleType>
|
26
|
+
</xsd:element>
|
27
|
+
<xsd:element minOccurs="0" name="description" type="xsd:string" />
|
28
|
+
<xsd:element minOccurs="0" name="icon" type="xsd:anyURI" />
|
29
|
+
<xsd:element minOccurs="0" name="website" type="xsd:anyURI" />
|
30
|
+
<xsd:element minOccurs="0" name="email" type="xsd:string" />
|
31
|
+
<xsd:element minOccurs="0" maxOccurs="unbounded" name="tag" type="xsd:string" />
|
32
|
+
<xsd:element minOccurs="0" name="owner">
|
33
|
+
<xsd:complexType>
|
34
|
+
<xsd:sequence>
|
35
|
+
<xsd:element minOccurs="0" name="login" type="xsd:string" />
|
36
|
+
<xsd:element minOccurs="0" name="url" type="xsd:anyURI" />
|
37
|
+
</xsd:sequence>
|
38
|
+
</xsd:complexType>
|
39
|
+
</xsd:element>
|
40
|
+
<xsd:element minOccurs="0" name="location">
|
41
|
+
<xsd:complexType>
|
42
|
+
<xsd:sequence>
|
43
|
+
<xsd:element minOccurs="0" name="name" type="xsd:string" />
|
44
|
+
<xsd:element name="lat">
|
45
|
+
<xsd:simpleType>
|
46
|
+
<xsd:restriction base="xsd:double">
|
47
|
+
<xsd:minInclusive value="-90" />
|
48
|
+
<xsd:maxInclusive value="90" />
|
49
|
+
</xsd:restriction>
|
50
|
+
</xsd:simpleType>
|
51
|
+
</xsd:element>
|
52
|
+
<xsd:element name="lon">
|
53
|
+
<xsd:simpleType>
|
54
|
+
<xsd:restriction base="xsd:double">
|
55
|
+
<xsd:minInclusive value="-180" />
|
56
|
+
<xsd:maxInclusive value="180" />
|
57
|
+
</xsd:restriction>
|
58
|
+
</xsd:simpleType>
|
59
|
+
</xsd:element>
|
60
|
+
<xsd:element minOccurs="0" maxOccurs="1" name="ele" type="xsd:double" />
|
61
|
+
</xsd:sequence>
|
62
|
+
<xsd:attribute name="exposure" use="optional">
|
63
|
+
<xsd:simpleType>
|
64
|
+
<xsd:restriction base="xsd:string">
|
65
|
+
<xsd:enumeration value="indoor" />
|
66
|
+
<xsd:enumeration value="outdoor" />
|
67
|
+
</xsd:restriction>
|
68
|
+
</xsd:simpleType>
|
69
|
+
</xsd:attribute>
|
70
|
+
<xsd:attribute name="domain" use="required">
|
71
|
+
<xsd:simpleType>
|
72
|
+
<xsd:restriction base="xsd:string">
|
73
|
+
<xsd:enumeration value="physical" />
|
74
|
+
<xsd:enumeration value="virtual" />
|
75
|
+
</xsd:restriction>
|
76
|
+
</xsd:simpleType>
|
77
|
+
</xsd:attribute>
|
78
|
+
<xsd:attribute name="disposition" use="optional">
|
79
|
+
<xsd:simpleType>
|
80
|
+
<xsd:restriction base="xsd:string">
|
81
|
+
<xsd:enumeration value="fixed" />
|
82
|
+
<xsd:enumeration value="mobile" />
|
83
|
+
</xsd:restriction>
|
84
|
+
</xsd:simpleType>
|
85
|
+
</xsd:attribute>
|
86
|
+
</xsd:complexType>
|
87
|
+
</xsd:element>
|
88
|
+
<xsd:element minOccurs="1" maxOccurs="unbounded" name="data">
|
89
|
+
<xsd:complexType>
|
90
|
+
<xsd:sequence>
|
91
|
+
<xsd:element minOccurs="0" maxOccurs="unbounded" name="tag" type="xsd:string" />
|
92
|
+
<xsd:element minOccurs="0" maxOccurs="1" name="current_value">
|
93
|
+
<xsd:complexType>
|
94
|
+
<xsd:simpleContent>
|
95
|
+
<xsd:extension base="xsd:string">
|
96
|
+
<xsd:attribute name="at" type="xsd:dateTime" use="optional" />
|
97
|
+
</xsd:extension>
|
98
|
+
</xsd:simpleContent>
|
99
|
+
</xsd:complexType>
|
100
|
+
</xsd:element>
|
101
|
+
<xsd:element minOccurs="0" maxOccurs="1" name="max_value" type="xsd:string" />
|
102
|
+
<xsd:element minOccurs="0" maxOccurs="1" name="min_value" type="xsd:string" />
|
103
|
+
<xsd:element minOccurs="0" maxOccurs="1" name="datapoints">
|
104
|
+
<xsd:complexType>
|
105
|
+
<xsd:sequence>
|
106
|
+
<xsd:element minOccurs="0" maxOccurs="unbounded" name="value">
|
107
|
+
<xsd:complexType>
|
108
|
+
<xsd:simpleContent>
|
109
|
+
<xsd:extension base="xsd:string">
|
110
|
+
<xsd:attribute name="at" type="xsd:dateTime" use="optional" />
|
111
|
+
</xsd:extension>
|
112
|
+
</xsd:simpleContent>
|
113
|
+
</xsd:complexType>
|
114
|
+
</xsd:element>
|
115
|
+
</xsd:sequence>
|
116
|
+
</xsd:complexType>
|
117
|
+
</xsd:element>
|
118
|
+
<xsd:element minOccurs="0" maxOccurs="1" name="unit">
|
119
|
+
<xsd:complexType>
|
120
|
+
<xsd:simpleContent>
|
121
|
+
<xsd:extension base="xsd:string">
|
122
|
+
<xsd:attribute name="symbol" type="xsd:string" use="optional">
|
123
|
+
</xsd:attribute>
|
124
|
+
<xsd:attribute name="type" use="optional">
|
125
|
+
<xsd:simpleType>
|
126
|
+
<xsd:restriction base="xsd:string">
|
127
|
+
<xsd:enumeration value="basicSI" />
|
128
|
+
<xsd:enumeration value="derivedSI" />
|
129
|
+
<xsd:enumeration value="conversionBasedUnits" />
|
130
|
+
<xsd:enumeration value="derivedUnits" />
|
131
|
+
<xsd:enumeration value="contextDependentUnits" />
|
132
|
+
</xsd:restriction>
|
133
|
+
</xsd:simpleType>
|
134
|
+
</xsd:attribute>
|
135
|
+
</xsd:extension>
|
136
|
+
</xsd:simpleContent>
|
137
|
+
</xsd:complexType>
|
138
|
+
</xsd:element>
|
139
|
+
</xsd:sequence>
|
140
|
+
<xsd:attribute name="id" type="xsd:nonNegativeInteger" use="required" />
|
141
|
+
</xsd:complexType>
|
142
|
+
</xsd:element>
|
143
|
+
</xsd:sequence>
|
144
|
+
<xsd:attribute name="updated" use="optional">
|
145
|
+
<xsd:simpleType>
|
146
|
+
<xsd:restriction base="xsd:dateTime" />
|
147
|
+
</xsd:simpleType>
|
148
|
+
</xsd:attribute>
|
149
|
+
<xsd:attribute name="creator" use="optional">
|
150
|
+
<xsd:simpleType>
|
151
|
+
<xsd:restriction base="xsd:string" />
|
152
|
+
</xsd:simpleType>
|
153
|
+
</xsd:attribute>
|
154
|
+
<xsd:attribute name="id" type="xsd:nonNegativeInteger" use="optional" />
|
155
|
+
</xsd:complexType>
|
156
|
+
</xsd:element>
|
157
|
+
</xsd:choice>
|
158
|
+
<xsd:attribute name="version" use="optional">
|
159
|
+
<xsd:simpleType>
|
160
|
+
<xsd:restriction base="xsd:string">
|
161
|
+
<xsd:enumeration value="0.5.1" />
|
162
|
+
</xsd:restriction>
|
163
|
+
</xsd:simpleType>
|
164
|
+
</xsd:attribute>
|
165
|
+
</xsd:complexType>
|
166
|
+
</xsd:element>
|
167
|
+
</xsd:schema>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<eeml xmlns="http://www.eeml.org/xsd/0.5.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="0.5.2" xsi:schemaLocation="http://www.eeml.org/xsd/0.5.2 http://www.eeml.org/xsd/0.5.2/0.5.2.xsd">
|
2
|
+
<environment>
|
3
|
+
<title>Pachube Office environment</title>
|
4
|
+
<data id="0" />
|
5
|
+
<data id="1" />
|
6
|
+
</environment>
|
7
|
+
</eeml>
|
8
|
+
|
data/test/test_environment.rb
CHANGED
@@ -18,7 +18,7 @@ class TestEnvironment < Test::Unit::TestCase
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
|
21
|
+
# Create an object from an eeml document
|
22
22
|
test 'creating Env obj - attrs' do
|
23
23
|
env = create_env_from_xml_file_one
|
24
24
|
|
@@ -36,6 +36,13 @@ class TestEnvironment < Test::Unit::TestCase
|
|
36
36
|
assert_equal('http://example.com/creator/', env.creator)
|
37
37
|
end
|
38
38
|
|
39
|
+
test "creating Env object from some 0.5.2 eeml" do
|
40
|
+
env = create_env_from_eeml_052
|
41
|
+
|
42
|
+
# simple text nodes available
|
43
|
+
assert_equal("Pachube Office environment", env.title)
|
44
|
+
end
|
45
|
+
|
39
46
|
test 'location parses ok' do
|
40
47
|
env = create_env_from_xml_file_one
|
41
48
|
|
@@ -764,4 +771,8 @@ CSV
|
|
764
771
|
return nil if json.nil?
|
765
772
|
json.gsub(/","/, '"' + "\n" + '"').sort
|
766
773
|
end
|
774
|
+
|
775
|
+
def create_env_from_eeml_052
|
776
|
+
return create_env_from_xml_file("environment_minimal_052.xml")
|
777
|
+
end
|
767
778
|
end
|
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: 89
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
9
|
+
- 35
|
10
|
+
version: 0.0.35
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Neill Bogie
|
@@ -17,16 +18,18 @@ autorequire:
|
|
17
18
|
bindir: bin
|
18
19
|
cert_chain: []
|
19
20
|
|
20
|
-
date: 2011-02-
|
21
|
+
date: 2011-02-24 00:00:00 +00:00
|
21
22
|
default_executable:
|
22
23
|
dependencies:
|
23
24
|
- !ruby/object:Gem::Dependency
|
24
25
|
name: libxml-ruby
|
25
26
|
prerelease: false
|
26
27
|
requirement: &id001 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
27
29
|
requirements:
|
28
30
|
- - ">="
|
29
31
|
- !ruby/object:Gem::Version
|
32
|
+
hash: 21
|
30
33
|
segments:
|
31
34
|
- 1
|
32
35
|
- 1
|
@@ -38,9 +41,11 @@ dependencies:
|
|
38
41
|
name: yajl-ruby
|
39
42
|
prerelease: false
|
40
43
|
requirement: &id002 !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
41
45
|
requirements:
|
42
46
|
- - ">="
|
43
47
|
- !ruby/object:Gem::Version
|
48
|
+
hash: 19
|
44
49
|
segments:
|
45
50
|
- 0
|
46
51
|
- 7
|
@@ -52,9 +57,11 @@ dependencies:
|
|
52
57
|
name: lightcsv
|
53
58
|
prerelease: false
|
54
59
|
requirement: &id003 !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
55
61
|
requirements:
|
56
62
|
- - ">="
|
57
63
|
- !ruby/object:Gem::Version
|
64
|
+
hash: 19
|
58
65
|
segments:
|
59
66
|
- 0
|
60
67
|
- 2
|
@@ -72,6 +79,7 @@ extra_rdoc_files:
|
|
72
79
|
- LICENSE
|
73
80
|
- README
|
74
81
|
files:
|
82
|
+
- .gitignore
|
75
83
|
- CHANGELOG
|
76
84
|
- LICENSE
|
77
85
|
- Manifest
|
@@ -93,7 +101,9 @@ files:
|
|
93
101
|
- lib/eeml/json_environment_parser_v100.rb
|
94
102
|
- lib/eeml/libxml_eeml_parser_v005.rb
|
95
103
|
- lib/eeml/libxml_eeml_parser_v051.rb
|
104
|
+
- lib/eeml/libxml_eeml_parser_v052.rb
|
96
105
|
- schemas/eeml/0.5.1.xsd
|
106
|
+
- schemas/eeml/0.5.2.xsd
|
97
107
|
- schemas/eeml/005.xsd
|
98
108
|
- test/data/.gitignore
|
99
109
|
- test/data/complete_namespaced.xml
|
@@ -112,6 +122,7 @@ files:
|
|
112
122
|
- test/data/doc_2_expected.json
|
113
123
|
- test/data/eeml_datastream_051.xml
|
114
124
|
- test/data/environment_minimal_051.xml
|
125
|
+
- test/data/environment_minimal_052.xml
|
115
126
|
- test/data/environment_tags.json
|
116
127
|
- test/data/environment_tags.xml
|
117
128
|
- test/data/list.xml
|
@@ -130,36 +141,40 @@ homepage:
|
|
130
141
|
licenses: []
|
131
142
|
|
132
143
|
post_install_message:
|
133
|
-
rdoc_options:
|
134
|
-
|
144
|
+
rdoc_options:
|
145
|
+
- --charset=UTF-8
|
135
146
|
require_paths:
|
136
147
|
- lib
|
137
148
|
required_ruby_version: !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
138
150
|
requirements:
|
139
151
|
- - ">="
|
140
152
|
- !ruby/object:Gem::Version
|
153
|
+
hash: 3
|
141
154
|
segments:
|
142
155
|
- 0
|
143
156
|
version: "0"
|
144
157
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
158
|
+
none: false
|
145
159
|
requirements:
|
146
160
|
- - ">="
|
147
161
|
- !ruby/object:Gem::Version
|
162
|
+
hash: 3
|
148
163
|
segments:
|
149
164
|
- 0
|
150
165
|
version: "0"
|
151
166
|
requirements: []
|
152
167
|
|
153
168
|
rubyforge_project:
|
154
|
-
rubygems_version: 1.3.
|
169
|
+
rubygems_version: 1.3.7
|
155
170
|
signing_key:
|
156
171
|
specification_version: 3
|
157
172
|
summary: Simple little library for programmatically manipulating EEML documents.
|
158
173
|
test_files:
|
159
|
-
- test/
|
160
|
-
- test/
|
174
|
+
- test/test_libxml_eeml_parser_v005.rb
|
175
|
+
- test/test_libxml_test_helper.rb
|
161
176
|
- test/test_csv_parser_v2.rb
|
177
|
+
- test/test_csv_parser_v1.rb
|
162
178
|
- test/test_environment.rb
|
179
|
+
- test/libxml_test_helper.rb
|
163
180
|
- test/test_helper.rb
|
164
|
-
- test/test_libxml_eeml_parser_v005.rb
|
165
|
-
- test/test_libxml_test_helper.rb
|