argos-ruby 1.1.3.1 → 1.2.0

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.
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}"