#include "dcxmlbase.h" #include "log.h" /* * ________________________________________ * / Distance doesn't make you any smaller, \ * | but it does make you part of a larger | * \ picture. / * ---------------------------------------- * \ * \ * .--. * |o_o | * |:_/ | * // \ \ * (| | ) * /'\_ _/`\ * \___)=(___/ * **********************************************************/ using namespace osdev::components; void xml_string_writer::write(const void* data, size_t size) { result += std::string(static_cast(data), size); } DcXmlBase::DcXmlBase(const QString& xmlFile) : m_xmldoc() , m_xPathHash() { if (!xmlFile.isNull() || !xmlFile.isEmpty()) { if (parseFile(xmlFile)) { LogDebug("[DcXmlBase::DcXmlBase]", std::string("File : " + xmlFile + "..............[OK].")); } else { LogError("[DcXmlBase::DcXmlBase]", QString("File : %1 ..............[Failed].").arg(xmlFile)); throw std::runtime_error("[DcXmlBase::DcXmlBase] parseFile failed"); } } } DcXmlBase::~DcXmlBase() = default; bool DcXmlBase::parseString(const QString& qsXml) { bool bResult = false; if (!qsXml.isEmpty()) { pugi::xml_parse_status parseStatus = m_xmldoc.load_buffer(qsXml.toStdString().c_str(), qsXml.toStdString().size()) .status; bResult = checkError(parseStatus); } return bResult; } bool DcXmlBase::parseFile(const QString& qsXml) { bool bResult = false; if (!qsXml.isEmpty()) { pugi::xml_parse_status parseStatus = m_xmldoc.load_file(qsXml.toStdString().c_str()).status; bResult = checkError(parseStatus); } return bResult; } bool DcXmlBase::checkError(pugi::xml_parse_status _parseStatus) { bool bResult = false; QString sLogMessage = "An unknown error occured."; /* * GCC 5.3.1 insits on all enumeration cases for this switch to be specified. * The enumeration cases that throws -Wswitch warning are not available in pugixml for FC21. * For backward compatibility with older pugixml version "-Wswitch" warnings are temporarily supressed. */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wswitch" switch (_parseStatus) { case pugi::status_ok: sLogMessage = "File parsed successfully."; bResult = true; break; case pugi::status_file_not_found: sLogMessage = "File not found."; break; case pugi::status_io_error: sLogMessage = "Some I/O Error occured during reading the file / stream. Check the hardware for errors."; break; case pugi::status_out_of_memory: sLogMessage = "Out of Memory while parsing the file."; break; case pugi::status_internal_error: sLogMessage = "Oh dear... That's different. Something went horribly wrong. It is unrecoverable. We're exiting the whole shabang.."; break; case pugi::status_unrecognized_tag: sLogMessage = "Parsing stopping due to a tag with either an empty name or a name which starts with an incorrect character (Left a '#' somewhere?)"; break; case pugi::status_bad_pi: sLogMessage = "Parsing stopped due to incorrect document declaration/processing instruction. "; break; case pugi::status_bad_comment: sLogMessage = "Parsing stopped due to the invalid construct of a Comment."; break; case pugi::status_bad_cdata: sLogMessage = "Parsing stopped due to the invalid construct of a CDATA section."; break; case pugi::status_bad_doctype: sLogMessage = "Parsing stopped due to the invalid construct of a DocType."; break; case pugi::status_bad_pcdata: sLogMessage = "Parsing stopped due to the invalid construct of a PCDATA section."; break; case pugi::status_bad_attribute: sLogMessage = "Parsing stopped because there was an incorrect attribute, such as an attribute without value or with value that is not quoted (note that is incorrect in XML)."; break; case pugi::status_bad_start_element: sLogMessage = "Parsing stopped because a starting tag either had no closing > symbol or contained some incorrect symbol."; break; case pugi::status_bad_end_element: sLogMessage = "Parsing stopped because ending tag had incorrect syntax (i.e. extra non-whitespace symbols between tag name and >)."; break; case pugi::status_end_element_mismatch: sLogMessage = "parsing stopped because the closing tag did not match the opening one (i.e. ) or because some tag was not closed at all."; break; // DISABLED ON FEDORA 21 and CentOS 7. Not present in pugixml 1.0-8.fc21 // case pugi::status_append_invalid_root: // case pugi::status_no_document_element: } #pragma GCC diagnostic pop LogDebug("[DcXmlBase::checkError]", sLogMessage); return bResult; } void DcXmlBase::addXPath(const QString& qsName, const QString& qsXPath) { if (m_xPathHash.contains(qsName)) { LogWarning("[DcXmlBase::addXPath]", "XPath already registered : " + qsName); } m_xPathHash.insert(qsName, qsXPath); LogDebug("[DcXmlBase::addXPath]", QString("XPath" + qsXPath + " registered with key : " + qsName)); } QString DcXmlBase::getXPath(const QString& qsXPathSelect) const { QString qsXPath = m_xPathHash.value(qsXPathSelect); if (qsXPath.isEmpty()) { LogWarning("dcxml", "XPath not registered : " + qsXPathSelect); } return qsXPath; } QString DcXmlBase::evaluateXPath(const QString& qsXPathSelect, const QList& arguments) const { QString qsResult = getXPath(qsXPathSelect); // LogInfo( "DcXmlBase::evaluateXPath", QString( "Found XPathExpression : " + qsResult + " for selection : " + qsXPathSelect ) ); for (auto& value : arguments) { qsResult = qsResult.arg(value.toString()); } // LogInfo( "DcXmlBase::evaluateXPath", QString( "Resulting XPathExpression : " + qsResult ) ); return qsResult; } void DcXmlBase::setSimpleData(const QString& qsXPathSelect, const QList& arguments, const QVariant& data) { QString qsXPath = evaluateXPath(qsXPathSelect, arguments); setNodeData(qsXPath, data); } void DcXmlBase::setSimpleData(const QString& qsXPathSelect, const QVariant& data) { QString qsXPath = getXPath(qsXPathSelect); setNodeData(qsXPath, data); } QVariant DcXmlBase::getSimpleData(const QString& qsXPathSelect, const QList& arguments) const { QString qsXPath = evaluateXPath(qsXPathSelect, arguments); QVariant qvResult = getNodeData(qsXPath); return qvResult; } // static bool DcXmlBase::getBoolean(const QVariant& value) { bool b_result = false; QString l_result = value.toString().toUpper(); if ( // ------------------------ ("Y" == l_result) || ("YES" == l_result) || ("TRUE" == l_result) || ("ON" == l_result) || ("1" == l_result) // ------------------------ ) { b_result = true; } return b_result; } // static QString DcXmlBase::getAttributeValue(const pugi::xml_node& xmlNode, const char* attributeName) { const auto attr = xmlNode.attribute(attributeName); if (attr.empty()) { return {}; } return attr.value(); } pugi::xpath_node DcXmlBase::selectNode(const QString& qsXPath) const { return m_xmldoc.select_node(qsXPath.toStdString().c_str()); } QList DcXmlBase::selectNodes(const QString& qsXPath) const { QList lstResult; pugi::xpath_node_set nodes = m_xmldoc.select_nodes(qsXPath.toStdString().c_str()); for (auto& node : nodes) { lstResult.append(node); } return lstResult; } void DcXmlBase::setNodeData(const QString& qsXPath, const QVariant& qsData) { pugi::xml_node selectedNode; selectedNode = selectNode(qsXPath).node(); if (!selectedNode.empty()) { selectedNode.set_value(qsData.toString().toStdString().c_str()); } else { LogError("dcxml", QString("No node(s) found for XPath expression : '%1'") .arg(qsXPath)); } } QVariant DcXmlBase::getNodeData(const QString& qsXPath) const { QVariant qvResult; pugi::xml_node selectedNode = selectNode(qsXPath).node(); if (!selectedNode.empty()) { qvResult = QString(selectedNode.value()); } return qvResult; } QString DcXmlBase::asString() const { xml_string_writer writer; m_xmldoc.save(writer); return QString(writer.result.c_str()); }