Isis 3 Programmer Reference
XmlToPvlTranslationManager.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7#include "LabelTranslationManager.h"
8
9#include <ostream>
10
11#include <QDebug>
12#include <QFile>
13#include <QString>
14
15#include "IException.h"
16#include "IString.h"
17#include "Message.h"
18#include "Pvl.h"
19#include "PvlContainer.h"
20#include "PvlGroup.h"
21#include "PvlKeyword.h"
22#include "PvlObject.h"
23#include "XmlToPvlTranslationManager.h"
24
25
26using namespace std;
27namespace Isis {
28
41 AddTable(transFile);
42 }
43
44
59
60
71 const QString &transFile)
73 AddTable(transFile);
74 parseFile(inputLabel);
75 }
76
77
88 std::istream &transStrm)
90 AddTable(transStrm);
91 parseFile(inputLabel);
92 }
93
94
100
101
108 parseFile(inputLabel);
109 }
110
111
118 vector< pair<QString, int> > XmlToPvlTranslationManager::validKeywords() const {
119
120 vector< pair<QString, int> > validKeywords = PvlTranslationTable::validKeywords();
121 validKeywords.push_back(pair<QString, int>("InputKeyAttribute", -1));
122 validKeywords.push_back(pair<QString, int>("InputKeyDependencies", -1));
123 validKeywords.push_back(pair<QString, int>("Debug", 0));
124
125 return validKeywords;
126 }
127
128
163 QString XmlToPvlTranslationManager::Translate(QString translationGroupName,
164 int index) {
165 try {
166 if (index != 0) {
167 QString msg = "Cannot translate value at index [" + toString(index) +
168 "]. Xml files can only store a single value in each element.";
169 throw IException(IException::Unknown, msg, _FILEINFO_);
170 }
171
172 const Pvl &transTable = TranslationTable();
173 PvlGroup transGroup;
174 try {
175 transGroup = transTable.findGroup(translationGroupName);
176 }
177 catch (IException &e){
178 QString msg = "Unable to retrieve translation group from translation table.";
179 throw IException(e, IException::Unknown, msg, _FILEINFO_);
180 }
181
182 // get input position values
183 PvlKeyword inputPosition;
184 try {
185 inputPosition = transGroup["InputPosition"];
186 }
187 catch (IException &e){
188 QString msg = "Unable to retrieve [InputPosition] keyword from "
189 "translation group.";
190 throw IException(e, IException::Unknown, msg, _FILEINFO_);
191 }
192 QString inputParentName = inputPosition[inputPosition.size() - 1];
193
194 // get input key (tag or att)
195 QString inputKey;
196 try {
197 inputKey = transGroup["InputKey"][0];
198 }
199 catch (IException &e){
200 QString msg = "Unable to retrieve [InputKey] keyword from "
201 "translation group.";
202 throw IException(e, IException::Unknown, msg, _FILEINFO_);
203 }
204 QString attributeName;
205 if (transGroup.hasKeyword("InputKeyAttribute")) {
206 attributeName = transGroup["InputKeyAttribute"][0];
207 }
208
209 // get dependencies
210 PvlKeyword keyDependencies;
211 if (transGroup.hasKeyword("InputKeyDependencies")) {
212 keyDependencies = transGroup["InputKeyDependencies"];
213 }
214
215 // Check for debug
216 bool isDebug = transGroup.hasKeyword("Debug");
217
218 // Notify what we are translating and what the translating group is.
219 if (isDebug) {
220 cout << endl << " ==================== " << endl;
221 cout << endl << "Translating output keyword: " << translationGroupName << endl;
222 cout << endl << "Translation group:" << endl;
223 cout << transGroup << endl << endl;
224 }
225
226 // read input value
227 QDomElement inputParentElement = m_xmlLabel.documentElement();
228 QString indent = "";
229 if (isDebug) {
230 cout << endl << "Finding input element:" << endl << endl;
231 cout << inputParentElement.tagName() << endl;
232 }
233 // traverse the input position path
234 Pvl::ConstPvlKeywordIterator it = transGroup.findKeyword("InputPosition",
235 transGroup.begin(),
236 transGroup.end());
237
238 QDomElement oldInputParentElement = inputParentElement;
239 QString childName;
240 while(it != transGroup.end()) {
241 const PvlKeyword &inputPosition = *it;
242 inputParentElement = oldInputParentElement;
243
244 for (int i = 0; i < inputPosition.size(); i++) {
245 childName = inputPosition[i];
246 inputParentElement = inputParentElement.firstChildElement(childName);
247 if(inputParentElement.isNull()) {
248 break;
249 }
250 if (isDebug) {
251 indent += " ";
252 cout << indent << inputParentElement.tagName() << endl;
253 }
254 }
255 if (!inputParentElement.isNull()) {
256 break;
257 }
258 it = transGroup.findKeyword("InputPosition", it + 1, transGroup.end());
259 }
260
261 if (inputParentElement.isNull()) {
262 if (hasInputDefault(translationGroupName)) {
263 if (isDebug) {
264 cout << endl << "Could not traverse input position, " <<
265 "using default value: " <<
266 InputDefault(translationGroupName) << endl;
267 }
268 return PvlTranslationTable::Translate( translationGroupName );
269 }
270 else {
271 QString msg = "Failed traversing input position. [" +
272 inputPosition.name() + "] element does not have a child element named [" +
273 childName + "].";
274 throw IException(IException::Unknown, msg, _FILEINFO_);
275 }
276 }
277 // now get input value at given input position path
278 QDomElement inputKeyElement = inputParentElement.firstChildElement(inputKey);
279 if (isDebug) {
280 indent += " ";
281 cout << indent << inputKeyElement.tagName() << endl;
282 }
283
284 // Check dependencies
285 while ( !inputParentElement.isNull() &&
286 !checkDependencies(inputKeyElement, keyDependencies, isDebug) ) {
287 if (isDebug) {
288 cout << endl << "Dependencies failed, checking next candidate." << endl;
289 }
290 // Check if a sibling satisfies the dependencies
291 inputKeyElement = inputKeyElement.nextSiblingElement(inputKey);
292 // If there are no siblings to check, try cousins.
293 while ( inputKeyElement.isNull() ) {
294 inputParentElement = inputParentElement.nextSiblingElement(inputParentName);
295 // If there are no more siblings of the parent we've run out of things to check.
296 if ( inputParentElement.isNull() ) {
297 break;
298 }
299 inputKeyElement = inputParentElement.firstChildElement(inputKey);
300 }
301 }
302 // If the parent element is NULL at this point then we traversed every
303 // potential input element and none of them satisfied the dependencies.
304 if ( inputParentElement.isNull() ) {
305 if ( hasInputDefault(translationGroupName) ) {
306 if (isDebug) {
307 cout << endl << "No input value found, using default value: " <<
308 InputDefault(translationGroupName) << endl;
309 }
310 return PvlTranslationTable::Translate( translationGroupName );
311 }
312 else {
313 QString msg = "Could not find an input or default value that fits the given input "
314 "keyword dependencies.";
315 throw IException(IException::Unknown, msg, _FILEINFO_);
316 }
317 }
318
319 // translate value to output value
320 QString inputValue = inputKeyElement.text();
321 // for attributes, overwrite inputValue
322 if (attributeName.size() > 0) {
323 if ( inputKeyElement.hasAttribute(attributeName) ) {
324 inputValue = inputKeyElement.attribute(attributeName);
325 }
326 else if (hasInputDefault(translationGroupName) ) {
327 if (isDebug) {
328 cout << endl << "No input value found, using default value: " <<
329 InputDefault(translationGroupName) << endl;
330 }
331 return PvlTranslationTable::Translate( translationGroupName );
332 }
333 else {
334 QString msg = "Input element [" + inputKeyElement.tagName() +
335 "] does not have an attribute named [" +
336 attributeName + "].";
337 throw IException(IException::Unknown, msg, _FILEINFO_);
338 }
339 }
340 if (isDebug) {
341 cout << endl << "Translating input value: " << inputValue << endl;
342 }
343 return PvlTranslationTable::Translate( translationGroupName, inputValue.trimmed() );
344 }
345 catch (IException &e){
346 QString msg = "Failed to translate output value for [" + translationGroupName + "].";
347 throw IException(e, IException::Unknown, msg, _FILEINFO_);
348 }
349 }
350
351
373 PvlKeyword dependencies,
374 bool isDebug) const{
375
376 if (isDebug) {
377 cout << endl << "Testing dependencies:" << endl;
378 }
379 for (int i = 0; i < dependencies.size(); i++) {
380 QStringList specification = parseSpecification(dependencies[i]);
381
382 if (specification.size() != 3) { // the specification is not a dependancy
383 return true;
384 }
385 if (isDebug) {
386 cout << endl << "Testing dependency number " << toString(i+1) << endl;
387 cout << " Specification: " << dependencies[i] << endl;
388 cout << endl;
389 cout << " Dependency type: " << specification[0] << endl;
390 cout << " Dependency name: " << specification[1] << endl;
391 cout << " Dependency value: " << specification[2] << endl;
392 }
393 if (specification[0] == "att") {
394 if ( element.hasAttributes() ) {
395 QDomNamedNodeMap atts = element.attributes();
396 QString attributeValue = atts.namedItem(specification[1]).nodeValue();
397 if (isDebug) {
398 cout << endl;
399 cout << " Attribute name: " << atts.namedItem(specification[1]).nodeName();
400 cout << " Attribute value: " << attributeValue << endl;
401 }
402 if ( attributeValue != specification[2] ) {
403 // attribute value does not match specification or
404 // element does not have the named attribute
405 return false;
406 }
407 }
408 else {
409 // element does not have any attributes
410 return false;
411 }
412 }
413
414 else if (specification[0] == "tag") {
415 QDomElement candidateSibling = element.parentNode().firstChildElement(specification[1]);
416 QString siblingValue = candidateSibling.text();
417 if (isDebug) {
418 cout << endl;
419 cout << " Tag name: " << candidateSibling.tagName() << endl;
420 cout << " Tag value: " << siblingValue << endl;
421 }
422 if (siblingValue != specification[2] ) {
423 // sibling tag value does not match specification or
424 // named sibling tag does not exist
425 return false;
426 }
427 }
428
429 else {
430 QString msg = "Parsing error, dependency type [" + specification[0] +
431 "] is not [att] or [tag].";
432 throw IException(IException::Unknown, msg, _FILEINFO_);
433 }
434 }
435
436 // No dependencies failed!
437 return true;
438 }
439
440
450 Pvl &outputLabel) {
451 parseFile(inputLabel);
452 Auto(outputLabel);
453 }
454
455
465 QFile xmlFile(xmlFileName.expanded());
466 if ( !xmlFile.open(QIODevice::ReadOnly) ) {
467 QString msg = "Could not open label file [" + xmlFileName.expanded() +
468 "].";
469 throw IException(IException::Unknown, msg, _FILEINFO_);
470 }
471
472 QString errmsg;
473 int errline, errcol;
474 if ( !m_xmlLabel.setContent(&xmlFile, false, &errmsg, &errline, &errcol) ) {
475 xmlFile.close();
476 QString msg = "XML read/parse error in file [" + xmlFileName.expanded()
477 + "] at line [" + toString(errline) + "], column [" + toString(errcol)
478 + "], message: " + errmsg;
479 throw IException(IException::Unknown, msg, _FILEINFO_);
480 }
481
482 xmlFile.close();
483 return;
484 }
485} // end namespace isis
File name manipulation and expansion.
Definition FileName.h:100
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
Allows applications to translate simple text files.
virtual QStringList parseSpecification(QString specification) const
Parses and validates a dependency specification.
QList< PvlKeyword >::const_iterator ConstPvlKeywordIterator
The const keyword iterator.
Contains multiple PvlContainers.
Definition PvlGroup.h:41
Container for cube-like labels.
Definition Pvl.h:119
A single keyword-value pair.
Definition PvlKeyword.h:87
virtual std::vector< std::pair< QString, int > > validKeywords() const
Returns a vector of valid keyword names and their sizes.
QString Translate(const QString translationGroupName, const QString inputKeyValue="") const
Translates a single output value from the given translation group name and input value.
bool hasInputDefault(const QString translationGroupName)
Determines whether the given group has a default input value.
void AddTable(std::istream &transStm)
Adds the contents of a translation table to the searchable groups/keys Also performs a verification,...
Pvl & TranslationTable()
Protected accessor for pvl translation table passed into class.
QString InputDefault(const QString translationGroupName) const
Returns the input default value from the translation table corresponding to the output name argument.
QDomDocument m_xmlLabel
The contents of the xml label.
virtual std::vector< std::pair< QString, int > > validKeywords() const
Returns a vector of valid keyword names and their sizes.
bool checkDependencies(QDomElement element, PvlKeyword dependencies, bool isDebug) const
Checks if a element in the xml label satisfies a list of dependencies.
virtual QString Translate(QString translationGroupName, int findex=0)
Returns a translated value.
virtual ~XmlToPvlTranslationManager()
Destroys the XmlToPvlTranslationManager object.
void Auto(FileName &inputLabel, Pvl &outputLabel)
Automatically translate all the output names flagged with the Auto keyword in the translation table a...
XmlToPvlTranslationManager(const QString &transFile)
Constructs and initializes an XmlToPvlTranslationManager object from the given Pvl translation file.
void parseFile(const FileName &xmlFileName)
Opens, parses, and internalizes an Xml label file.
void SetLabel(FileName &inputLabel)
Reads an Xml label file and internalizes it for translation.
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition IString.cpp:211
Namespace for the standard library.