Skip to content
Snippets Groups Projects
Unverified Commit 491152bb authored by David Hoese's avatar David Hoese
Browse files

Add basic XML format for data API

parent 2e8b79ed
Branches
No related tags found
No related merge requests found
...@@ -2,7 +2,6 @@ import logging ...@@ -2,7 +2,6 @@ import logging
from xml.dom.minidom import Document from xml.dom.minidom import Document
from datetime import datetime, timedelta from datetime import datetime, timedelta
from metobsapi.queryInflux import query from metobsapi.queryInflux import query
from io import StringIO
import pandas as pd import pandas as pd
from flask import render_template, jsonify, Response from flask import render_template, jsonify, Response
from flask_json import as_json_p from flask_json import as_json_p
...@@ -110,10 +109,15 @@ def handle_csv(frame, symbols, epoch, sep=',', **kwargs): ...@@ -110,10 +109,15 @@ def handle_csv(frame, symbols, epoch, sep=',', **kwargs):
symbols=sep.join(str(x) for x in row.values)) symbols=sep.join(str(x) for x in row.values))
data_lines.append(line) data_lines.append(line)
if not epoch:
epoch_str = '%Y-%m-%dT%H:%M:%SZ'
else:
epoch_str = data_responses.epoch_translation[epoch] + ' since epoch (1970-01-01 00:00:00)'
output = output.format( output = output.format(
message='', message='',
num_results=frame.shape[0], num_results=frame.shape[0],
epoch_str=data_responses.epoch_translation.get(epoch, 'YYYY-MM-DDTHH:MM:SSZ'), epoch_str=epoch_str,
symbol_list=sep.join(symbols), symbol_list=sep.join(symbols),
symbol_data="\n".join(data_lines), symbol_data="\n".join(data_lines),
) )
...@@ -152,67 +156,47 @@ def handle_json(frame, symbols, epoch, order='columns', **kwargs): ...@@ -152,67 +156,47 @@ def handle_json(frame, symbols, epoch, order='columns', **kwargs):
def handle_xml(frame, symbols, epoch, sep=',', **kwargs): def handle_xml(frame, symbols, epoch, sep=',', **kwargs):
doc = Document() doc = Document()
header = 'metobs' header = 'metobs'
timeStamps = list(frame.columns.values)
head = doc.createElement(header) head = doc.createElement(header)
head.setAttribute('status', 'success') head.setAttribute('status', 'success')
head.setAttribute('code', '200') head.setAttribute('code', '200')
head.setAttribute('message', '') head.setAttribute('message', '')
head.setAttribute('num_results', str(len(timeStamps))) head.setAttribute('num_results', str(frame.shape[0]))
head.setAttribute('seperator', sep) head.setAttribute('seperator', sep)
doc.appendChild(head) doc.appendChild(head)
columns_elem = doc.createElement('symbols')
stampElt = doc.createElement('timestamp') time_elem = doc.createElement('symbol')
time_elem.setAttribute('name', 'time')
time_elem.setAttribute('short_name', 'time')
if not epoch: if not epoch:
stampElt.setAttribute('format', '%Y-%m-%dT%H:%M:%SZ') time_elem.setAttribute('format', '%Y-%m-%dT%H:%M:%SZ')
else: else:
stampElt.setAttribute('format', data_responses.epoch_translation[epoch] + ' since epoch (1970-01-01 00:00:00)') time_elem.setAttribute('format', data_responses.epoch_translation[epoch] + ' since epoch (1970-01-01 00:00:00)')
columns_elem.appendChild(time_elem)
dateStrings = StringIO()
for c in frame.columns:
first = 0 col_elem = doc.createElement('symbol')
col_elem.setAttribute('name', c)
for dateString in timeStamps: parts = c.split('.')
if first == 0: col_elem.setAttribute('short_name', parts[2])
dateStrings.write(dateString) col_elem.setAttribute('site', parts[0])
first = 1 col_elem.setAttribute('inst', parts[1])
columns_elem.appendChild(col_elem)
else: head.appendChild(columns_elem)
dateStrings.write(sep + dateString)
data_elem = doc.createElement('data')
stamp_content = doc.createTextNode(dateStrings.getvalue()) for t, row in frame.iterrows():
stampElt.appendChild(stamp_content) row_elem = doc.createElement('row')
head.appendChild(stampElt) row_elem.appendChild(doc.createTextNode(str(t)))
for point in row:
frame = frame.transpose() row_elem.appendChild(doc.createTextNode(str(point)))
data_elem.appendChild(row_elem)
for symbol in symbols: head.appendChild(data_elem)
first = 0
# txt = doc.toprettyxml(indent=" ", encoding="utf-8")
dataStrings = StringIO() txt = doc.toxml(encoding="utf-8")
dataElt = doc.createElement('data')
dataElt.setAttribute('symbol', symbol)
dataElt.setAttribute('site', site)
dataElt.setAttribute('inst', inst)
dataList = frame[symbol]
for data in dataList:
if first == 0:
dataStrings.write(str(data))
first = 1
else:
dataStrings.write(sep + str(data))
symbol_content = doc.createTextNode(dataStrings.getvalue())
dataElt.appendChild(symbol_content)
head.appendChild(dataElt)
txt = doc.toprettyxml(indent=" ", encoding="utf-8")
return Response(txt, mimetype='text/xml') return Response(txt, mimetype='text/xml')
...@@ -297,7 +281,7 @@ def modify_data(fmt, begin, end, site, inst, symbols, interval, ...@@ -297,7 +281,7 @@ def modify_data(fmt, begin, end, site, inst, symbols, interval,
try: try:
influx_symbols = handle_symbols(symbols) influx_symbols = handle_symbols(symbols)
except ValueError as e: except ValueError as e:
return handle_error(fmt, str(e.message)) return handle_error(fmt, str(e))
result = query(site, inst, influx_symbols, begin, end, interval, epoch) result = query(site, inst, influx_symbols, begin, end, interval, epoch)
frame = handle_influxdb_result(result, influx_symbols, interval) frame = handle_influxdb_result(result, influx_symbols, interval)
......
...@@ -181,3 +181,16 @@ class TestDataAPI(unittest.TestCase): ...@@ -181,3 +181,16 @@ class TestDataAPI(unittest.TestCase):
# header, data, newline at end # header, data, newline at end
self.assertEqual(len(res.split('\n')), 5 + 9 + 1) self.assertEqual(len(res.split('\n')), 5 + 9 + 1)
self.assertIn("# code: 200", res) self.assertIn("# code: 200", res)
@mock.patch('metobsapi.modifyData.query')
def test_one_symbol_xml(self, query_func):
from xml.dom.minidom import parseString
r = fake_data('1m', {('aoss', 'tower'): ['time', 'air_temp']}, 9)
query_func.return_value = r
# row should be the default
res = self.app.get('/api/data.xml?symbols=aoss.tower.air_temp&begin=-00:10:00')
res = parseString(res.data.decode())
# symbols: time and air_temp
self.assertEqual(len(res.childNodes[0].childNodes[0].childNodes), 2)
# data rows
self.assertEqual(len(res.childNodes[0].childNodes[1].childNodes), 9)
...@@ -42,11 +42,13 @@ SYMBOL_TRANSLATIONS = { ...@@ -42,11 +42,13 @@ SYMBOL_TRANSLATIONS = {
'pressure': 'pressure', 'pressure': 'pressure',
'altimeter': 'altimeter', 'altimeter': 'altimeter',
'solar_flux': 'solar_flux', 'solar_flux': 'solar_flux',
'wind_speed': 'wind_speed',
}, },
('mendota', 'buoy'): { ('mendota', 'buoy'): {
'air_temp': 'air_temp', 'air_temp': 'air_temp',
'dewpoint': 'dewpoint', 'dewpoint': 'dewpoint',
'rel_hum': 'rel_hum', 'rel_hum': 'rel_hum',
'wind_speed': 'wind_speed',
'water_temp_1': 'water_temp_1', 'water_temp_1': 'water_temp_1',
'water_temp_2': 'water_temp_2', 'water_temp_2': 'water_temp_2',
'water_temp_3': 'water_temp_3', 'water_temp_3': 'water_temp_3',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment