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