argos-ruby 1.1.3.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- YzBiNzk2MjU0YWQ0NGViYzk2ZjMzMjZhMTBjYjgzNjY4M2U2MzdkMg==
5
- data.tar.gz: !binary |-
6
- ZjNhYTliZDM2ZWNjOTg4OWFlMzEyYjZiMmYzMjVkZDY0MDc4MmUzMA==
2
+ SHA1:
3
+ metadata.gz: c8fc28465dbe802bf2961bea1d3913654d4969b9
4
+ data.tar.gz: fb761e384ab9d9761bd601c641fcbd87e0d2525a
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- ZDI3YzNiYTlhMmY2MmU4NGMwOTQxZThjNzc5NjgwZjc2NDAzNjgxNzYzNDQw
10
- ZTVmZWM5ZTc3ZmM0OWNkZDE2ZTNiZGI0ZTc2NzFmY2UzOTM5ZGRjYWYxOGM4
11
- NmVmOWU3ODAxZDdlOWVkNmJlODg3MDVhNGJmMWQ0NTA1NzJlZjY=
12
- data.tar.gz: !binary |-
13
- MjlkNmM4MDhmMDZhNGIwY2FlNWU2MTYxNmQ1MWJlMTUxNDEyZDYxMjY0MThh
14
- MmZjNGU3NTgyOGE4MjZhNTUwNGVlZDI1OTYyYjEwYjQ3MmQxMWIxMWE0NTQz
15
- NjQyYWI4Y2EwNDFjMWUwNzg1MjEyMjExZGUzOWZjYTdiMzQ3NGI=
6
+ metadata.gz: 74ac8e53f830ec8119d0339e9ea12c98f09640baf7992b1e3288c92d23f80ae13198a0bf32206ff0b047b2610c48403271d3f54db44145022f720f07297678ea
7
+ data.tar.gz: c4894a56bdae7a75c581f3dff27da1c2c91a88a1a67f58745c2755a6ba6bc5cbd7731d10d747715d9adfe12b9dfbaa3dbf4bc9eefbab734ca897583805551106
data/Gemfile CHANGED
@@ -4,12 +4,9 @@ gem "yajl-ruby", git: "git://github.com/brianmario/yajl-ruby.git"
4
4
  gem "uuidtools"
5
5
  gem "hashie", git: "git://github.com/intridea/hashie.git"
6
6
  #gem "json-schema", git: "git://github.com/hoxworth/json-schema.git"
7
- gem "savon", github: 'savonrb/savon'
7
+ gem "savon", github: "savonrb/savon", branch: "version3"
8
8
 
9
9
  group :development, :test do
10
- gem "thin"
11
- gem "shotgun"
12
10
  gem "rspec"
13
11
  gem "simplecov"
14
- gem "ruby-prof"
15
12
  end
data/README.md CHANGED
@@ -1,57 +1,46 @@
1
1
  # argos-ruby
2
2
 
