cphot 0.1
A C++ tool for computing photometry from spectra.
votable.hpp
Go to the documentation of this file.
1 /**
2  * @defgroup VOTABLE VOTable reader
3  * @brief Reading VOTABLEs
4  *
5  * This package is a very first draft of a VOTABLE reader. It was intended to
6  * read small "simple" tables rapidly. It does not make specific verifications
7  *
8  * VOTable supports a number of different serialization formats.
9  *
10  * * TABLEDATA stores the data in pure XML, where the numerical values are written
11  * as human-readable strings.
12  *
13  * * BINARY is a binary representation of the data, stored in the XML as an opaque
14  * base64-encoded blob.
15  *
16  * * BINARY2 was added in VOTable 1.3, and is identical to “BINARY”, except that
17  * it explicitly records the position of missing values rather than identifying
18  * them by a special value.
19  *
20  * * FITS stores the data in an external FITS file. This serialization is not
21  * supported
22  *
23  * \warning Currently only the TABLEDATA is supported by this package
24  *
25  * version: 0.1a
26  */
27 #pragma once
28 #include "helpers.hpp"
29 #include "prettyprint.hpp"
30 #include "rapidjson/document.h"
31 #include "xml2json.hpp"
32 #include <map>
33 #include <string>
34 
35 
36 /** \ingroup VOTABLE
37  */
38 namespace votable {
39 
40  /**
41  * @brief Store Table Parameter Attributes
42  *
43  * @ingroup VOTABLE
44  */
45  struct Param {
46  std::string name;
47  std::string datatype;
48  std::string value;
49  std::string ucd;
50  std::string utype;
51  std::string unit;
52  std::string description;
53  };
54 
55  /**
56  * @brief Store Table Field and data
57  *
58  * @ingroup VOTABLE
59  */
60  struct Field {
61  std::string name;
62  std::string datatype;
63  std::string ucd;
64  std::string utype;
65  std::string unit;
66  std::string description;
67  std::vector<std::string> data;
68  };
69 
70 
71  /**
72  * @brief Store parsed data from VOTable with a non-string format
73  * @ingroup VOTABLE
74  *
75  * Preserves the information from a field, but parses the data into T type
76  * to be easily usable.
77  *
78  * @tparam T data type
79  */
80  template <typename T>
81  struct VOField {
82  std::string name;
83  std::string datatype;
84  std::string ucd;
85  std::string utype;
86  std::string unit;
87  std::string description;
88  std::vector<T> data;
89  };
90 
91 
92 
93  /**
94  * Display an `std::vector` object
95  */
96  std::ostream & operator<<(std::ostream &os,
97  const Param &v)
98  {
99  os << "Param: " << v.name << "= "
100  << v.value << " [" << v.unit << "]\n"
101  << " DTYPE=" << v.datatype << "\n"
102  << " UCD=" << v.ucd << "\n"
103  << " DESCRIPTION=" << v.description << "\n";
104  return os;
105  }
106 
107 
108  /**
109  * Display a `Field` structure
110  */
111  std::ostream & operator<<(std::ostream &os,
112  const Field &v)
113  {
114  os << "Field: " << v.name << "length="
115  << v.data.size() << " [" << v.unit << "]\n"
116  << " DTYPE=" << v.datatype << "\n"
117  << " UCD=" << v.ucd << "\n"
118  << " DESCRIPTION=" << v.description << "\n";
119  if (v.data.size() > 0){
120  os << " [ ";
121  for (size_t idx=0; idx < 5; ++idx) {os << v.data[idx] << ", ";}
122  os << "..., ";
123  for (size_t idx=v.data.size() - 5; idx < v.data.size() - 1; ++idx) {os << v.data[idx] << ", ";}
124  os << v.data[v.data.size() - 1] << "]\n";
125  }
126  return os;
127  }
128 
129 
130  /**
131  * Display a `VOField` structure
132  */
133  template <typename T>
134  std::ostream & operator<<(std::ostream &os,
135  const VOField<T> &v)
136  {
137  os << "Field: " << v.name << "length="
138  << v.data.size() << " [" << v.unit << "]\n"
139  << " DTYPE=" << v.datatype << "\n"
140  << " UCD=" << v.ucd << "\n"
141  << " DESCRIPTION=" << v.description << "\n";
142  if (v.data.size() > 0){
143  os << " [ ";
144  for (size_t idx=0; idx < 5; ++idx) {os << v.data[idx] << ", ";}
145  os << "..., ";
146  for (size_t idx=v.data.size() - 5; idx < v.data.size() - 1; ++idx) {os << v.data[idx] << ", ";}
147  os << v.data[v.data.size() - 1] << "]\n";
148  }
149  return os;
150  }
151 
152  /**
153  * @brief Class defining a very simple parser of XML VOTable
154  *
155  * @ingroup VOTABLE
156  *
157  * This class reads in the XML content assuming a single table was defined.
158  * It stores the descriptions into fields and params (attributes of the
159  * table) the `get` methods allows one to rapidly access the data into a
160  * non-string type.
161  */
162  class VOTable {
163 
164  public:
165  std::map<std::string, Param> params; ///< Table parameters
166  std::vector<Field> fields; ///< Table Fields
167 
168  VOTable();
169  VOTable(const std::string & input_filename);
170  void from_content(const std::string & content);
171  size_t size();
172  size_t n_columns();
173 
174  template <typename T> VOField<T> get(std::string field_name);
175  template <typename T> VOField<T> get(size_t field_index);
176 
177  private:
178  rapidjson::Document document; /** Storing the JSON document */
179  size_t n_data = 0; ///< length of the data
180  void parse(const std::string & input_filename);
181  void setup_params();
182  void setup_fields();
183  };
184 
185 
186 /**
187  * Dummy Constructor
188  *
189  */
191 
192 /**
193  * Constructor
194  *
195  * @param input_filename: XML file to parse
196  */
197 VOTable::VOTable(const std::string & input_filename){
198  this->parse(input_filename);
199  this->setup_params();
200  this->setup_fields();
201 }
202 
203 /**
204  * @brief Constructor
205  *
206  * @param content: XML file content to parse
207  */
208 void VOTable::from_content(const std::string & content){
209  std::string json_str = xml2json(content.c_str());
210  this->document.Parse(json_str.c_str());
211  this->setup_params();
212  this->setup_fields();
213 }
214 
215 /**
216  * @brief Parse the xml file into a json document
217  *
218  * @param input_filename file to parse
219  */
220 void VOTable::parse(const std::string & input_filename){
221  std::ostringstream oss;
222  std::ifstream infile;
223  infile.open(input_filename);
224  oss.str("");
225  oss << infile.rdbuf();
226  infile.close();
227  std::string json_str = xml2json(oss.str().data());
228  this->document.Parse(json_str.c_str());
229 }
230 
231 /**
232  * @brief Read the document PARAM elements
233  *
234  * PARAM elements contain attributes of the VOTABLE
235  * These are stored into `VOTable::params`
236  */
237 void VOTable::setup_params(){
238 
239  if (!this->document["VOTABLE"]["RESOURCE"]["TABLE"].HasMember("PARAM")){
240  std::cerr << "No PARAM elements found in VOTABLE\n";
241  return;
242  }
243  // read in the document PARAMs
244  const rapidjson::Value& where = this->document["VOTABLE"]["RESOURCE"]["TABLE"]["PARAM"];
245  for (const auto& v : where.GetArray()){
246  Param p;
247  auto name = v["@name"].GetString();
248  p.name = name;
249  p.datatype = v["@datatype"].GetString();
250  p.value = v["@value"].GetString();
251  if (v.HasMember("@ucd")) {p.ucd = v["@ucd"].GetString();}
252  if (v.HasMember("@ytype")) {p.utype = v["@utype"].GetString();}
253  if (v.HasMember("@unit")) {p.unit = v["@unit"].GetString();}
254  if (v.HasMember("@DESCRIPTION")) {p.description = v["@DESCRIPTION"].GetString(); }
255  this->params[name] = p;
256  }
257 }
258 
259 /**
260  * @brief Read the document FIELD and DATA elements
261  *
262  * FIELD elements contain column description of the VOTABLE
263  * These are stored into `VOTable::fields`
264  *
265  * The DATA element contain the table(s).
266  * These are stored as strings in the `VOTable::fields::data` vectors
267  * [Note: I do not know what happens with multi tables]
268  */
269 void VOTable::setup_fields(){
270 
271  // Read in FIELD information
272  const rapidjson::Value& where = this->document["VOTABLE"]["RESOURCE"]["TABLE"]["FIELD"];
273  for (const auto& v : where.GetArray()){
274  Field p;
275  auto name = v["@name"].GetString();
276  p.name = name;
277  p.datatype = v["@datatype"].GetString();
278  if (v.HasMember("@ucd")) {p.ucd = v["@ucd"].GetString();}
279  if (v.HasMember("@ytype")) {p.utype = v["@utype"].GetString();}
280  if (v.HasMember("@unit")) {p.unit = v["@unit"].GetString();}
281  if (v.HasMember("@DESCRIPTION")) {p.description = v["@DESCRIPTION"].GetString(); }
282  this->fields.push_back(p);
283  }
284 
285  // setup data arrays
286  const rapidjson::Value& data = this->document["VOTABLE"]["RESOURCE"]["TABLE"]["DATA"]["TABLEDATA"]["TR"];
287  size_t n_entries = data.GetArray().Size();
288  size_t n_fields = this->fields.size();
289  for (auto & field: this->fields){
290  field.data.resize(n_entries);
291  }
292  this->n_data = n_entries;
293 
294  // Store data
295  const auto& tr_array = data.GetArray();
296  for (size_t k_entry=0; k_entry < n_entries; ++k_entry){
297  const auto& td = tr_array[k_entry]["TD"].GetArray();
298  for( size_t k_field=0; k_field < n_fields; ++k_field){
299  this->fields[k_field].data[k_entry] = td[k_field].GetString();
300  }
301  }
302 }
303 
304 /**
305  * @brief Size of the data table
306  *
307  * @return size_t length of the data
308  */
309 size_t VOTable::size(){
310  return this->n_data;
311 }
312 
313 /**
314  * @brief number of fields
315  *
316  * @return size_t length of the fields
317  */
319  return this->fields.size();
320 }
321 
322 /**
323  * @brief Retrieve field data
324  *
325  * @tparam T type to parse the data into
326  * @param field_name name of the field
327  * @return std::vector<T> data vector
328  */
329 template <typename T>
330 VOField<T> VOTable::get(std::string field_name){
331  size_t match = -1;
332  for (size_t idx=0; idx < this->fields.size(); ++idx){
333  if (field_name.compare(this->fields[idx].name) == 0){
334  match = idx;
335  break;
336  }
337  }
338  if (match == (size_t(-1))){
339  throw std::runtime_error("Field: " + field_name + " not found.");
340  }
341  return this->get<T>(match);
342 };
343 
344 /**
345  * @brief Retrieve field data
346  *
347  * @tparam T type to parse the data into
348  * @param field_index index of the field
349  * @return std::vector<T> data vector
350  */
351 template <typename T>
352 VOField<T> VOTable::get(size_t field_index){
353  size_t n = this->size();
354  VOField<T> newfield;
355  newfield.data.resize(n);
356  const auto & field = this->fields[field_index];
357  std::transform(
358  field.data.begin(),
359  field.data.end(),
360  newfield.data.begin(), [](std::string val) { return parseString<T>(val);});
361  newfield.name = field.name;
362  newfield.datatype = field.datatype;
363  newfield.ucd = field.ucd;
364  newfield.utype = field.utype;
365  newfield.unit = field.unit;
366  newfield.description = field.description;
367  return newfield;
368 };
369 
370 /**
371 * Display a `VOTable` object
372 */
373 std::ostream & operator<<(std::ostream &os,
374  const VOTable &vot)
375 {
376  os << "VOTable(\n";
377  for (const auto & p: vot.params){
378  os << " - " << p.second;
379  }
380  os << "\n";
381  for (const auto & f: vot.fields){
382  os << " - " << f;
383  }
384  os << ")\n";
385  return os;
386 }
387 
388 } // namespace votable
votable::VOTable::fields
std::vector< Field > fields
Table Fields.
Definition: votable.hpp:166
votable::VOField::unit
std::string unit
Definition: votable.hpp:86
votable::Param::ucd
std::string ucd
Definition: votable.hpp:49
Document
GenericDocument< UTF8<> > Document
GenericDocument with UTF8 encoding.
Definition: document.h:2402
votable::Param::name
std::string name
Definition: votable.hpp:46
votable::Param::unit
std::string unit
Definition: votable.hpp:51
document.h
votable::VOField
Store parsed data from VOTable with a non-string format.
Definition: votable.hpp:81
votable::VOField::ucd
std::string ucd
Definition: votable.hpp:84
votable::VOTable
Class defining a very simple parser of XML VOTable.
Definition: votable.hpp:162
votable::VOField::datatype
std::string datatype
Definition: votable.hpp:83
helpers.hpp
Some random tools to ease the project.
votable::Param::datatype
std::string datatype
Definition: votable.hpp:47
votable::Param
Store Table Parameter Attributes.
Definition: votable.hpp:45
prettyprint.hpp
votable::Field::utype
std::string utype
Definition: votable.hpp:64
votable::VOField::data
std::vector< T > data
Definition: votable.hpp:88
votable::VOField::utype
std::string utype
Definition: votable.hpp:85
votable::Param::utype
std::string utype
Definition: votable.hpp:50
votable::VOTable::n_columns
size_t n_columns()
number of fields
Definition: votable.hpp:318
votable::Field::description
std::string description
Definition: votable.hpp:66
xml2json
std::string xml2json(const char *xml_str)
Definition: xml2json.hpp:244
Value
GenericValue< UTF8<> > Value
GenericValue with UTF8 encoding.
Definition: document.h:2010
votable::operator<<
std::ostream & operator<<(std::ostream &os, const Param &v)
Display an std::vector object.
Definition: votable.hpp:96
votable::Field::unit
std::string unit
Definition: votable.hpp:65
votable
Definition: votable.hpp:38
votable::VOTable::VOTable
VOTable()
Dummy Constructor.
Definition: votable.hpp:190
votable::VOField::name
std::string name
Definition: votable.hpp:82
votable::Field
Store Table Field and data.
Definition: votable.hpp:60
votable::Field::name
std::string name
Definition: votable.hpp:61
votable::Field::data
std::vector< std::string > data
Definition: votable.hpp:67
votable::VOTable::params
std::map< std::string, Param > params
Table parameters.
Definition: votable.hpp:165
votable::VOTable::from_content
void from_content(const std::string &content)
Constructor.
Definition: votable.hpp:208
votable::VOTable::size
size_t size()
Size of the data table.
Definition: votable.hpp:309
votable::Field::datatype
std::string datatype
Definition: votable.hpp:62
votable::Field::ucd
std::string ucd
Definition: votable.hpp:63
votable::VOField::description
std::string description
Definition: votable.hpp:87
votable::Param::value
std::string value
Definition: votable.hpp:48
xml2json.hpp
votable::Param::description
std::string description
Definition: votable.hpp:52
votable::VOTable::get
VOField< T > get(std::string field_name)
Retrieve field data.
Definition: votable.hpp:330