Flow123d  release_2.2.0-26-ge868538
path_json.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file path_json.cc
15  * @brief
16  */
17 
18 #include "input/path_json.hh"
20 #include "input/comment_filter.hh"
21 #include "system/system.hh"
22 
24 #include "input/json_spirit/json_spirit_reader.h" // for read_or_...
25 
26 #include <boost/iostreams/device/file.hpp>
27 #include <boost/iostreams/filtering_stream.hpp>
28 #include <boost/algorithm/string.hpp>
29 
30 
31 namespace Input {
32 using namespace std;
33 
34 
35 PathJSON::PathJSON(istream &in)
36 : PathJSON()
37 {
38  io::filtering_istream filter_in;
39 
40  filter_in.push(uncommenting_filter());
41  filter_in.push(in);
42 
43  root_node_ = std::make_shared<Node>();
44 
45  try {
46  json_spirit::read_or_throw( filter_in, *root_node_);
47  } catch (json_spirit::Error_position &e ) {
48  THROW( ReaderInternalBase::ExcNotJSONFormat() << ReaderInternalBase::EI_JSONLine(e.line_) << ReaderInternalBase::EI_JSONColumn(e.column_)
49  << ReaderInternalBase::EI_JSONReason(e.reason_));
50  }
51 
52  nodes_.push_back( root_node_.get() );
53 }
54 
55 
57 : PathBase()
58 {
59  /* from json_spirit_value.hh:
60  * enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type };
61  */
62  json_type_names.push_back("JSON object");
63  json_type_names.push_back("JSON array");
64  json_type_names.push_back("JSON string");
65  json_type_names.push_back("JSON bool");
66  json_type_names.push_back("JSON int");
67  json_type_names.push_back("JSON real");
68  json_type_names.push_back("JSON null");
69  json_type_names.push_back(""); //scalar type
70  json_type_names.push_back(""); //undefined type
71 }
72 
73 
75 {
76  this->go_to_root();
77 }
78 
79 bool PathJSON::down(unsigned int index)
80 {
81  const Node * head_node = nodes_.back();
82  const json_spirit::mArray &array = head_node->get_array(); // the type should be checked in make_storage
83 
84  if ( index >= array.size()) return false;
85  path_.push_back( make_pair( index, string("") ) );
86  nodes_.push_back( &( array[index] ) );
87  return true;
88 }
89 
90 
91 bool PathJSON::down(const string& key, int index)
92 {
93  const Node * head_node = nodes_.back();
94  const json_spirit::mObject &obj = head_node->get_obj(); // the type should be checked in make_storage
95 
96  json_spirit::mObject::const_iterator it = obj.find(key);
97  if (it == obj.end()) {
98  return false;
99  } else {
100  path_.push_back( make_pair( index, key) );
101  nodes_.push_back( &( it->second ) );
102  }
103  return true;
104 }
105 
106 
108 {
109  if (path_.size() > 1) {
110  path_.pop_back();
111  nodes_.pop_back();
112  }
113 }
114 
115 
116 /**
117  * This returns path to reference given by address in ref_address.
118  *
119  */
121 {
122  namespace ba = boost::algorithm;
123 
124  const Node * head_node = nodes_.back();
125  if (head_node->type() != json_spirit::obj_type) return NULL;
126  const json_spirit::mObject &obj = head_node->get_obj();
127  if (obj.size() != 1) return NULL;
128  if (obj.begin()->first != "REF") return NULL;
129 
130  const Node &ref_node = obj.begin()->second;
131  if (ref_node.type() != json_spirit::str_type) {
132  THROW( ExcRefOfWrongType() << EI_ErrorAddress(this->as_string()) );
133 
134  }
135  string ref_address = ref_node.get_str();
136 
137  PathJSON * ref_path = this->clone();
138  string::size_type pos = 0;
139  string::size_type new_pos = 0;
140  string address = ref_address + '/';
141  string tmp_str;
142  bool relative_ref = false;
143 
144  std::set<string>::iterator it = previous_references_.find(ref_address);
145  if (it == previous_references_.end()) {
146  ref_path->previous_references_.insert(ref_address);
147  } else {
148  THROW( ExcReferenceNotFound() << EI_RefAddress(this->as_string()) << EI_ErrorAddress(ref_path->as_string()) << EI_RefStr(ref_address)
149  << EI_Specification("cannot follow reference") );
150  }
151 
152  while ( ( new_pos=address.find('/',pos) ) != string::npos ) {
153  tmp_str = address.substr(pos, new_pos - pos);
154  if (pos==0 && tmp_str == "") {
155  // absolute path
156  ref_path->go_to_root();
157 
158  } else if ( ba::all( tmp_str, ba::is_digit()) ) {
159  // integer == index in array
160  if ( !ref_path->is_array_type() ) {
161  THROW( ExcReferenceNotFound() << EI_RefAddress(this->as_string()) << EI_ErrorAddress(ref_path->as_string()) << EI_RefStr(ref_address)
162  << EI_Specification("there should be Array") );
163  }
164 
165  if ( !ref_path->down( atoi(tmp_str.c_str()) ) ) {
166  THROW( ExcReferenceNotFound() << EI_RefAddress(this->as_string()) << EI_ErrorAddress(ref_path->as_string()) << EI_RefStr(ref_address)
167  << EI_Specification("index out of size of Array") );
168  }
169 
170  } else if (tmp_str == "..") {
171  relative_ref = true;
172  if (ref_path->level() <= 0 ) {
173  THROW( ExcReferenceNotFound() << EI_RefAddress(this->as_string()) << EI_ErrorAddress(ref_path->as_string()) << EI_RefStr(ref_address)
174  << EI_Specification("can not go up from root") );
175  }
176  ref_path->up();
177 
178  } else {
179  if ( !ref_path->is_record_type() )
180  THROW( ExcReferenceNotFound() << EI_RefAddress(this->as_string()) << EI_ErrorAddress(ref_path->as_string()) << EI_RefStr(ref_address)
181  << EI_Specification("there should be Record") );
182  if ( !ref_path->down(tmp_str) )
183  THROW( ExcReferenceNotFound() << EI_RefAddress(this->as_string()) << EI_ErrorAddress(ref_path->as_string()) << EI_RefStr(ref_address)
184  << EI_Specification("key '"+tmp_str+"' not found") );
185  }
186  pos = new_pos+1;
187  }
188  if (relative_ref) {
189  MessageOut() << "Referencing '" << this->as_string() << "' to '" << ref_path->as_string() << "'." << std::endl;
190  }
191  return ref_path;
192 }
193 
194 
195 
197  return head()->type() == json_spirit::null_type;
198 }
199 
200 
202  if (head()->type() == json_spirit::bool_type) {
203  return head()->get_bool();
204  } else {
205  THROW( ReaderInternalBase::ExcInputError() );
206  }
207  return false;
208 }
209 
210 
211 
212 std::int64_t PathJSON::get_int_value() const {
213  if (head()->type() == json_spirit::int_type) {
214  return head()->get_int64();
215  } else {
216  THROW( ReaderInternalBase::ExcInputError() );
217  }
218  return 0;
219 }
220 
221 
222 
224  auto value_type = head()->type();
225  if ( value_type== json_spirit::real_type
226  || value_type == json_spirit::int_type) {
227  return head()->get_real();
228  } else {
229  THROW( ReaderInternalBase::ExcInputError() );
230  }
231  return 0.0;
232 }
233 
234 
235 
236 std::string PathJSON::get_string_value() const {
237  if (head()->type() == json_spirit::str_type) {
238  return head()->get_str();
239  } else {
240  THROW( ReaderInternalBase::ExcInputError() );
241  }
242  return "";
243 }
244 
245 
246 
247 unsigned int PathJSON::get_node_type_index() const {
248  return head()->type();
249 }
250 
251 
252 
253 bool PathJSON::get_record_key_set(std::set<std::string> &keys_list) const {
254  if ( this->is_record_type() ) {
255  const json_spirit::mObject & j_map = head()->get_obj();
256  json_spirit::mObject::const_iterator map_it;
257  std::set<string>::iterator set_it;
258 
259  for( map_it = j_map.begin(); map_it != j_map.end(); ++map_it) {
260  keys_list.insert(map_it->first);
261  }
262 
263  return true;
264  }
265 
266  return false;
267 }
268 
269 
270 
272  if (head()->type() == json_spirit::array_type) {
273  const json_spirit::mArray & j_array = head()->get_array();
274  return j_array.size();
275  }
276 
277  return -1;
278 }
279 
280 
281 
283  return head()->type() == json_spirit::obj_type;
284 }
285 
286 
287 
289  return head()->type() == json_spirit::array_type;
290 }
291 
292 
293 
295  return new PathJSON(*this);
296 }
297 
298 
299 
300 std::string PathJSON::get_record_tag() const {
301  std::string tag_value;
302  if ( this->is_record_type() ) {
303  PathJSON type_path(*this);
304  if ( type_path.down("TYPE") ) {
305  //check if TYPE key is reference
306  PathBase * ref_path = type_path.find_ref_node();
307  if (ref_path) {
308  tag_value = ref_path->get_string_value();
309  delete ref_path;
310  } else {
311  tag_value = type_path.get_string_value();
312  }
313  }
314  } else {
315  tag_value = "";
316  }
317 
318  return tag_value;
319 }
320 
321 
322 
325 }
326 
327 
328 
330  return false;
331 }
332 
333 
334 
335 std::ostream& operator<<(std::ostream& stream, const PathJSON& path) {
336  path.output(stream);
337  return stream;
338 }
339 
340 
341 } // namespace Input
bool is_array_type() const override
Implements PathBase::is_array_type.
Definition: path_json.cc:288
boost::int64_t get_int64() const
bool is_null_type() const override
Implements PathBase::is_null_type.
Definition: path_json.cc:196
io::finite_state_filter< uncommenting_fsm > uncommenting_filter
Class used by ReaderToStorage class to iterate over the JSON tree provided by json_spirit library...
Definition: path_json.hh:46
std::ostream & operator<<(std::ostream &stream, const Address &address)
Definition: accessors.hh:253
Base abstract class used by ReaderToStorage class to iterate over the input tree. ...
Definition: path_base.hh:41
#define MessageOut()
Macro defining &#39;message&#39; record of log.
Definition: logger.hh:233
std::string as_string() const
Returns string address of current position.
Definition: path_base.cc:48
PathBase * find_ref_node() override
Implements reading of reference keys, and check of cyclic references.
Definition: path_json.cc:120
std::vector< std::string > json_type_names
Names of all possible node types in parsed input tree.
Definition: path_base.hh:175
const Node * head() const
Pointer to JSON Value object at current path.
Definition: path_json.hh:124
std::vector< const Node * > nodes_
Definition: path_json.hh:138
bool down(unsigned int index) override
Dive into json_spirit hierarchy.
Definition: path_json.cc:79
bool is_record_type() const override
Implements PathBase::is_record_type.
Definition: path_json.cc:282
double get_double_value() const override
Implements PathBase::get_double_value.
Definition: path_json.cc:223
void go_to_root()
Move to root node.
Definition: path_base.cc:56
void up() override
Return one level up in the hierarchy.
Definition: path_json.cc:107
void read_or_throw(const std::string &s, mValue &value)
std::int64_t get_int_value() const override
Implements PathBase::get_int_value.
Definition: path_json.cc:212
const String_type & get_str() const
std::vector< std::pair< int, std::string > > path_
One level of the path_ is either index (nonnegative int) in array or string key in a json object...
Definition: path_base.hh:166
void remember_reference()
Put address of actual reference to previous_references_ set.
Definition: path_json.cc:323
~PathJSON() override
Destructor.
Definition: path_json.cc:74
int level() const
Implements PathBase::level.
Definition: path_json.hh:83
unsigned int get_node_type_index() const override
Implements PathBase::get_node_type_index.
Definition: path_json.cc:247
std::string get_string_value() const override
Implements PathBase::get_string_value.
Definition: path_json.cc:236
Value_type type() const
virtual std::string get_string_value() const =0
Get string value of head node or throw exception.
const Array & get_array() const
bool get_record_key_set(std::set< std::string > &) const override
Implements PathBase::get_record_key_set.
Definition: path_json.cc:253
bool is_effectively_null() const override
Implements PathBase::is_effectively_null.
Definition: path_json.cc:329
void output(std::ostream &stream) const
Output to the given stream.
Definition: path_base.cc:31
const Object & get_obj() const
PathJSON()
Default constructor.
Definition: path_json.cc:56
int get_array_size() const override
Implements PathBase::get_array_size.
Definition: path_json.cc:271
std::set< std::string > previous_references_
Remember used references in order to avoid detect cyclic references.
Definition: path_json.hh:132
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
PathJSON * clone() const override
Implements PathBase::clone.
Definition: path_json.cc:294
bool get_bool_value() const override
Implements PathBase::get_bool_value.
Definition: path_json.cc:201
std::string get_record_tag() const override
Implements PathBase::get_record_tag.
Definition: path_json.cc:300