3
- A Ruby library and command-line tool accessing data from the [Argos](http://www.argos-system.org) tracking system.
3
+ [argos-ruby](https://github.com/npolar/argos-ruby) contains tools for working with
4
+ [Argos](http://www.argos-system.org) satellite tracking data and services:
4
5
 
5
- ## argos-soap (webservice client)
6
+ * Parsers for Argos legacy ASCII (DS/DAT and DIAG/DIA files)
7
+ * SOAP web service client
8
+ * Web service download tool
9
+ * JSON conversion from ASCII and XML
6
10
 
7
- $ argos-soap --operations
8
- ```json
9
- ["getCsv","getStreamXml","getKml","getXml","getXsd","getPlatformList","getObsCsv","getObsXml"]
10
- ```
11
- **All programs**
12
- Data from all programs and all platforms are fetched by default
13
-
14
- $ argos-soap --operation=getXml > [getXml.xml](https://github.com/npolar/argos-ruby/blob/master/spec/argos/_soap/getXml.xml)
15
-
16
- $ argos-soap --operation=getXml --format=json > [getXml.json](https://github.com/npolar/argos-ruby/blob/master/spec/argos/_soap/getXml.json)
17
-
18
- $ argos-soap --operation=getKml > [getKml.xml](https://github.com/npolar/argos-ruby/blob/master/spec/argos/_soap/getKml.xml)
19
-
20
- $ argos-soap --operation=getCsv --format=text > [getCsv.csv](https://github.com/npolar/argos-ruby/blob/master/spec/argos/_soap/getCsv.csv)
21
-
22
- **Select program(s)**
23
- argos-soap --operation getXml --programNumber 9660
24
-
25
- **Select platformId(s)**
26
- $ argos-soap --operation getXml --platformId 81308
11
+ Developed by staff at the [Norwegian Polar Data Centre](http://data.npolar.no), [Norwegian Polar Institute](http://npolar.no).
27
12
 
13
+ ## Webservice
28
14
 
29
- **Authentication**
30
- Either set your credentials on the command line
31
- $ argos-soap --operation=getPlatformList --username=myusername --password=mypassword
32
- Or set environmental variables ARGOS_SOAP_USERNAME and ARGOS_SOAP_PASSWORD
33
-
34
- ## Argos file parsing
35
- ### DS/DIAG to JSON
36
- $ #
15
+ ```sh
16
+ $ argos-soap --download archive/tracking/CLS --username=USERNAME --password=PASSWORD --debug
17
+ $ argos-soap -o getXml --username=USERNAME --password=PASSWORD
18
+ ```
19
+ See [argos-soap](https://github.com/npolar/argos-ruby/wiki/argos-soap) for more usage examples.
37
20
 
38
- ## About
21
+ ### Legacy file parsing
39
22
 
40
- [argos-ruby](https://github.com/npolar/argos-ruby) was developed to parse [Argos](http://www.argos-system.org)
41
- satellite tracking data text files collected by the [Norwegian Polar Institute]
42
- (http://npolar.no/en) since 1989. Be warned, the Argos text file formats have changed over time. No promises are
43
- made that the library will work outside of Norway :).
23
+ ```sh
24
+ $ argos-ascii spec/argos/_ds/*.DAT
25
+ $ argos-ascii --action=source "spec/argos/_d*"
26
+ $ argos-ascii --filter='lambda {|d| d[:program] == 9660 and d[:platform] == 2189 }' spec/argos/_ds/990660_A.DAT
27
+ ```
28
+ The **source** action provides a metadata summary, list of programs, platforms, etc.
44
29
 
45
- Currently, the library parses Argos DS/DIAG files dating from August 1990 and onwards.
30
+ ### JSON (via XSLT)
31
+ ```sh
32
+ $ xsltproc lib/argos/_xslt/argos-json.xslt spec/argos/_soap/getXml.xml
33
+ ```
46
34
 
47
35
  ## Install
36
+ ```sh
48
37
  $ gem install argos-ruby
38
+ ```
49
39
 
50
40
  ## Links
51
-
52
41
  * https://github.com/npolar/api.npolar.no/wiki/Tracking-API-JSON
53
42
  * [Argos User's Manual](http://www.argos-system.org/manual/)
54
- * [Argos Web Service Interface Specification v1.5](http://www.argos-system.org/manual/argos_webservices-1_4.pdf)
43
+ * [Argos Web Service Interface Specification v1.4](http://www.argos-system.org/manual/argos_webservices-1_4.pdf)
55
44
  * http://alaska.usgs.gov/science/biology/spatial/
56
45
  * http://gis-lab.info/programs/argos/argos-manual-eng.html
57
-
46
+ * [CLS](http://www.cls.fr/welcome_en.html) - operates the Argos system
data/argos-ruby.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
12
12
  s.summary = %q{Argos satellite tracking library and command-line tools}
13
13
  s.description = %q{Argos (http://www.argos-system.org/) webservice client and Argos legacy file (DS/DAT and DIAG/DIA) parser.}
14
14
  s.license = "GPL-3.0"
15
- s.add_development_dependency "rspec"
15
+ s.add_development_dependency 'rspec', '~> 3'
16
16
  s.files = `git ls-files`.split("\n")
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
18
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
data/bin/argos-soap CHANGED
@@ -4,10 +4,12 @@
4
4
  # Ruby-based command line client for Argos' Soap webservice
5
5
  #
6
6
  # For more information:
7
- # $ ./bin/argos-soap --help
7
+ # $ argos-soap --help
8
8
  # https://github.com/npolar/argos-ruby/blob/master/README.md
9
9
 
10
- require_relative "../lib/argos"
11
- require_relative "../lib/argos/soap_command"
10
+ Dir.chdir(__dir__) do
11
+ require_relative "../lib/argos"
12
+ require_relative "../lib/argos/soap_command"
13
+ end
14
+ Argos::SoapCommand.run
12
15
 
13
- Argos::SoapCommand.run
@@ -0,0 +1,158 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
3
+
4
+ <!-- W3C specifications http://www.w3.org/TR/xmlschema-0 -->
5
+
6
+ <!-- DATA DECLARATION -->
7
+ <xs:element name="data">
8
+ <xs:complexType>
9
+ <xs:sequence>
10
+ <xs:element name="program" type="program" minOccurs="0" maxOccurs="unbounded"/>
11
+ <xs:element name="errors" type="errors" minOccurs="0"/>
12
+ </xs:sequence>
13
+ <xs:attribute name="version" type="xs:string"/>
14
+ </xs:complexType>
15
+ </xs:element>
16
+
17
+ <!-- PROGRAM DECLARATION -->
18
+ <xs:complexType name="program">
19
+ <xs:sequence>
20
+ <xs:element name="programNumber" type="xs:int" minOccurs="0"/>
21
+ <xs:element name ="platform" type="platform" minOccurs="0" maxOccurs="unbounded"/>
22
+ </xs:sequence>
23
+ </xs:complexType>
24
+
25
+ <!-- PLATFORM DECLARATION -->
26
+ <xs:complexType name="platform">
27
+ <xs:sequence>
28
+ <xs:element name="platformId" type="xs:int" minOccurs="0"/>
29
+ <xs:element name="platformType" type="xs:string" minOccurs="0"/>
30
+ <xs:element name="platformName" type="xs:string" minOccurs="0"/>
31
+ <xs:element name="platformModel" type="xs:string" minOccurs="0"/>
32
+ <xs:element name="platformHexId" type="xs:string" minOccurs="0"/>
33
+ <xs:element name ="satellitePass" type="satellitePass" minOccurs="0" maxOccurs="unbounded"/>
34
+ </xs:sequence>
35
+ </xs:complexType>
36
+
37
+ <!-- SATELLITE PASS DECLARATION -->
38
+ <xs:complexType name="satellitePass">
39
+ <xs:sequence>
40
+ <xs:element name="satellite" type="xs:string" minOccurs="0"/>
41
+ <xs:element name="bestMsgDate" type="xs:dateTime" minOccurs="0"/>
42
+ <!-- unit : second -->
43
+ <xs:element name="duration" type="xs:int" minOccurs="0"/>
44
+ <xs:element name="nbMessage" type="xs:int" minOccurs="0"/>
45
+ <xs:element name="message120" type="xs:int" minOccurs="0"/>
46
+ <!-- unit : dBm -->
47
+ <xs:element name="bestLevel" type="xs:int" minOccurs="0"/>
48
+ <!-- unit : Hertz -->
49
+ <xs:element name="frequency" type="xs:double" minOccurs="0"/>
50
+ <xs:element name="location" type="location" minOccurs="0"/>
51
+ <xs:element name ="message" type="message" minOccurs="0" maxOccurs="unbounded"/>
52
+ </xs:sequence>
53
+ </xs:complexType>
54
+
55
+ <!-- LOCATION DECLARATION -->
56
+ <xs:complexType name="location">
57
+ <xs:sequence>
58
+ <!-- GMT -->
59
+ <xs:element name="locationDate" type="xs:dateTime" minOccurs="0"/>
60
+ <!-- range : -90°..+90° -->
61
+ <xs:element name="latitude" type="xs:double" minOccurs="0"/>
62
+ <!-- range : -180°..+180° -->
63
+ <xs:element name="longitude" type="xs:double" minOccurs="0"/>
64
+ <!-- unit : meter -->
65
+ <xs:element name="altitude" type="xs:double" minOccurs="0"/>
66
+ <xs:element name="locationClass" type="xs:string" minOccurs="0"/>
67
+ <!-- unit : meter/second -->
68
+ <xs:element name="gpsSpeed" type="xs:float" minOccurs="0"/>
69
+ <!-- range : 0°..+360°, clockwise -->
70
+ <xs:element name="gpsHeading" type="xs:float" minOccurs="0"/>
71
+ <xs:element name="diagnostic" type="diagnostic" minOccurs="0"/>
72
+ </xs:sequence>
73
+ </xs:complexType>
74
+
75
+ <!-- DIAGNOSTIC DECLARATION -->
76
+ <xs:complexType name="diagnostic">
77
+ <xs:sequence>
78
+ <!-- range : -90°..+90° -->
79
+ <xs:element name="latitude2" type="xs:float" minOccurs="0"/>
80
+ <!-- range : -180°..+180° -->
81
+ <xs:element name="longitude2" type="xs:float" minOccurs="0"/>
82
+ <!-- unit : meter -->
83
+ <xs:element name="altitude2" type="xs:float" minOccurs="0"/>
84
+ <xs:element name="index" type="xs:int" minOccurs="0"/>
85
+ <xs:element name="nopc" type="xs:int" minOccurs="0"/>
86
+ <!-- unit : meter -->
87
+ <xs:element name="errorRadius" type="xs:float" minOccurs="0"/>
88
+ <!-- unit : meter -->
89
+ <xs:element name="semiMajor" type="xs:float" minOccurs="0"/>
90
+ <!-- unit : meter -->
91
+ <xs:element name="semiMinor" type="xs:float" minOccurs="0"/>
92
+ <!-- range 0°..180°, clockwise -->
93
+ <xs:element name="orientation" type="xs:float" minOccurs="0"/>
94
+ <xs:element name="hdop" type="xs:string" minOccurs="0"/>
95
+ </xs:sequence>
96
+ </xs:complexType>
97
+
98
+ <!-- MESSAGE DECLARATION -->
99
+ <xs:complexType name="message">
100
+ <xs:sequence>
101
+ <!-- GMT -->
102
+ <xs:element name="bestDate" type="xs:dateTime" minOccurs="0"/>
103
+ <xs:element name="compression" type="xs:int" minOccurs="0"/>
104
+ <xs:element name ="collect" type="collect" minOccurs="0" maxOccurs="unbounded"/>
105
+ <xs:element name ="format" type="format" minOccurs="0" maxOccurs="unbounded"/>
106
+ </xs:sequence>
107
+ </xs:complexType>
108
+
109
+ <!-- COLLECT DECLARATION -->
110
+ <xs:complexType name="collect">
111
+ <xs:sequence>
112
+ <xs:element name="type" type="xs:string" minOccurs="0"/>
113
+ <xs:element name="alarm" type="xs:string" minOccurs="0"/>
114
+ <xs:element name="concatenated" type="xs:string" minOccurs="0"/>
115
+ <!-- GMT -->
116
+ <xs:element name="date" type="xs:dateTime" minOccurs="0"/>
117
+ <!-- unit : dBm -->
118
+ <xs:element name="level" type="xs:float" minOccurs="0"/>
119
+ <!-- unit : Hertz -->
120
+ <xs:element name="doppler" type="xs:double" minOccurs="0"/>
121
+ <xs:element name="rawData" type="xs:string" minOccurs="0"/>
122
+ </xs:sequence>
123
+ </xs:complexType>
124
+
125
+
126
+ <!-- FORMAT DECLARATION -->
127
+ <xs:complexType name="format">
128
+ <xs:sequence>
129
+ <xs:element name="formatOrder" type="xs:int" minOccurs="0"/>
130
+ <xs:element name="formatName" type="xs:string" minOccurs="0"/>
131
+ <xs:element name ="sensor" type="sensor" minOccurs="0" maxOccurs="unbounded"/>
132
+ </xs:sequence>
133
+ </xs:complexType>
134
+
135
+ <!-- SENSOR DECLARATION -->
136
+ <xs:complexType name="sensor">
137
+ <xs:sequence>
138
+ <xs:element name="order" type="xs:int" minOccurs="0"/>
139
+ <xs:element name="name" type="xs:string" minOccurs="0"/>
140
+ <xs:element name="valueType" type="xs:string" minOccurs="0"/>
141
+ <xs:element name="value" type="xs:string" minOccurs="0"/>
142
+ <xs:element name="valueStr" type="xs:string" minOccurs="0"/>
143
+ </xs:sequence>
144
+ </xs:complexType>
145
+
146
+
147
+ <!-- ERRORS DECLARATION -->
148
+ <xs:complexType name="errors">
149
+ <xs:sequence>
150
+ <xs:element name ="error" type="xs:string" minOccurs="0" maxOccurs="unbounded">
151
+
152
+ </xs:element>
153
+ </xs:sequence>
154
+ </xs:complexType>
155
+
156
+ </xs:schema>
157
+
158
+
@@ -0,0 +1,81 @@
1
+ <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
2
+ <xsl:output omit-xml-declaration="yes" indent="yes"/>
3
+ <xsl:strip-space elements="*"/>
4
+ <!--
5
+ Transform Argos data XML to Tracking JSON (http://api.npolar.no/schema/tracking)
6
+
7
+ Usage:
8
+ xsltproc argos-json.xslt argos.xml
9
+
10
+ xsltproc argos-json.xslt - -stringparam filename "argos-2014-06-11-platform-129654.xml" argos-2014-06-11-platform-129654.xml
11
+
12
+ @todo param name system to force gps on known gps devices?
13
+ @todo test with errors
14
+
15
+ -->
16
+ <xsl:param name="filename" select="''"/>
17
+ <xsl:param name="npolar" select="'true'"/>
18
+
19
+
20
+ <xsl:template match="/">
21
+ [<xsl:for-each select="/data[number(@version) &lt; 2]/program/platform/satellitePass/message">
22
+
23
+ <xsl:variable name="programNumber" select="ancestor::program/programNumber" />
24
+ <xsl:variable name="platform" select="ancestor::program/platform" />
25
+ <xsl:variable name="satellitePass" select="parent::satellitePass" />
26
+ <xsl:variable name="location" select="$satellitePass/location" />
27
+
28
+ { "program": "<xsl:value-of select="$programNumber"/>",
29
+ "platform": "<xsl:value-of select="$platform/platformId"/>",
30
+ "platform_type": "<xsl:value-of select="$platform/platformType"/>",
31
+ "platform_model": "<xsl:value-of select="$platform/platformModel"/>",
32
+ "platform_name": "<xsl:value-of select="$platform/platformName"/>",
33
+ "platform_id": "<xsl:value-of select="$platform/platformHexId"/>",
34
+ "latitude": <xsl:choose><xsl:when test="number($location/latitude) = $location/latitude"><xsl:value-of select="$location/latitude"/></xsl:when><xsl:otherwise>null</xsl:otherwise></xsl:choose>,
35
+ "longitude": <xsl:choose><xsl:when test="number($location/longitude) = $location/longitude"><xsl:value-of select="$location/longitude"/></xsl:when><xsl:otherwise>null</xsl:otherwise></xsl:choose>,
36
+ "altitude": <xsl:choose><xsl:when test="number($location/altitude) = $location/altitude"><xsl:value-of select="$location/altitude"/></xsl:when><xsl:otherwise>null</xsl:otherwise></xsl:choose>,
37
+ "measured": "<xsl:value-of select="$satellitePass/bestMsgDate"/>",
38
+ "satellite": "<xsl:value-of select="$satellitePass/satellite"/>",
39
+ "duration": <xsl:value-of select="$satellitePass/duration"/>,
40
+ "messages": <xsl:value-of select="$satellitePass/nbMessage"/>,
41
+ "messages_120dB": <xsl:choose><xsl:when test="number($satellitePass/message120) = $satellitePass/message120"><xsl:value-of select="$satellitePass/message120"/></xsl:when><xsl:otherwise>null</xsl:otherwise></xsl:choose>,
42
+ "best_level": <xsl:choose><xsl:when test="number($satellitePass/bestLevel) = $satellitePass/bestLevel"><xsl:value-of select="$satellitePass/bestLevel"/></xsl:when><xsl:otherwise>null</xsl:otherwise></xsl:choose>,
43
+ "frequency": <xsl:choose><xsl:when test="number($satellitePass/frequency) = $satellitePass/frequency"><xsl:value-of select="$satellitePass/frequency"/></xsl:when><xsl:otherwise>null</xsl:otherwise></xsl:choose>,
44
+ "positioned": <xsl:choose><xsl:when test="$location/locationDate != ''">"<xsl:value-of select="$location/locationDate"/>"</xsl:when><xsl:otherwise>null</xsl:otherwise></xsl:choose>,
45
+ "lc": <xsl:choose><xsl:when test="$location/locationClass != ''">"<xsl:value-of select="$location/locationClass"/>"</xsl:when><xsl:otherwise>null</xsl:otherwise></xsl:choose>,<xsl:choose><xsl:when test="$location/diagnostic">
46
+ "lc_index": <xsl:choose><xsl:when test="number($location/diagnostic/index) = $location/diagnostic/index"><xsl:value-of select="$location/diagnostic/index"/></xsl:when><xsl:otherwise>null</xsl:otherwise></xsl:choose>,
47
+ "latitude2": <xsl:value-of select="$location/diagnostic/latitude2"/>,
48
+ "longitude2": <xsl:value-of select="$location/diagnostic/longitude2"/>,
49
+ "altitude2": <xsl:value-of select="$location/diagnostic/altitude2"/>,
50
+ "nopc": <xsl:value-of select="$location/diagnostic/nopc"/>,
51
+ "error_radius": <xsl:value-of select="$location/diagnostic/errorRadius"/>,
52
+ "semi_major": <xsl:value-of select="$location/diagnostic/semiMajor"/>,
53
+ "semi_minor": <xsl:value-of select="$location/diagnostic/semiMinor"/>,
54
+ "speed": <xsl:choose><xsl:when test="number($location/diagnostic/gpsSpeed) = $location/diagnostic/gpsSpeed"><xsl:value-of select="$location/diagnostic/gpsSpeed"/></xsl:when><xsl:otherwise>null</xsl:otherwise></xsl:choose>,
55
+ "heading": <xsl:choose><xsl:when test="number($location/diagnostic/gpsHeading) = $location/diagnostic/gpsHeading"><xsl:value-of select="$location/diagnostic/gpsHeading"/></xsl:when><xsl:otherwise>null</xsl:otherwise></xsl:choose>,
56
+ "orientation": <xsl:value-of select="$location/diagnostic/orientation"/>,
57
+ "hdop": <xsl:value-of select="$location/diagnostic/hdop"/>,</xsl:when></xsl:choose>
58
+ "row": <xsl:value-of select="position()"/>,
59
+ "total": <xsl:value-of select="count(//message)"/>,
60
+ "file": "<xsl:value-of select="$filename"/>",
61
+ "identical": <xsl:value-of select="compression"/>,
62
+ "sensor_data": [<xsl:for-each select="format/sensor/value">"<xsl:value-of select="."/>"<xsl:choose><xsl:when test="position() &lt; last()">,</xsl:when></xsl:choose></xsl:for-each>],
63
+ "sensor_hex": "<xsl:value-of select="collect/rawData"/>",
64
+ "sensor": [<xsl:for-each select="format/sensor">{"name": "<xsl:value-of select="name"/>", "value": "<xsl:value-of select="value|valueStr"/>", "value_type": "<xsl:value-of select="valueType"/>", "order": <xsl:value-of select="order"/> }<xsl:choose><xsl:when test="position() &lt; last()">, </xsl:when></xsl:choose></xsl:for-each>],
65
+ "doppler": <xsl:value-of select="collect/doppler"/>,
66
+ "level": <xsl:value-of select="collect/level"/>,
67
+ "collects": <xsl:value-of select="count(collect)"/>,
68
+ "formats": <xsl:value-of select="count(format)"/>,
69
+ "collect": [<xsl:for-each select="collect">{ "level": <xsl:value-of select="level"/>, "type": "<xsl:value-of select="type"/>", "alarm": "<xsl:value-of select="alarm"/>", "concatenated": "<xsl:value-of select="concatenated"/>", "hex": "<xsl:value-of select="rawData"/>", "doppler": <xsl:value-of select="doppler"/>, "measured": "<xsl:value-of select="date"/>" }<xsl:choose><xsl:when test="position() &lt; last()">,</xsl:when></xsl:choose></xsl:for-each>],
70
+ "format": [<xsl:for-each select="format">{ "order": <xsl:value-of select="formatOrder"/>, "name": "<xsl:value-of select="formatName"/>" }<xsl:choose><xsl:when test="position() &lt; last()">,</xsl:when></xsl:choose></xsl:for-each>]<xsl:choose><xsl:when test="$npolar = 'true'">,
71
+ "schema": "http://api.npolar.no/schema/tracking",
72
+ "collection": "tracking",
73
+ "technology": "argos",
74
+ "system": "<xsl:choose><xsl:when test="number($location/diagnostic/gpsSpeed) = $location/diagnostic/gpsSpeed">gps</xsl:when><xsl:otherwise>argos</xsl:otherwise></xsl:choose>",
75
+ "parser": "argos-json.xslt",
76
+ "type": "xml"</xsl:when></xsl:choose><xsl:choose><xsl:when test="count(/data/errors/error) &gt; 0">,
77
+ "warn": [<xsl:for-each select="/data/errors/error">"<xsl:value-of select="."/> (argos webservice error code <xsl:value-of select="@code"/>)"<xsl:choose><xsl:when test="position() &lt; last()">,</xsl:when></xsl:choose></xsl:for-each>]</xsl:when></xsl:choose>}<xsl:choose><xsl:when test="position() &lt; last()">,</xsl:when></xsl:choose>
78
+ </xsl:for-each>]
79
+ </xsl:template>
80
+
81
+ </xsl:stylesheet>
@@ -1,6 +1,8 @@
1
1
  require "fileutils"
2
2
  require "logger"
3
3
  require "time"
4
+ require "digest"
5
+ require "nokogiri"
4
6
 
5
7
  module Argos
6
8
 
@@ -11,17 +13,22 @@ module Argos
11
13
  # /{archive}/{year}/program-{programNumber}/platform-{platformId}/argos-{YYYY-MM-DD}-platform-{platformId}.[xml|csv]
12
14
  #
13
15
  # Command line:
14
- # $ ./bin/argos-soap --download /mnt/tracking/ws-argos.cls.fr --username=xyz --password=123
16
+ # $ ./bin/argos-soap --download /tmp/tracking/ws-argos.cls.fr --username=xyz --password=123 --debug
17
+ # Crontab example:
18
+ # 27 3 * * * source /home/argos/.rvm/environments/default && argos-soap --download /var/ws-argos.cls.fr --username=user --password=pw
19
+
15
20
 
16
21
  class Download
17
22
 
18
23
  def self.download(username, password, archive, log, days=20)
19
24
 
25
+ log.debug "Starting download of Argos XML to #{archive}"
26
+
20
27
  soap = Argos::Soap.new({username: username, password: password})
21
28
  soap.log = log
22
29
 
23
30
  programs = soap.programs
24
-
31
+ log.debug "Programs for #{username}: #{programs.to_json}"
25
32
  year = DateTime.now.year
26
33
 
27
34
  soap.getPlatformList["data"]["program"].each do |program|
@@ -29,9 +36,8 @@ module Argos
29
36
  soap.programNumber = programNumber
30
37
 
31
38
  platforms = soap.platforms
32
- log.debug "Program: #{program["programNumber"]}, #{platforms.size} platform(s)"
33
39
 
34
- program["platform"].select {|platform|
40
+ active = program["platform"].select {|platform|
35
41
 
36
42
  lastCollectDate = DateTime.parse(platform["lastCollectDate"])
37
43
  lastLocationDate = DateTime.parse(platform["lastLocationDate"])
@@ -40,13 +46,24 @@ module Argos
40
46
 
41
47
  (lastCollectDate > twentydays or lastLocationDate > twentydays)
42
48
 
43
- }.each_with_index do | platform, idx |
49
+ }
50
+
51
+
52
+ inactive = program["platform"] - active
53
+
54
+ active.each_with_index do |a,m|
55
+ log.debug "Active [#{m+1}/#{active.size}]: #{a.reject{|k,v| k =~ /location/i }.to_json}"
56
+ end
57
+ inactive.each_with_index do |i,n|
58
+ log.debug "Inactive [#{n+1}/#{inactive.size}]: #{i.reject{|k,v| k =~ /location/i }.to_json}"
59
+ end
60
+ active.each_with_index do | platform, idx |
44
61
 
45
62
 
46
63
  platformId = platform["platformId"]
47
64
  soap.platformId = platformId
48
65
 
49
- log.debug "Program: #{programNumber}, platform: #{platformId}, lastCollectDate: #{platform["lastCollectDate"]}"
66
+ log.debug "About to download program: #{programNumber}, platform: #{platformId} [#{idx+1}/#{active.size}], lastCollectDate: #{platform["lastCollectDate"]}"
50
67
 
51
68
  20.downto(1) do |daysago|
52
69
 
@@ -58,27 +75,48 @@ module Argos
58
75
  soap.period = {startDate: "#{date}T00:00:00Z", endDate: "#{date}T23:59:59.999Z"}
59
76
  soap.getXml
60
77
 
61
-
62
78
  FileUtils.mkdir_p(destination)
63
79
  filename = destination+"/argos-#{date}-platform-#{platformId}.xml"
64
-
65
- File.open(filename, "wb") { |file| file.write(soap.xml)}
66
- log.debug "Saved #{filename}"
67
80
 
68
- soap.getCsv
81
+ if File.exists? filename
82
+ existing_sha1 = Digest::SHA1.file(filename).hexdigest
83
+ existing_errors = Argos::Soap.new.validate(File.read(filename))
84
+ if existing_errors.any?
85
+ log.error "Validation error for existing data #{filename} (#{File.size(filename)} bytes): #{existing_errors.uniq.to_json}"
86
+ end
87
+ #log.debug "Keeping existing file #{filename} from #{File.mtime(filename)}, fresh data is identical"
88
+ end
89
+
90
+ new_xml_ng = Nokogiri::XML(soap.xml, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS | Nokogiri::XML::ParseOptions::NOCDATA | Nokogiri::XML::ParseOptions::STRICT)
91
+ new_xml = new_xml_ng.canonicalize
92
+ new_sha1 = Digest::SHA1.hexdigest(new_xml)
69
93
 
70
- File.open(filename.gsub(/xml$/, "csv"), "wb") { |file| file.write(soap.text)}
94
+ if existing_sha1.nil? or existing_errors.any? or existing_sha1 != new_sha1
95
+
96
+ if errors = Argos::Soap.new.validate(new_xml_ng).any?
97
+ raise "Failed XML schema validation"
98
+ else
99
+ File.open(filename, "wb") { |file| file.write(new_xml)}
100
+ log.debug "Validated and saved new data: #{filename}"
101
+ end
71
102
 
103
+ end
104
+ log.debug "Day -#{daysago}: #{date}: #{new_xml_ng.xpath("//message").size} message(s) (program #{programNumber}, platform #{platformId})"
72
105
  rescue Argos::NodataException
73
106
  # noop
107
+ log.debug "Day -#{daysago}: #{date}: No data for (program #{programNumber}, platform #{platformId})"
74
108
  rescue => e
75
109
  log.error e
76
110
  end
77
111
 
78
112
  end
113
+
114
+ log.debug "Completed download of #{platformId}"
115
+
79
116
  end
117
+ log.debug "Completed download for #{username}"
80
118
  end
81
119
  end
82
120
 
83
121
  end
84
- end
122
+ end
data/lib/argos/soap.rb CHANGED
@@ -18,8 +18,7 @@ end
18
18
  module Argos
19
19
  class Soap
20
20
 
21
- # A "simple" Soap client for Argos-system satellite tracking webservice
22
- # http://wanderingbarque.com/nonintersecting/2006/11/15/the-s-stands-for-simple/
21
+ # A [simple](http://wanderingbarque.com/nonintersecting/2006/11/15/the-s-stands-for-simple/) Soap client for the Argos satellite tracking webservice operated by CLS
23
22
 
24
23
  # client [Savon] (version 3)
25
24
  # request [String] Soap:Envelope (XML request body)
@@ -244,7 +243,6 @@ module Argos
244
243
  platformListPrograms.each do |program|
245
244
  platforms += program["platform"].map {|p| p["platformId"].to_i}
246
245
  end
247
-
248
246
  platforms
249
247
  end
250
248
 
@@ -283,6 +281,18 @@ module Argos
283
281
  client.services
284
282
  end
285
283
 
284
+ def schema
285
+ Nokogiri::XML::Schema(File.read("#{__dir__}/_xsd/argos-data.xsd"))
286
+ end
287
+
288
+ def validate(xml)
289
+ if xml.is_a? String
290
+ xml = Nokogiri.XML(xml)
291
+ end
292
+ schema.validate(xml)
293
+
294
+ end
295
+
286
296
  # @return [String]
287
297
  def text
288
298
  @text||=""
@@ -336,6 +346,7 @@ module Argos
336
346
  end
337
347
 
338
348
  # Handle errors
349
+
339
350
  ng = Nokogiri.XML(xml)
340
351
  ng.xpath("/data/errors/error").each do | error |
341
352
  if error.key?("code")
@@ -351,11 +362,18 @@ module Argos
351
362
  end
352
363
  end
353
364
 
354
- # Validation
355
- # Validation against XSD does not work: ["Element 'data': No matching global declaration available for the validation root."]
356
- # schema = Nokogiri::XML::Schema(File.read("/tmp/argos-data.xsd"))
357
- # v = schema.validate(ng)
365
+ # Validation - only :getXml
366
+ if [:getXml].include? op_sym
367
+ # Validation against getXSD schema does not work: ["Element 'data': No matching global declaration available for the validation root."]
368
+ # See https://github.com/npolar/argos-ruby/commit/219e4b3761e5265f8f9e8b924bcfc23607902428 for the fix
369
+ schema = Nokogiri::XML::Schema(File.read("#{__dir__}/_xsd/argos-data.xsd"))
370
+ v = schema.validate(ng)
371
+ if v.any?
372
+ log.debug "#{v.size} errors: #{v.map{|v|v.to_s}.uniq.to_json}"
373
+ end
374
+ end
358
375
 
376
+
359
377
  # Convert XML to Hash
360
378
  nori = Nori.new
361
379
  nori.parse(xml)
@@ -117,7 +117,7 @@ module Argos
117
117
  end
118
118
  end
119
119
 
120
- opts.on("--download=archive", "Download") do |archive|
120
+ opts.on("--download=/path/to/archive", "Download") do |archive|
121
121
  @param[:archive] = archive
122
122
  end
123
123
 
@@ -178,7 +178,7 @@ module Argos
178
178
  else
179
179
  raise ArgumentError, "Unspported operation: #{param[:operation]}"
180
180
  end
181
- puts output
181
+ puts output.to_s
182
182
 
183
183
  rescue NodataException
184
184
  log.debug output
@@ -216,8 +216,7 @@ module Argos
216
216
  when :raw
217
217
  soap.raw
218
218
  when :xml
219
- # Return XML with parameter and time in trailing comment
220
- soap.xml+xml_trailer
219
+ soap.xml+"\n"
221
220
  else
222
221
  raise ArgumentError, "Unknown format: #{format}"
223
222
  end
@@ -236,9 +235,9 @@ module Argos
236
235
  [:getCsv, :getStreamXml, :getKml, :getXml, :getXsd, :getPlatformList, :getObsCsv, :getObsXml]
237
236
  end
238
237
 
239
- def xml_trailer
240
- "<!-- #{Argos.library_version} #{param.reject {|k,v| k =~ /^password$/}.to_json} now: #{Time.now.utc.xmlschema} -->"
241
- end
242
-
238
+ #def xml_trailer
239
+ # "<!-- #{Argos.library_version} #{param.reject {|k,v| k =~ /^password$/}.to_json} now: #{Time.now.utc.xmlschema} -->\n"
240
+ #end
241
+ #
243
242
  end
244
243
  end
data/lib/argos.rb CHANGED
@@ -25,7 +25,7 @@ require_relative "argos/download"
25
25
  #
26
26
  # For information about Argos, see: http://www.argos-system.org
27
27
  module Argos
28
- VERSION = "1.1.3.1"
28
+ VERSION = "1.2.0"
29
29
 
30
30
  def self.library_version
31
31
  "argos-ruby-#{VERSION}"