diff options
Diffstat (limited to 'include/iprt/cpp/xml.h')
-rw-r--r-- | include/iprt/cpp/xml.h | 512 |
1 files changed, 422 insertions, 90 deletions
diff --git a/include/iprt/cpp/xml.h b/include/iprt/cpp/xml.h index bb9f5a18..d45ce746 100644 --- a/include/iprt/cpp/xml.h +++ b/include/iprt/cpp/xml.h @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2007-2011 Oracle Corporation + * Copyright (C) 2007-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -30,10 +30,13 @@ # error "There are no XML APIs available in Ring-0 Context!" #endif +#include <iprt/list.h> +#include <iprt/cpp/exception.h> +#include <iprt/cpp/utils.h> + #include <list> #include <memory> -#include <iprt/cpp/exception.h> /** @defgroup grp_rt_cpp_xml C++ XML support * @ingroup grp_rt_cpp @@ -380,60 +383,158 @@ class AttributeNode; class ContentNode; /** - * Node base class. Cannot be used directly, but ElementNode, ContentNode and - * AttributeNode derive from this. This does implement useful public methods though. + * Node base class. + * + * Cannot be used directly, but ElementNode, ContentNode and AttributeNode + * derive from this. This does implement useful public methods though. + * + * */ class RT_DECL_CLASS Node { public: - ~Node(); + virtual ~Node(); - const char* getName() const; - bool nameEquals(const char *pcszNamespace, const char *pcsz) const; + const char *getName() const; + const char *getPrefix() const; + const char *getNamespaceURI() const; + bool nameEqualsNS(const char *pcszNamespace, const char *pcsz) const; bool nameEquals(const char *pcsz) const { - return nameEquals(NULL, pcsz); + return nameEqualsNS(NULL, pcsz); } + bool nameEqualsN(const char *pcsz, size_t cchMax, const char *pcszNamespace = NULL) const; - const char* getValue() const; + const char *getValue() const; bool copyValue(int32_t &i) const; bool copyValue(uint32_t &i) const; bool copyValue(int64_t &i) const; bool copyValue(uint64_t &i) const; - int getLineNumber() const; + /** @name Introspection. + * @{ */ + /** Is this an ElementNode instance. + * @returns true / false */ + bool isElement() const + { + return m_Type == IsElement; + } - int isElement() const + /** Is this an ContentNode instance. + * @returns true / false */ + bool isContent() const + { + return m_Type == IsContent; + } + + /** Is this an AttributeNode instance. + * @returns true / false */ + bool isAttribute() const { return m_Type == IsElement; } + int getLineNumber() const; + /** @} */ + + /** @name General tree enumeration. + * + * Use the introspection methods isElement() and isContent() before doing static + * casting. Parents are always or ElementNode type, but siblings and children + * can be of both ContentNode and ElementNode types. + * + * @remarks Attribute node are in the attributes list, while both content and + * element nodes are in the list of children. See ElementNode. + * + * @remarks Careful mixing tree walking with node removal! + * @{ + */ + /** Get the parent node + * @returns Pointer to the parent node, or NULL if root. */ + const Node *getParent() const + { + return m_pParent; + } + + /** Get the previous sibling. + * @returns Pointer to the previous sibling node, NULL if first child. + */ + const Node *getPrevSibiling() const + { + if (!m_pParentListAnchor) + return NULL; + return RTListGetPrevCpp(m_pParentListAnchor, this, const Node, m_listEntry); + } + + /** Get the next sibling. + * @returns Pointer to the next sibling node, NULL if last child. */ + const Node *getNextSibiling() const + { + if (!m_pParentListAnchor) + return NULL; + return RTListGetNextCpp(m_pParentListAnchor, this, const Node, m_listEntry); + } + /** @} */ + protected: - typedef enum {IsElement, IsAttribute, IsContent} EnumType; + /** Node types. */ + typedef enum { IsElement, IsAttribute, IsContent } EnumType; + /** The type of node this is an instance of. */ EnumType m_Type; - Node *m_pParent; - xmlNode *m_plibNode; // != NULL if this is an element or content node - xmlAttr *m_plibAttr; // != NULL if this is an attribute node - const char *m_pcszNamespacePrefix; // not always set - const char *m_pcszNamespaceHref; // full http:// spec - const char *m_pcszName; // element or attribute name, points either into plibNode or plibAttr; - // NULL if this is a content node + /** The parent node (always an element), NULL if root. */ + Node *m_pParent; + + xmlNode *m_pLibNode; ///< != NULL if this is an element or content node + xmlAttr *m_pLibAttr; ///< != NULL if this is an attribute node + const char *m_pcszNamespacePrefix; ///< not always set + const char *m_pcszNamespaceHref; ///< full http:// spec + const char *m_pcszName; ///< element or attribute name, points either into pLibNode or pLibAttr; + ///< NULL if this is a content node + + /** Child list entry of this node. (List head m_pParent->m_children.) */ + RTLISTNODE m_listEntry; + /** Pointer to the parent list anchor. + * This allows us to use m_listEntry both for children and attributes. */ + PRTLISTANCHOR m_pParentListAnchor; // hide the default constructor so people use only our factory methods Node(EnumType type, Node *pParent, - xmlNode *plibNode, - xmlAttr *plibAttr); + PRTLISTANCHOR pListAnchor, + xmlNode *pLibNode, + xmlAttr *pLibAttr); Node(const Node &x); // no copying - void buildChildren(const ElementNode &elmRoot); + friend class AttributeNode; + friend class ElementNode; /* C list hack. */ +}; - /* Obscure class data */ - struct Data; - Data *m; +/** + * Node subclass that represents an attribute of an element. + * + * For attributes, Node::getName() returns the attribute name, and Node::getValue() + * returns the attribute value, if any. + * + * Since the Node constructor is private, one can create new attribute nodes + * only through the following factory methods: + * + * -- ElementNode::setAttribute() + */ +class RT_DECL_CLASS AttributeNode : public Node +{ +public: - friend class AttributeNode; +protected: + // hide the default constructor so people use only our factory methods + AttributeNode(const ElementNode *pElmRoot, + Node *pParent, + PRTLISTANCHOR pListAnchor, + xmlAttr *pLibAttr); + AttributeNode(const AttributeNode &x); // no copying + + friend class Node; + friend class ElementNode; }; /** @@ -451,54 +552,313 @@ protected: class RT_DECL_CLASS ElementNode : public Node { public: - int getChildElements(ElementNodesList &children, - const char *pcszMatch = NULL) const; + int getChildElements(ElementNodesList &children, const char *pcszMatch = NULL) const; - const ElementNode* findChildElement(const char *pcszNamespace, - const char *pcszMatch) const; - const ElementNode* findChildElement(const char *pcszMatch) const + const ElementNode *findChildElementNS(const char *pcszNamespace, const char *pcszMatch) const; + const ElementNode *findChildElement(const char *pcszMatch) const { - return findChildElement(NULL, pcszMatch); + return findChildElementNS(NULL, pcszMatch); } - const ElementNode* findChildElementFromId(const char *pcszId) const; - - const AttributeNode* findAttribute(const char *pcszMatch) const; - bool getAttributeValue(const char *pcszMatch, const char *&ppcsz) const; - bool getAttributeValue(const char *pcszMatch, RTCString &str) const; - bool getAttributeValuePath(const char *pcszMatch, RTCString &str) const; - bool getAttributeValue(const char *pcszMatch, int32_t &i) const; - bool getAttributeValue(const char *pcszMatch, uint32_t &i) const; - bool getAttributeValue(const char *pcszMatch, int64_t &i) const; - bool getAttributeValue(const char *pcszMatch, uint64_t &i) const; - bool getAttributeValue(const char *pcszMatch, bool &f) const; - - ElementNode* createChild(const char *pcszElementName); - - ContentNode* addContent(const char *pcszContent); - ContentNode* addContent(const RTCString &strContent) + const ElementNode *findChildElementFromId(const char *pcszId) const; + + /** Finds the first decendant matching the name at the end of @a pcszPath and + * optionally namespace. + * + * @returns Pointer to the child string value, NULL if not found or no value. + * @param pcszPath The attribute name. Slashes can be used to make a + * simple path to any decendant. + * @param pcszNamespace The namespace to match, NULL (default) match any + * namespace. When using a path, this matches all + * elements along the way. + * @see findChildElement, findChildElementP + */ + const ElementNode *findChildElementP(const char *pcszPath, const char *pcszNamespace = NULL) const; + + /** Finds the first child with matching the give name and optionally namspace, + * returning its value. + * + * @returns Pointer to the child string value, NULL if not found or no value. + * @param pcszPath The attribute name. Slashes can be used to make a + * simple path to any decendant. + * @param pcszNamespace The namespace to match, NULL (default) match any + * namespace. When using a path, this matches all + * elements along the way. + * @see findChildElement, findChildElementP + */ + const char *findChildElementValueP(const char *pcszPath, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getValue(); + return NULL; + } + + /** Combines findChildElementP and findAttributeValue. + * + * @returns Pointer to attribute string value, NULL if either the element or + * the attribute was not found. + * @param pcszPath The attribute name. Slashes can be used to make a + * simple path to any decendant. + * @param pcszAttribute The attribute name. + * @param pcszPathNamespace The namespace to match @pcszPath with, NULL + * (default) match any namespace. When using a + * path, this matches all elements along the way. + * @param pcszAttribNamespace The namespace prefix to apply to the attribute, + * NULL (default) match any namespace. + * @see findChildElementP and findAttributeValue + */ + const char *findChildElementAttributeValueP(const char *pcszPath, const char *pcszAttribute, + const char *pcszPathNamespace = NULL, + const char *pcszAttributeNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszPathNamespace); + if (pElem) + return pElem->findAttributeValue(pcszAttribute, pcszAttributeNamespace); + return NULL; + } + + + /** @name Tree enumeration. + * @{ */ + + /** Get the next tree element in a full tree enumeration. + * + * By starting with the root node, this can be used to enumerate the entire tree + * (or sub-tree if @a pElmRoot is used). + * + * @returns Pointer to the next element in the tree, NULL if we're done. + * @param pElmRoot The root of the tree we're enumerating. NULL if + * it's the entire tree. + */ + ElementNode const *getNextTreeElement(ElementNode const *pElmRoot = NULL) const; + RT_CPP_GETTER_UNCONST_RET(ElementNode *, ElementNode, getNextTreeElement, (const ElementNode *pElmRoot = NULL), (pElmRoot)) + + /** Get the first child node. + * @returns Pointer to the first child node, NULL if no children. */ + const Node *getFirstChild() const + { + return RTListGetFirstCpp(&m_children, const Node, m_listEntry); + } + RT_CPP_GETTER_UNCONST_RET(Node *, ElementNode, getFirstChild,(),()) + + /** Get the last child node. + * @returns Pointer to the last child node, NULL if no children. */ + const Node *getLastChild() const + { + return RTListGetLastCpp(&m_children, const Node, m_listEntry); + } + + /** Get the first child node. + * @returns Pointer to the first child node, NULL if no children. */ + const ElementNode *getFirstChildElement() const; + + /** Get the last child node. + * @returns Pointer to the last child node, NULL if no children. */ + const ElementNode *getLastChildElement() const; + + /** Get the previous sibling element. + * @returns Pointer to the previous sibling element, NULL if first child + * element. + * @see getNextSibilingElement, getPrevSibling + */ + const ElementNode *getPrevSibilingElement() const; + + /** Get the next sibling element. + * @returns Pointer to the next sibling element, NULL if last child element. + * @see getPrevSibilingElement, getNextSibling + */ + const ElementNode *getNextSibilingElement() const; + + /** Find the previous element matching the given name and namespace (optionally). + * @returns Pointer to the previous sibling element, NULL if first child + * element. + * @param pcszName The element name to match. + * @param pcszNamespace The namespace name, default is NULL which means + * anything goes. + * @note Changed the order of the arguments. + */ + const ElementNode *findPrevSibilingElement(const char *pcszName, const char *pcszNamespace = NULL) const; + + /** Find the next element matching the given name and namespace (optionally). + * @returns Pointer to the previous sibling element, NULL if first child + * element. + * @param pcszName The element name to match. + * @param pcszNamespace The namespace name, default is NULL which means + * anything goes. + * @note Changed the order of the arguments. + */ + const ElementNode *findNextSibilingElement(const char *pcszName, const char *pcszNamespace = NULL) const; + /** @} */ + + + const AttributeNode *findAttribute(const char *pcszMatch, const char *pcszNamespace = NULL) const; + /** Find the first attribute with the given name, returning its value string. + * @returns Pointer to the attribute string value. + * @param pcszName The attribute name. + * @param pcszNamespace The namespace name, default is NULL which means + * anything goes. + * @see getAttributeValue + */ + const char *findAttributeValue(const char *pcszName, const char *pcszNamespace = NULL) const + { + const AttributeNode *pAttr = findAttribute(pcszName, pcszNamespace); + if (pAttr) + return pAttr->getValue(); + return NULL; + } + + bool getAttributeValue(const char *pcszMatch, const char *&pcsz, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &pcsz, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, RTCString &str, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &str, pcszNamespace); } + bool getAttributeValuePath(const char *pcszMatch, RTCString &str, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &str, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, int32_t &i, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &i, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, uint32_t &i, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &i, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, int64_t &i, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &i, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, uint64_t &u, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &u, pcszNamespace); } + bool getAttributeValue(const char *pcszMatch, bool &f, const char *pcszNamespace = NULL) const + { return getAttributeValue(pcszMatch, &f, pcszNamespace); } + + /** @name Variants that for clarity does not use references for output params. + * @{ */ + bool getAttributeValue(const char *pcszMatch, const char **ppcsz, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, RTCString *pStr, const char *pcszNamespace = NULL) const; + bool getAttributeValuePath(const char *pcszMatch, RTCString *pStr, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, int32_t *pi, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, uint32_t *pu, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, int64_t *piValue, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, uint64_t *pu, const char *pcszNamespace = NULL) const; + bool getAttributeValue(const char *pcszMatch, bool *pf, const char *pcszNamespace = NULL) const; + /** @} */ + + /** @name Convenience methods for convering the element value. + * @{ */ + bool getElementValue(int32_t *piValue) const; + bool getElementValue(uint32_t *puValue) const; + bool getElementValue(int64_t *piValue) const; + bool getElementValue(uint64_t *puValue) const; + bool getElementValue(bool *pfValue) const; + /** @} */ + + /** @name Convenience findChildElementAttributeValueP and getElementValue. + * @{ */ + bool getChildElementValueP(const char *pcszPath, int32_t *piValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + return pElem && pElem->getElementValue(piValue); + } + bool getChildElementValueP(const char *pcszPath, uint32_t *puValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + return pElem && pElem->getElementValue(puValue); + } + bool getChildElementValueP(const char *pcszPath, int64_t *piValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + return pElem && pElem->getElementValue(piValue); + } + bool getChildElementValueP(const char *pcszPath, uint64_t *puValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + return pElem && pElem->getElementValue(puValue); + } + bool getChildElementValueP(const char *pcszPath, bool *pfValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + return pElem && pElem->getElementValue(pfValue); + } + + /** @} */ + + /** @name Convenience findChildElementAttributeValueP and getElementValue with a + * default value being return if the child element isn't present. + * + * @remarks These will return false on conversion errors. + * @{ */ + bool getChildElementValueDefP(const char *pcszPath, int32_t iDefault, int32_t *piValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getElementValue(piValue); + *piValue = iDefault; + return true; + } + bool getChildElementValueDefP(const char *pcszPath, uint32_t uDefault, uint32_t *puValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getElementValue(puValue); + *puValue = uDefault; + return true; + } + bool getChildElementValueDefP(const char *pcszPath, int64_t iDefault, int64_t *piValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getElementValue(piValue); + *piValue = iDefault; + return true; + } + bool getChildElementValueDefP(const char *pcszPath, uint64_t uDefault, uint64_t *puValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getElementValue(puValue); + *puValue = uDefault; + return true; + } + bool getChildElementValueDefP(const char *pcszPath, bool fDefault, bool *pfValue, const char *pcszNamespace = NULL) const + { + const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace); + if (pElem) + return pElem->getElementValue(pfValue); + *pfValue = fDefault; + return true; + } + /** @} */ + + ElementNode *createChild(const char *pcszElementName); + + ContentNode *addContent(const char *pcszContent); + ContentNode *addContent(const RTCString &strContent) { return addContent(strContent.c_str()); } - AttributeNode* setAttribute(const char *pcszName, const char *pcszValue); - AttributeNode* setAttribute(const char *pcszName, const RTCString &strValue) + AttributeNode *setAttribute(const char *pcszName, const char *pcszValue); + AttributeNode *setAttribute(const char *pcszName, const RTCString &strValue) { return setAttribute(pcszName, strValue.c_str()); } - AttributeNode* setAttributePath(const char *pcszName, const RTCString &strValue); - AttributeNode* setAttribute(const char *pcszName, int32_t i); - AttributeNode* setAttribute(const char *pcszName, uint32_t i); - AttributeNode* setAttribute(const char *pcszName, int64_t i); - AttributeNode* setAttribute(const char *pcszName, uint64_t i); - AttributeNode* setAttributeHex(const char *pcszName, uint32_t i); - AttributeNode* setAttribute(const char *pcszName, bool f); + AttributeNode *setAttributePath(const char *pcszName, const RTCString &strValue); + AttributeNode *setAttribute(const char *pcszName, int32_t i); + AttributeNode *setAttribute(const char *pcszName, uint32_t i); + AttributeNode *setAttribute(const char *pcszName, int64_t i); + AttributeNode *setAttribute(const char *pcszName, uint64_t i); + AttributeNode *setAttributeHex(const char *pcszName, uint32_t i); + AttributeNode *setAttribute(const char *pcszName, bool f); + + virtual ~ElementNode(); protected: // hide the default constructor so people use only our factory methods - ElementNode(const ElementNode *pelmRoot, Node *pParent, xmlNode *plibNode); + ElementNode(const ElementNode *pElmRoot, Node *pParent, PRTLISTANCHOR pListAnchor, xmlNode *pLibNode); ElementNode(const ElementNode &x); // no copying - const ElementNode *m_pelmRoot; + /** We keep a pointer to the root element for attribute namespace handling. */ + const ElementNode *m_pElmRoot; + + /** List of child elements and content nodes. */ + RTLISTANCHOR m_children; + /** List of attributes nodes. */ + RTLISTANCHOR m_attributes; + + static void buildChildren(ElementNode *pElmRoot); friend class Node; friend class Document; @@ -519,41 +879,13 @@ public: protected: // hide the default constructor so people use only our factory methods - ContentNode(Node *pParent, xmlNode *plibNode); + ContentNode(Node *pParent, PRTLISTANCHOR pListAnchor, xmlNode *pLibNode); ContentNode(const ContentNode &x); // no copying friend class Node; friend class ElementNode; }; -/** - * Node subclass that represents an attribute of an element. - * - * For attributes, Node::getName() returns the attribute name, and Node::getValue() - * returns the attribute value, if any. - * - * Since the Node constructor is private, one can create new attribute nodes - * only through the following factory methods: - * - * -- ElementNode::setAttribute() - */ -class RT_DECL_CLASS AttributeNode : public Node -{ -public: - -protected: - // hide the default constructor so people use only our factory methods - AttributeNode(const ElementNode &elmRoot, - Node *pParent, - xmlAttr *plibAttr, - const char **ppcszKey); - AttributeNode(const AttributeNode &x); // no copying - - RTCString m_strKey; - - friend class Node; - friend class ElementNode; -}; /** * Handy helper class with which one can loop through all or some children @@ -583,7 +915,7 @@ private: Document doc; XmlFileParser parser; parser.read("file.xml", doc); - Element *pelmRoot = doc.getRootElement(); + Element *pElmRoot = doc.getRootElement(); @endcode * * -- XmlMemWriter or XmlFileWriter to write out an XML document after it has @@ -591,7 +923,7 @@ private: * * @code Document doc; - Element *pelmRoot = doc.createRootElement(); + Element *pElmRoot = doc.createRootElement(); // add children xml::XmlFileWriter writer(doc); writer.write("file.xml", true); |