xmlbase.h 7.57 KB
/* ****************************************************************************
 * Copyright 2019 Open Systems Development BV                                 *
 *                                                                            *
 * Permission is hereby granted, free of charge, to any person obtaining a    *
 * copy of this software and associated documentation files (the "Software"), *
 * to deal in the Software without restriction, including without limitation  *
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
 * and/or sell copies of the Software, and to permit persons to whom the      *
 * Software is furnished to do so, subject to the following conditions:       *
 *                                                                            *
 * The above copyright notice and this permission notice shall be included in *
 * all copies or substantial portions of the Software.                        *
 *                                                                            *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING    *
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER        *
 * DEALINGS IN THE SOFTWARE.                                                  *
 * ***************************************************************************/
#pragma once

#include <pugixml.hpp>
#include <string>

#include <QtCore>

namespace osdev {
namespace components {
namespace xml {

/*!
 * \brief xml_string_writer
 *        This struct is used to write a pugiXL DOM document to a std::string (QString)
 *        pugiXML is not able to this on its own, but we use the possibility to dump
 *        an XML-document to std::cout
 */
struct xml_string_writer : pugi::xml_writer
{
    std::string result = std::string();
    virtual void write(const void* data, size_t size) override;
};

/*!
 * \brief   The XmlBase class describes the base class for all xml related classes
 *          The basic functionality is implemented here. This class is intended to
 *          be inherited and specialized and not to be used directly. ( Nothing bad
 *          will happen, just to make life easier )
 */
/*
 *    ________________________________________
 *   / I'm serious about thinking through all \
 *   | the possibilities before we settle on  |
 *   | anything. All things have the          |
 *   | advantages of their disadvantages, and |
 *   | vice versa.                            |
 *   |                                        |
 *   | -- Larry Wall in                       |
 *   \ <199709032332.QAA21669@wall.org>       /
 *    ----------------------------------------
 *     \
 *       \
 *           .--.
 *          |o_o |
 *          |:_/ |
 *         //   \ \
 *        (|     | )
 *       /'\_   _/`\
 *       \___)=(___/
 */

class XmlBase
{
public:
    /*! Default constructor */
    explicit XmlBase(const QString& xmlFile = QString());
    virtual ~XmlBase();

    /*!
     * \brief  Parses the XML contents of the string.
     * \param qsXml - String containing the contents of the XML-string
     * \return true if successfull, false if not...
     */
    bool parseString(const QString& qsXml);

    /*!
     * \brief Parses the contents of the given XML-file.
     * \param qsXml - String with the filepath & -name of the XML file.
     * \return true if successfull, false if not...
     */
    bool parseFile(const QString& qsXml);

    /*!
     * \brief Adds an XPath expression to the internal structure.
     * \param qsName - Name of the XPath expression. This should be descriptive to make life easier
     * \param qsXPath - The XPath expression to the specific data we're interested in.
     */
    void addXPath(const QString& qsName, const QString& qsXPath);

    /*!
     * \brief Retrieves an XPath expression from the internal structure
     * \param qsXPathSelect - The name of the XPath expression.
     * \return  The XPath expression as stored in the internal Hash
     */
    QString getXPath(const QString& qsXPathSelect) const;

    /*!
     * \brief Interprets the XPath expression and adds values to the variables.
     * \param qsXPathSelect - The XPath expression as given by getXPath.
     * \param arguments - The list of variables to be added to the XPath expression.
     * \return The interpreted XPath expression.
     */
    QString evaluateXPath(const QString& qsXPathSelect, const QList<QVariant>& arguments) const;

    /*!
     * \brief Set a simple node in the xml-doc.
     * \param qsXPathSelect - The XPath expression of the node we want to set.
     * \param arguments - the list of arguments in the node
     * \param data - The nodetext.
     */
    void setSimpleData(const QString& qsXPathSelect, const QList<QVariant>& arguments, const QVariant& data);

    /*!
     * \brief Set a simple node in the xml-doc.
     * \param qsXPathSelect - The XPath expression of the node we want to set.
     * \param data - The nodetext.
     */
    void setSimpleData(const QString& qsXPathSelect, const QVariant& data);

    QVariant getSimpleData(const QString& qsXPathSelect, const QList<QVariant>& arguments) const;

    /*!
     * \brief Retreive a single node based on the XPath expression
     * \param qsXPath    - The XPath expression
     * \return           - a single xpath-node
     */
    pugi::xpath_node selectNode(const QString& qsXPath) const;

    /*!
     * \brief Retreives a list of nodes based on the given XPath expression
     * \param qsXPath     - The XPath expression
     * \return            - The list of nodes
     */
    QList<pugi::xpath_node> selectNodes(const QString& qsXPath) const;

    /*! Added for convenience. The DOMTree is exported as QString */
    QString asString() const;

    /*! Helper method for the setSimpleData */
    void setNodeData(const QString& qsXPath, const QVariant& qsData);

    //! Helper method for the getSimpleData. Get data from the node that
    //! is selected with the XPath expression.
    virtual QVariant getNodeData(const QString& qsXPath) const;

    /**
     * @brief Turns a value into a boolean.
     * @param value Value to be interpreted.
     * @return boolean representation of value
     *
     * The following (capitalised) items convert to "true" :
     * - Y
     * - YES
     * - TRUE
     * - ON
     * - 1
     *
     * Everything else converts to false.
     */
    static bool getBoolean(const QVariant& value);

    /**
     * @param xmlNode The node to query for an attribute value.
     * @param attributeName The name of the attribute to query.
     * @return an attribute value.
     * @retval value as QString
     * @retval null QString when the attribute is not found.
     */
    static QString getAttributeValue(const pugi::xml_node& xmlNode, const char* attributeName);

private:
    /*!
     * \brief   Translates the pugiXML status into Human Readable messages
     * \param   parseStatus - The pugi::XML status enum from the parser.
     * \return  True if there was no error whatsoever. False if not.. 8-|
     */
    bool checkError(pugi::xml_parse_status parseStatus);

    /*!
     * \brief The internal representation of the XML document.
     */
    pugi::xml_document m_xmldoc;

    //! Storage for the XPath expressions
    QHash<QString, QString> m_xPathHash;
};

}   // End namespace xml
}   // End namespace osdev
}   // End namespace components