Isis 3 Programmer Reference
XmlToJson.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 
8 #include "XmlToJson.h"
9 #include "IException.h"
10 
11 #include <nlohmann/json.hpp>
12 #include <iostream>
13 
14 #include <QDomDocument>
15 #include <QDomElement>
16 #include <QFile>
17 
18 using json = nlohmann::json;
19 
20 namespace Isis {
21  json convertLastChildNodeToJson(QDomElement& element);
22  json convertXmlToJson(QDomElement& element, json& output);
23 
34  json xmlToJson(QString xmlFile) {
35  QDomDocument doc("xmlInput");
36  QFile file(xmlFile);
37 
38  if (!file.open(QIODevice::ReadOnly)) {
39  QString message = QString("Failed to open file for XML Input: [%1]").arg(xmlFile);
40  throw IException(IException::Io, message, _FILEINFO_);
41  }
42 
43  if (!doc.setContent(&file)) {
44  file.close();
45  QString message = QString("Failed to use file for XML Input: [%1]").arg(xmlFile);
46  throw IException(IException::Io, message, _FILEINFO_);
47  }
48 
49  file.close();
50 
51  return xmlToJson(doc);
52  }
53 
54 
63  json xmlToJson(QDomDocument& doc) {
64  QDomElement docElem = doc.documentElement();
65  json output;
66  return convertXmlToJson(docElem, output);
67  }
68 
69 
92  json convertLastChildNodeToJson(QDomElement& element){
93  json newJson;
94  if (element.hasAttributes()) {
95  // If there are attributes, add them
96  // <tag attributeName="attributeValue">textValue</tag>
97  json attributeSection;
98  QDomNamedNodeMap attrMap = element.attributes();
99  for (int i=0; i < attrMap.size(); i++) {
100  QDomAttr attr = attrMap.item(i).toAttr();
101  attributeSection["attrib_"+attr.name().toStdString()] = attr.value().toStdString();
102  }
103  // If there is no textValue, don't include it
104  // <tag attributeName="attributeValue" />
105  if (!element.text().isEmpty()) {
106  attributeSection["_text"] = element.text().toStdString();
107  }
108  newJson[element.tagName().replace(":", "_").toStdString()] = attributeSection;
109  }
110  else {
111  // Just add element and its value
112  // <tag>value</tag>
113  if (!element.text().isEmpty()) {
114  newJson[element.tagName().replace(":", "_").toStdString()] = element.text().toStdString();
115  }
116  else {
117  // <tag /> no value case
118  newJson[element.tagName().replace(":", "_").toStdString()];
119  }
120  }
121  return newJson;
122  }
123 
124 
145  json convertXmlToJson(QDomElement& element, json& output) {
146  while (!element.isNull()) {
147  QDomElement next = element.firstChildElement();
148  if (next.isNull()){
149  json converted = convertLastChildNodeToJson(element);
150  // Simple case with no repeated tags at the same level
151  if (!output.contains(element.tagName().toStdString())){
152  output.update(converted);
153  }
154  else {
155  // There is a repeated tag at the same level in the XML, i.e: <a>val1</a><a>val2</a>
156  // Translated json goal: a:[val1, val2]
157  // If the converted json has an array already, append, else make it an array
158  if (!output[element.tagName().toStdString()].is_array()) {
159  json repeatedArray;
160  repeatedArray.push_back(output[element.tagName().toStdString()]);
161  output[element.tagName().replace(":", "_").toStdString()] = repeatedArray;
162  }
163  output[element.tagName().replace(":", "_").toStdString()].push_back(converted[element.tagName().toStdString()]);
164  }
165  }
166  else {
167  // If there is already an element with this tag name at any level besides the same one,
168  // add it to a list rather than
169  // overwriting. This is the following situation:
170  // XML: <a> <first>value1</first> </a> <a> <second>value2</second></a>
171  // JSON: a: [ {first:value1, second:value2} ]
172  if (output.contains(element.tagName().toStdString())) {
173  // If it's an array already, append, else make it an array
174  json temporaryJson;
175  convertXmlToJson(next, temporaryJson);
176  if (!output[element.tagName().toStdString()].is_array()) {
177  json repeatedArray;
178  repeatedArray.push_back(output[element.tagName().toStdString()]);
179  output[element.tagName().replace(":", "_").toStdString()] = repeatedArray;
180  }
181  output[element.tagName().replace(":", "_").toStdString()].push_back(temporaryJson);
182  }
183  else {
184  if (element.hasAttributes()) {
185  json tempArea;
186  QDomNamedNodeMap attrMap = element.attributes();
187  for (int j=0; j < attrMap.size(); j++) {
188  QDomAttr attr = attrMap.item(j).toAttr();
189  tempArea["attrib_"+attr.name().toStdString()] = attr.value().toStdString();
190  }
191  tempArea.update(
192  convertXmlToJson(next, output[element.tagName().toStdString()]));
193  output[element.tagName().replace(":", "_").toStdString()] = tempArea;
194  }
195  else {
196  output[element.tagName().toStdString()] =
197  convertXmlToJson(next, output[element.tagName().replace(":", "_").toStdString()]);
198  }
199  }
200  }
201  element = element.nextSiblingElement();
202  }
203  return output;
204  }
205 }
206 
Isis::IException::Io
@ Io
A type of error that occurred when performing an actual I/O operation.
Definition: IException.h:155
Isis::xmlToJson
json xmlToJson(QString xmlFile)
Converts an XML file to a json object.
Definition: XmlToJson.cpp:34
Isis::convertLastChildNodeToJson
json convertLastChildNodeToJson(QDomElement &element)
Not intended to be used directly.
Definition: XmlToJson.cpp:92
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::convertXmlToJson
json convertXmlToJson(QDomElement &element, json &output)
Not intended to be used directly.
Definition: XmlToJson.cpp:145
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16