cphot 0.1
A C++ tool for computing photometry from spectra.
xml2json.hpp
Go to the documentation of this file.
1 #ifndef XML2JSON_HPP_INCLUDED
2 #define XML2JSON_HPP_INCLUDED
3 
4 // Copyright (C) 2015 Alan Zhuang (Cheedoong) HKUST. [Updated to the latest version of rapidjson]
5 // Copyright (C) 2013 Alan Zhuang (Cheedoong) Tencent, Inc.
6 
7 #include <iostream>
8 #include <map>
9 #include <string>
10 #include <cctype>
11 
12 #include "rapidxml/rapidxml.hpp"
15 
16 #include "rapidjson/document.h"
17 #include "rapidjson/prettywriter.h"
19 #include "rapidjson/stringbuffer.h"
20 #include "rapidjson/reader.h"
21 #include "rapidjson/writer.h"
24 #include "rapidjson/error/en.h"
25 
26 /* [Start] This part is configurable */
27 static const char xml2json_text_additional_name[] = "#text";
28 static const char xml2json_attribute_name_prefix[] = "@";
29 /* Example:
30  <node_name attribute_name="attribute_value">value</node_name> ---> "node_name":{"#text":"value","@attribute_name":"attribute_value"}
31 */
32 static const bool xml2json_numeric_support = false;
33 /* Example:
34  xml2json_numeric_support = false:
35  <number>26.026</number> ---> "number":"26.026"
36  xml2json_numeric_support = true:
37  <number>26.026</number> ---> "number":26.026
38 */
39 /* [End] This part is configurable */
40 
41 // Avoided any namespace pollution.
42 static bool xml2json_has_digits_only(const char * input, bool *hasDecimal)
43 {
44  if (input == nullptr)
45  return false; // treat empty input as a string (probably will be an empty string)
46 
47  const char * runPtr = input;
48 
49  *hasDecimal = false;
50 
51  while (*runPtr != '\0')
52  {
53  if (*runPtr == '.')
54  {
55  if (!(*hasDecimal))
56  *hasDecimal = true;
57  else
58  return false; // we found two dots - not a number
59  }
60  else if (isalpha(*runPtr))
61  {
62  return false;
63  }
64  runPtr++;
65  }
66 
67  return true;
68 }
69 
70 void xml2json_to_array_form(const char *name, rapidjson::Value &jsvalue, rapidjson::Value &jsvalue_chd, rapidjson::Document::AllocatorType& allocator)
71 {
72  rapidjson::Value jsvalue_target; // target to do some operation
73  rapidjson::Value jn; // this is a must, partially because of the latest version of rapidjson
74  jn.SetString(name, allocator);
75  jsvalue_target = jsvalue.FindMember(name)->value;
76  if(jsvalue_target.IsArray())
77  {
78  jsvalue_target.PushBack(jsvalue_chd, allocator);
79  jsvalue.RemoveMember(name);
80  jsvalue.AddMember(jn, jsvalue_target, allocator);
81  }
82  else
83  {
84  rapidjson::Value jsvalue_array;
85  //jsvalue_array = jsvalue_target;
86  jsvalue_array.SetArray();
87  jsvalue_array.PushBack(jsvalue_target, allocator);
88  jsvalue_array.PushBack(jsvalue_chd, allocator);
89  jsvalue.RemoveMember(name);
90  jsvalue.AddMember(jn, jsvalue_array, allocator);
91  }
92 }
93 
95 {
97  for(myattr = xmlnode->first_attribute(); myattr; myattr = myattr->next_attribute())
98  {
99  rapidjson::Value jn, jv;
100  jn.SetString((std::string(xml2json_attribute_name_prefix) + myattr->name()).c_str(), allocator);
101 
102  if (xml2json_numeric_support == false)
103  {
104  jv.SetString(myattr->value(), allocator);
105  }
106  else
107  {
108  bool hasDecimal;
109  if (xml2json_has_digits_only(myattr->value(), &hasDecimal) == false)
110  {
111  jv.SetString(myattr->value(), allocator);
112  }
113  else
114  {
115  if (hasDecimal)
116  {
117  double value = std::strtod(myattr->value(),nullptr);
118  jv.SetDouble(value);
119  }
120  else
121  {
122  long int value = std::strtol(myattr->value(), nullptr, 0);
123  jv.SetInt(value);
124  }
125  }
126  }
127  jsvalue.AddMember(jn, jv, allocator);
128  }
129 }
130 
132 {
133  //cout << "this: " << xmlnode->type() << " name: " << xmlnode->name() << " value: " << xmlnode->value() << endl;
134  rapidjson::Value jsvalue_chd;
135 
136  jsvalue.SetObject();
137  jsvalue_chd.SetObject();
138  rapidxml::xml_node<> *xmlnode_chd;
139 
140  // classified discussion:
141  if((xmlnode->type() == rapidxml::node_data || xmlnode->type() == rapidxml::node_cdata) && xmlnode->value())
142  {
143  // case: pure_text
144  jsvalue.SetString(xmlnode->value(), allocator); // then addmember("#text" , jsvalue, allocator)
145  }
146  else if(xmlnode->type() == rapidxml::node_element)
147  {
148  if(xmlnode->first_attribute())
149  {
150  if(xmlnode->first_node() && xmlnode->first_node()->type() == rapidxml::node_data && count_children(xmlnode) == 1)
151  {
152  // case: <e attr="xxx">text</e>
153  rapidjson::Value jn, jv;
154  jn.SetString(xml2json_text_additional_name, allocator);
155  jv.SetString(xmlnode->first_node()->value(), allocator);
156  jsvalue.AddMember(jn, jv, allocator);
157  xml2json_add_attributes(xmlnode, jsvalue, allocator);
158  return;
159  }
160  else
161  {
162  // case: <e attr="xxx">...</e>
163  xml2json_add_attributes(xmlnode, jsvalue, allocator);
164  }
165  }
166  else
167  {
168  if(!xmlnode->first_node())
169  {
170  // case: <e />
171  jsvalue.SetNull();
172  return;
173  }
174  else if(xmlnode->first_node()->type() == rapidxml::node_data && count_children(xmlnode) == 1)
175  {
176  // case: <e>text</e>
177  if (xml2json_numeric_support == false)
178  {
179  jsvalue.SetString(rapidjson::StringRef(xmlnode->first_node()->value()), allocator);
180  }
181  else
182  {
183  bool hasDecimal;
184  if (xml2json_has_digits_only(xmlnode->first_node()->value(), &hasDecimal) == false)
185  {
186  jsvalue.SetString(rapidjson::StringRef(xmlnode->first_node()->value()), allocator);
187  }
188  else
189  {
190  if (hasDecimal)
191  {
192  double value = std::strtod(xmlnode->first_node()->value(), nullptr);
193  jsvalue.SetDouble(value);
194  }
195  else
196  {
197  long int value = std::strtol(xmlnode->first_node()->value(), nullptr, 0);
198  jsvalue.SetInt(value);
199  }
200  }
201  }
202  return;
203  }
204  }
205  if(xmlnode->first_node())
206  {
207  // case: complex else...
208  std::map<std::string, int> name_count;
209  for(xmlnode_chd = xmlnode->first_node(); xmlnode_chd; xmlnode_chd = xmlnode_chd->next_sibling())
210  {
211  std::string current_name;
212  const char *name_ptr = NULL;
213  rapidjson::Value jn, jv;
214  if(xmlnode_chd->type() == rapidxml::node_data || xmlnode_chd->type() == rapidxml::node_cdata)
215  {
216  current_name = xml2json_text_additional_name;
217  name_count[current_name]++;
218  jv.SetString(xml2json_text_additional_name, allocator);
219  name_ptr = jv.GetString();
220  }
221  else if(xmlnode_chd->type() == rapidxml::node_element)
222  {
223  current_name = xmlnode_chd->name();
224  name_count[current_name]++;
225  name_ptr = xmlnode_chd->name();
226  }
227  xml2json_traverse_node(xmlnode_chd, jsvalue_chd, allocator);
228  if(name_count[current_name] > 1 && name_ptr)
229  xml2json_to_array_form(name_ptr, jsvalue, jsvalue_chd, allocator);
230  else
231  {
232  jn.SetString(name_ptr, allocator);
233  jsvalue.AddMember(jn, jsvalue_chd, allocator);
234  }
235  }
236  }
237  }
238  else
239  {
240  std::cerr << "err data!!" << std::endl;
241  }
242 }
243 
244 std::string xml2json(const char *xml_str)
245 {
246  //file<> fdoc("track_orig.xml"); // could serve another use case
248  xml_doc->parse<0> (const_cast<char *>(xml_str));
249 
250  rapidjson::Document js_doc;
251  js_doc.SetObject();
252  rapidjson::Document::AllocatorType& allocator = js_doc.GetAllocator();
253 
254  rapidxml::xml_node<> *xmlnode_chd;
255 
256  for(xmlnode_chd = xml_doc->first_node(); xmlnode_chd; xmlnode_chd = xmlnode_chd->next_sibling())
257  {
258  rapidjson::Value jsvalue_chd;
259  jsvalue_chd.SetObject();
260  //rapidjson::Value jsvalue_name(xmlnode_chd->name(), allocator);
261  //js_doc.AddMember(jsvalue_name, jsvalue_chd, allocator);
262  xml2json_traverse_node(xmlnode_chd, jsvalue_chd, allocator);
263  js_doc.AddMember(rapidjson::StringRef(xmlnode_chd->name()), jsvalue_chd, allocator);
264  }
265 
267  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
268  js_doc.Accept(writer);
269  delete xml_doc;
270  return buffer.GetString();
271 }
272 
273 #endif
Document
GenericDocument< UTF8<> > Document
GenericDocument with UTF8 encoding.
Definition: document.h:2402
xml2json_numeric_support
static const bool xml2json_numeric_support
Definition: xml2json.hpp:32
document.h
prettywriter.h
rapidxml::count_children
std::size_t count_children(xml_node< Ch > *node)
Counts children of node.
Definition: rapidxml_utils.hpp:93
xml2json_add_attributes
void xml2json_add_attributes(rapidxml::xml_node<> *xmlnode, rapidjson::Value &jsvalue, rapidjson::Document::AllocatorType &allocator)
Definition: xml2json.hpp:94
StringRef
GenericStringRef< CharType > StringRef(const CharType *str)
Mark a character pointer as constant string.
Definition: document.h:346
stringbuffer.h
rapidxml::node_element
@ node_element
An element node.
Definition: rapidxml.hpp:149
rapidxml::xml_attribute
Class representing attribute node of XML document.
Definition: rapidxml.hpp:141
StringBuffer
GenericStringBuffer< UTF8< char >, CrtAllocator > StringBuffer
Definition: fwd.h:59
rapidxml::xml_node::type
node_type type() const
Gets type of node.
Definition: rapidxml.hpp:999
rapidxml::xml_node::first_node
xml_node< Ch > * first_node(const Ch *name=0, const Ch *xmlns=0, std::size_t name_size=0, std::size_t xmlns_size=0, bool case_sensitive=true) const
Gets first child node, optionally matching node name.
Definition: rapidxml.hpp:1115
MemoryPoolAllocator<>
reader.h
filewritestream.h
xml2json
std::string xml2json(const char *xml_str)
Definition: xml2json.hpp:244
rapidxml_utils.hpp
Value
GenericValue< UTF8<> > Value
GenericValue with UTF8 encoding.
Definition: document.h:2010
rapidxml::xml_document::parse
Ch * parse(Ch *text, xml_document< Ch > *parent=0)
Parses zero-terminated XML string according to given flags.
Definition: rapidxml.hpp:1595
rapidxml::xml_document
This class represents root of the DOM hierarchy.
Definition: rapidxml.hpp:142
rapidxml::node_data
@ node_data
A data node.
Definition: rapidxml.hpp:150
encodedstream.h
rapidxml::xml_node
Class representing a node of XML document.
Definition: rapidxml.hpp:140
xml2json_to_array_form
void xml2json_to_array_form(const char *name, rapidjson::Value &jsvalue, rapidjson::Value &jsvalue_chd, rapidjson::Document::AllocatorType &allocator)
Definition: xml2json.hpp:70
xml2json_text_additional_name
static const char xml2json_text_additional_name[]
Definition: xml2json.hpp:27
en.h
rapidxml::xml_attribute::next_attribute
xml_attribute< Ch > * next_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Gets next attribute, optionally matching attribute name.
Definition: rapidxml.hpp:921
xml2json_traverse_node
void xml2json_traverse_node(rapidxml::xml_node<> *xmlnode, rapidjson::Value &jsvalue, rapidjson::Document::AllocatorType &allocator)
Definition: xml2json.hpp:131
value
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1222
rapidxml.hpp
filereadstream.h
xml2json_has_digits_only
static bool xml2json_has_digits_only(const char *input, bool *hasDecimal)
Definition: xml2json.hpp:42
rapidxml::xml_node::first_attribute
xml_attribute< Ch > * first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Gets first attribute of node, optionally matching attribute name.
Definition: rapidxml.hpp:1208
xml2json_attribute_name_prefix
static const char xml2json_attribute_name_prefix[]
Definition: xml2json.hpp:28
rapidxml::node_cdata
@ node_cdata
A CDATA node.
Definition: rapidxml.hpp:151
rapidxml_print.hpp
rapidxml::xml_node::next_sibling
xml_node< Ch > * next_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Gets next sibling node, optionally matching node name.
Definition: rapidxml.hpp:1187
writer.h