--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xml/xmldomandxpath/src/xmlenginedom/xmlengnode.cpp Thu Dec 17 09:29:21 2009 +0200
@@ -0,0 +1,1170 @@
+// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Node functions implementation
+//
+
+#include <stdlib.h>
+
+#include <xml/dom/xmlengelement.h>
+#include <xml/dom/xmlengdocument.h>
+#include <xml/dom/xmlengnamespace.h>
+#include <xml/dom/xmlengtext.h>
+#include <xml/dom/xmlenguserdata.h>
+#include <xml/dom/xmlengnodelist.h>
+#include <stdapis/libxml2/libxml2_parser.h>
+#include <stdapis/libxml2/libxml2_globals.h>
+#include <stdapis/libxml2/libxml2_xmlio.h>
+#include "libxml2_xmlsave_private.h"
+#include "libxml2_tree_private.h"
+#include "xmlengdomdefs.h"
+#include <xml/dom/xmlengerrors.h>
+#include <xml/utils/xmlengmem.h>
+#include <xml/utils/xmlengxestrings.h>
+
+// ---------------------------------------------------------------------------------------------
+// Unlinks the internal libxml2's node from double-linked list.
+// Relinks neighbour nodes.The node stays virtually linked to its old neighbours! Use with care!!
+//
+// No checks are made; nor parent's, nor node's properties updated
+// ---------------------------------------------------------------------------------------------
+//
+void TXmlEngNode::DoUnlinkNode()
+ {
+ xmlNodePtr& next = LIBXML_NODE->next;
+ xmlNodePtr& prev = LIBXML_NODE->prev;
+ // Unlink this node; relink neighbors
+ if (prev)
+ {
+ prev->next = next;
+ }
+ else
+ {
+ // Unlinked node is the first in the list
+ // 'children' or 'properties' property of the parent node
+ // must be updated (depending on the type of the node: content node or attribute)
+ xmlNodePtr& parent = LIBXML_NODE->parent;
+ // Ugly, but works :)
+ xmlNodePtr* first = ((LIBXML_NODE->type == XML_ATTRIBUTE_NODE)
+ ? reinterpret_cast<xmlNodePtr*>(&(parent->properties))
+ : &(parent->children));
+ *first = next;
+ }
+ if (next)
+ {
+ next->prev = prev;
+ }
+ else
+ {
+ // Unlinked node is the last in the list (of elements or attributes)
+ // 'last' property of the parent element must be updated (for content nodes only)
+ if(LIBXML_NODE->type != XML_ATTRIBUTE_NODE)
+ {
+ LIBXML_NODE->parent->last = prev;
+ }
+ }
+ }
+
+
+// ---------------------------------------------------------------------------------------------
+// Inserts the node in a double-linked list of nodes before specified node.
+//
+// No checks are made; nor parent's, nor node's properties updated (except prev/next)
+// ---------------------------------------------------------------------------------------------
+//
+void TXmlEngNode::LinkBefore(TXmlEngNode aTargetNode)
+ {
+ xmlNodePtr node = INTERNAL_NODEPTR(aTargetNode);
+ xmlNodePtr& prev = node->prev;
+ LIBXML_NODE->next = node;
+ LIBXML_NODE->prev = prev;
+ prev->next = LIBXML_NODE;
+ node->prev = LIBXML_NODE;
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Get innerXML string. This method return all content of the node.
+// Output text does not include node markup.
+//
+// @note Returned TString should be freed
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TInt TXmlEngNode::InnerXmlL(RBuf8& aBuffer)
+ {
+ if(aBuffer.Length())
+ {
+ aBuffer.Close();
+ }
+ if(IsNull())
+ {
+ User::Leave(KXmlEngErrWrongUseOfAPI);
+ }
+
+ if(NodeType() == TXmlEngNode::EDocument)
+ {
+ return OwnerDocument().SaveL(aBuffer, OwnerDocument(), NULL);
+ }
+ aBuffer.FillZ();
+ RXmlEngNodeList<TXmlEngNode> nodeList;
+ RBuf8 tmpStr;
+ GetChildNodes(nodeList);
+ TXmlEngNode tmpNode;
+ while(nodeList.HasNext())
+ {
+ tmpNode = nodeList.Next();
+ tmpNode.OuterXmlL(tmpStr);
+ CleanupClosePushL(tmpStr);
+ if((aBuffer.MaxSize() - aBuffer.Size()) < tmpStr.Size())
+ {
+ aBuffer.ReAllocL(aBuffer.MaxSize() + tmpStr.Size() + 1);
+ }
+ aBuffer.Append(tmpStr);
+ CleanupStack::PopAndDestroy();
+ }
+ tmpStr.Close();
+
+ return aBuffer.Size();
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Get outerXML string. This method return all content of the node.
+// Output text includes node markup.
+//
+// @note Returned TString should be freed
+//
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TInt TXmlEngNode::OuterXmlL(RBuf8& aBuffer)
+ {
+ TInt size = -1;
+ if(aBuffer.Length())
+ {
+ aBuffer.Close();
+ }
+ if(IsNull())
+ {
+ User::Leave(KXmlEngErrWrongUseOfAPI);
+ }
+
+ if(NodeType() == TXmlEngNode::EDocument)
+ {
+ return OwnerDocument().SaveL(aBuffer, OwnerDocument(), NULL);
+ }
+
+ xmlSaveCtxt ctxt;
+ xmlOutputBufferPtr buf;
+
+ /*
+ * save the content to a temp buffer.
+ */
+ buf = xmlAllocOutputBuffer(NULL);
+ OOM_IF_NULL(buf);
+
+ memset(&ctxt, 0, sizeof(ctxt));
+ ctxt.doc = LIBXML_NODE->doc;
+ ctxt.buf = buf;
+ ctxt.level = 0;
+ ctxt.format = 0;
+
+ xmlSaveCtxtInit(&ctxt);
+
+ xmlNodeDumpOutputInternal(&ctxt, LIBXML_NODE);
+ if(xmlOOMFlag())
+ {
+ xmlOutputBufferClose(buf);
+ OOM_HAPPENED;
+ }
+
+ size = buf->buffer->use;
+ if(size > 0)
+ {
+ // frees any previous contents of aBuffer argument
+ aBuffer.Assign(buf->buffer->content,size,size);
+ // To prevent it from freeing
+ buf->buffer->content = NULL;
+ }
+ xmlOutputBufferClose(buf);
+
+ // Leaves with KErrNoMemory
+ TEST_OOM_FLAG;
+ if (size < 0)
+ {
+ XmlEngLeaveL(KXmlEngErrNegativeOutputSize);
+ }
+
+ return size;
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Moves the node to become the first in the list of its siblings
+// Node is expected to have a parent.
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C void TXmlEngNode::SetAsFirstSibling()
+ {
+ if (LIBXML_NODE->type == XML_NAMESPACE_DECL)
+ {
+ return;
+ }
+ xmlNodePtr& prev = LIBXML_NODE->prev;
+ if (prev)
+ {
+ DoUnlinkNode();
+ // Insert as first
+ prev = NULL;
+ xmlNodePtr& parent = LIBXML_NODE->parent;
+ // Ugly, but works :)
+ xmlNodePtr* first = ((LIBXML_NODE->type == XML_ATTRIBUTE_NODE)
+ ? reinterpret_cast<xmlNodePtr*>(&(parent->properties))
+ : &(parent->children));
+
+ (*first)->prev = LIBXML_NODE;
+ LIBXML_NODE->next = *first;
+ *first = LIBXML_NODE;
+ // NOTE: it is possible to cope without having parent defined,
+ // it will need to iterate through sibling list to find the first one
+ }
+ }
+
+
+// ---------------------------------------------------------------------------------------------
+// Moves the node to become the last in the list of its siblings
+// Node is expected to have a parent.
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C void TXmlEngNode::SetAsLastSibling()
+ {
+ if (LIBXML_NODE->type == XML_NAMESPACE_DECL)
+ {
+ return;
+ }
+ xmlNodePtr& next = LIBXML_NODE->next;
+ if (next)
+ {
+ DoUnlinkNode();
+ xmlNodePtr& parent = LIBXML_NODE->parent;
+ xmlNodePtr& prev = LIBXML_NODE->prev;
+ if (LIBXML_NODE->type != XML_ATTRIBUTE_NODE)
+ {
+ if (!prev)
+ parent->children = next;
+ prev = parent->last;
+ parent->last->next = LIBXML_NODE;
+ parent->last = LIBXML_NODE;
+ }
+ else
+ {
+ if (!prev)
+ parent->properties = (xmlAttrPtr)next;
+ prev = next; // NOTE: 'next' is always different than NULL
+ while (prev->next)
+ prev = prev->next;
+ prev->next = LIBXML_NODE;
+ }
+ next = NULL;
+ }
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Moves the node in the list of sibling nodes before another node
+// Node is expected to have a parent.
+// Do nothing if aSiblingNode is not one of node's siblings
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C void TXmlEngNode::MoveBeforeSibling(
+ TXmlEngNode aSiblingNode )
+ {
+ if (LIBXML_NODE->type == XML_NAMESPACE_DECL)
+ {
+ return;
+ }
+ xmlNodePtr node = INTERNAL_NODEPTR(aSiblingNode);
+ if (!node->prev)
+ {
+ SetAsFirstSibling();
+ }
+ else
+ {
+ DoUnlinkNode();
+ LinkBefore(aSiblingNode);
+ }
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Moves the node in the list of sibling nodes after another node
+// Node is expected to have a parent.
+// Do nothing if aSiblingNode is not one of the node's siblings
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C void TXmlEngNode::MoveAfterSibling(
+ TXmlEngNode aSiblingNode)
+ {
+ if (LIBXML_NODE->type == XML_NAMESPACE_DECL)
+ {
+ return;
+ }
+ xmlNodePtr node = INTERNAL_NODEPTR(aSiblingNode);
+ if (!node->next)
+ {
+ SetAsLastSibling();
+ }
+ else
+ {
+ DoUnlinkNode();
+ LinkBefore(aSiblingNode.NextSibling());
+ }
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Retrieves a "handle" for namespace declaration that applies to the node's namespace
+// Note: DOM specs do not consider namespace declarations as a kind of nodes
+// This API adds TXmlEngNamespace type of nodes, which is derived from TXmlEngNode.
+//
+// @return Object that represents namespace declaration and prefix binding that
+// act on the node; returns NULL object (check using TXmlEngNamespace.IsNull()
+// or TXmlEngNamespace.NotNull()) if no namespace associated
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TXmlEngNamespace TXmlEngNode::NamespaceDeclaration() const
+ {
+ //
+ switch(LIBXML_NODE->type)
+ {
+ case XML_ELEMENT_NODE:
+ case XML_ATTRIBUTE_NODE:
+ return TXmlEngNamespace(LIBXML_NODE->ns);
+ default:
+ return NULL;
+ }
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Clones the node completely: all attributes and namespace declarations (for TXmlEngElement nodes),
+// values and children nodes are copied as well.
+//
+// Document nodes cannot be copied with this method: RXmlEngDocument::CloneDocumentL() must be used.
+//
+// @return Complete copy of a node or leaves.
+// @note The node should not be NULL!
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TXmlEngNode TXmlEngNode::CopyL() const
+ {
+ if ( !LIBXML_NODE )
+ {
+ User::Leave(KXmlEngErrNullNode);
+ }
+ // Copying of RXmlEngDocument should be made with RXmlEngDocument::CloneDocumentL()
+ if(NodeType() == TXmlEngNode::EDocument)
+ return NULL;
+ //
+ xmlNodePtr copy = xmlStaticCopyNode(
+ LIBXML_NODE,
+ NULL /* doc */,
+ NULL /* parent */,
+ 1);
+ //
+ if (xmlOOMFlag())
+ {
+ if(copy)
+ xmlFreeNode(copy); // it may be a partial copy
+ OOM_HAPPENED;
+ }
+ TXmlEngNode ncopy(copy);
+ OwnerDocument().TakeOwnership(ncopy);
+ return ncopy;
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Creates a deep copy of the node and appends the subtree as a new child
+// to the provided parent node.
+//
+// @return Created copy of the node after linking it into the target document tree.
+// @note Document nodes cannot be copied with this method; use RXmlEngDocument::CloneDocumentL()
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TXmlEngNode TXmlEngNode::CopyToL(
+ TXmlEngNode aParent ) const
+ {
+ if ( !LIBXML_NODE )
+ {
+ User::Leave(KXmlEngErrNullNode);
+ }
+ if ( LIBXML_NODE->type == XML_DOCUMENT_NODE )
+ {
+ User::Leave(KXmlEngErrWrongUseOfAPI);
+ }
+ if ( aParent.IsNull() )
+ {
+ User::Leave(KXmlEngErrNullNode);
+ }
+ //
+ TXmlEngNode ncopy = CopyL();
+ return aParent.AppendChildL(ncopy);
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Detaches a node from document tree
+//
+// @return This node, which is already not a part of any document
+// @note Remember to use ReconcileNamespacesL() later, if extracted node (subtree)
+// contains references to namespace declarations outside of the subtree.
+// @see ReconcileNamespacesL()
+// @note The document, from which the node is being unlinked, becomes an owner of the node
+// until it is linked elsewhere.
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TXmlEngNode TXmlEngNode::Unlink()
+ {
+ //
+ if(LIBXML_NODE && ParentNode().NotNull())
+ {
+ RXmlEngDocument tmpDoc = OwnerDocument();
+ xmlUnlinkNode(LIBXML_NODE);
+ tmpDoc.TakeOwnership(*this);
+ }
+ return *this;
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Unlinks the node and destroys it; all child nodes are destroyed as well and all memory is freed
+//
+// @note Document nodes cannot be "removed" with this method, uses RXmlEngDocument-specific methods.
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C void TXmlEngNode::Remove()
+ {
+ //
+ if (!LIBXML_NODE || LIBXML_NODE->type == XML_DOCUMENT_NODE)
+ {
+ return;
+ }
+ if(ParentNode().NotNull())
+ {
+ xmlUnlinkNode(LIBXML_NODE);
+ }
+ else
+ {
+ OwnerDocument().RemoveOwnership(*this);
+ }
+ if (LIBXML_NODE->type != XML_ATTRIBUTE_NODE)
+ {
+ xmlFreeNode(LIBXML_NODE);
+ }
+ else
+ {
+ xmlFreeProp(INTERNAL_ATTRPTR(iInternal));
+ }
+
+ iInternal = 0;
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Ensures that namespaces referred to in the node and its descendants are
+// in the scope the node.
+//
+// * This method checks that all the namespaces declared within the given
+// * tree are properly declared. This is needed for example after Copy or Unlink
+// * and then Append operations. The subtree may still hold pointers to
+// * namespace declarations outside the subtree or they may be invalid/masked. As much
+// * as possible the function try to reuse the existing namespaces found in
+// * the new environment. If not possible, the new namespaces are redeclared
+// * on the top of the subtree.
+//
+// This method should be used after unlinking nodes and inserting to another
+// document tree or to a another part of the original tree, if some nodes of the subtree
+// are remove from the scope of a namespace declaration they refer to.
+//
+// When node is unlinked, it may still refer to namespace declarations from the previous location.
+// It is important to reconcile subtree's namespaces if previous parent tree is to be destroyed.
+// On the other hand, if the parent tree is not changed before pasting its unlinked part into another
+// tree, then reconciliation is needed only after paste operation.
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C void TXmlEngNode::ReconcileNamespacesL()
+ {
+ xmlReconciliateNs(LIBXML_NODE->doc, LIBXML_NODE);
+ TEST_OOM_FLAG;
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Current node is replaced with another node (subtree).
+//
+// The replacement node is linked into document tree instead of this node.
+// The replaced node is destroyed.
+//
+// @see SubstituteForL(TXmlEngNode)
+//
+// In both cases the argument node is unlinked from its previous location
+// (which can be NONE, i.e. not linked; SAME or ANOTHER document tree).
+//
+// @note Replacement of a node with NULL TXmlEngNode is legal and equivalent to removing the node.
+// @note Not applicable to document nodes
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C void TXmlEngNode::ReplaceWithL(TXmlEngNode aNode)
+ {
+ if ( !LIBXML_NODE )
+ {
+ User::Leave(KXmlEngErrNullNode);
+ }
+ if ( LIBXML_NODE->type == XML_DOCUMENT_NODE )
+ {
+ User::Leave(KXmlEngErrWrongUseOfAPI);
+ }
+
+ if(aNode.ParentNode().IsNull())
+ {
+ // new node is unlinked, so owned by some (maybe other than this) document
+ // previous ownership must be withdrawn
+ aNode.OwnerDocument().RemoveOwnership(aNode);
+ }
+ if(ParentNode().IsNull())
+ {
+ // This node is unlinked, thus owned by its document
+ // Ownership must be withdrawn before removing the node
+ RXmlEngDocument doc = OwnerDocument();
+ doc.RemoveOwnership(*this);
+ // Also, there is no place to link the new node!
+ // So it will be unlinked, but owned by this node's document
+ doc.TakeOwnership(aNode);
+ }
+ // put new node instead of 'this' node: it works with all combinations of linked/unlinked states of the nodes
+ xmlFreeNode(xmlReplaceNode(LIBXML_NODE, INTERNAL_NODEPTR(aNode)));
+ }
+
+EXPORT_C void TXmlEngNode::ReplaceWith(TXmlEngNode aNode)
+ {
+ if(!LIBXML_NODE || LIBXML_NODE->type == XML_DOCUMENT_NODE)
+ return;
+ if(aNode.ParentNode().IsNull())
+ {
+ // new node is unlinked, so owned by some (maybe other than this) document
+ // previous ownership must be withdrawn
+ aNode.OwnerDocument().RemoveOwnership(aNode);
+ }
+ if(ParentNode().IsNull())
+ {
+ // This node is unlinked, thus owned by its document
+ // Ownership must be withdrawn before removing the node
+ RXmlEngDocument doc = OwnerDocument();
+ doc.RemoveOwnership(*this);
+ // Also, there is no place to link the new node!
+ // So it will be unlinked, but owned by this node's document
+ doc.TakeOwnership(aNode);
+ }
+ // put new node instead of 'this' node: it works with all combinations of linked/unlinked states of the nodes
+ xmlFreeNode(xmlReplaceNode(LIBXML_NODE, INTERNAL_NODEPTR(aNode)));
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Another node is put instead of the current node.
+//
+// Does the same as ReplaceWith(TXmlEngNode) but does not free node and just returns it.
+//
+// @return Current node after unlinking it from document tree
+// @see ReplaceWith(TXmlEngNode)
+//
+// In both cases the argument node is unlinked from its previous location
+// (which can be NONE, i.e. not linked; SAME or ANOTHER document tree)
+//
+// It is possible to use NULL TXmlEngNode object as an argument. In such case
+// no new node will be put instead of unlinked one.
+//
+// @note Not applicable to document nodes
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TXmlEngNode TXmlEngNode::SubstituteForL(TXmlEngNode aNode)
+ {
+ if ( !LIBXML_NODE )
+ {
+ User::Leave(KXmlEngErrNullNode);
+ }
+ if ( LIBXML_NODE->type == XML_DOCUMENT_NODE )
+ {
+ User::Leave(KXmlEngErrWrongUseOfAPI);
+ }
+ //
+ if(aNode.ParentNode().IsNull())
+ {
+ // new node is unlinked, so owned by other document
+ // it must not be owned to be linked
+ aNode.OwnerDocument().RemoveOwnership(aNode);
+ }
+ if(ParentNode().IsNull())
+ {
+ // this node is unlinked - nowhere to link new node: this node's document will own it
+ OwnerDocument().TakeOwnership(aNode);
+ // this node will stay as it is
+ // new node will be unlinked by call to xmlReplaceNode
+ }
+ TXmlEngNode tmpNode = TXmlEngNode(xmlReplaceNode(LIBXML_NODE, INTERNAL_NODEPTR(aNode)));
+ aNode.OwnerDocument().TakeOwnership(tmpNode);
+ return tmpNode;
+ }
+
+// ---------------------------------------------------------------------------------------------
+// DOM Level 3 Core
+// ---------------------------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------------------------
+//Initializes a node list with all children of the node
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C void TXmlEngNode::GetChildNodes(RXmlEngNodeList<TXmlEngNode>& aList) const
+ {
+ aList.Open(LIBXML_NODE->children, TDOMNODETYPENONE);
+ }
+
+// ---------------------------------------------------------------------------------------------
+// @return Parent node of the node or NULL if no parent
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TXmlEngNode TXmlEngNode::ParentNode() const
+ {
+ //
+ return TXmlEngNode(LIBXML_NODE->parent);
+ }
+
+// ---------------------------------------------------------------------------------------------
+// @return The first child node or NULL if no children
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TXmlEngNode TXmlEngNode::FirstChild() const
+ {
+ //
+ return TXmlEngNode(LIBXML_NODE->children);
+ }
+
+// ---------------------------------------------------------------------------------------------
+// @return The last child node or NULL if no children
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TXmlEngNode TXmlEngNode::LastChild() const
+ {
+ //
+ return TXmlEngNode(LIBXML_NODE->last);
+ }
+
+// ---------------------------------------------------------------------------------------------
+// @return Previous node in a child list or NULL if no sibling before
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TXmlEngNode TXmlEngNode::PreviousSibling() const
+ {
+ if(!LIBXML_NODE->parent)
+ {
+ return NULL;
+ }
+ return TXmlEngNode(LIBXML_NODE->prev);
+ }
+
+// ---------------------------------------------------------------------------------------------
+// @return Following node in a child list or NULL if no sibling after
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TXmlEngNode TXmlEngNode::NextSibling() const
+ {
+ if(!LIBXML_NODE->parent)
+ {
+ return NULL;
+ }
+ return TXmlEngNode(LIBXML_NODE->next);
+ }
+
+// ---------------------------------------------------------------------------------------------
+// @return A document node of the DOM tree this node belongs to
+// @note An instance of RXmlEngDocument class returns itself
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C RXmlEngDocument TXmlEngNode::OwnerDocument() const
+ {
+ //
+ return RXmlEngDocument(LIBXML_NODE->doc);
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Append a child node.
+//
+// This is universal operation for any types of nodes.
+// Note, that some types of nodes cannot have children and
+// some types of nodes are not allowed to be children of some other types.
+//
+// @return Appended node, which could changed as a result of adding it to
+// list of child nodes (e.g. text nodes can coalesce together)
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TXmlEngNode TXmlEngNode::AppendChildL(
+ TXmlEngNode aNewChild)
+ {
+ if ( !LIBXML_NODE || aNewChild.IsNull() )
+ {
+ User::Leave(KXmlEngErrNullNode);
+ }
+ //
+ if(aNewChild.ParentNode().IsNull())
+ {
+ aNewChild.OwnerDocument().RemoveOwnership(aNewChild);
+ }
+ else
+ {
+ xmlUnlinkNode(INTERNAL_NODEPTR(aNewChild));
+ }
+ xmlNodePtr child = xmlAddChild(LIBXML_NODE, INTERNAL_NODEPTR(aNewChild));
+
+ TEST_OOM_FLAG;
+ return child;
+}
+
+// ---------------------------------------------------------------------------------------------
+// @return Type of the node
+//
+// Use NodeType() to find out the type of the node prior to casting object
+// of TXmlEngNode class to one of its derived subclasses (TXmlEngElement, TXmlEngAttr, TXmlEngTextNode, etc.)
+//
+// @see TXmlEngDOMNodeType
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TXmlEngNode::TXmlEngDOMNodeType TXmlEngNode::NodeType() const
+ {
+ //
+ if((TXmlEngDOMNodeType)LIBXML_NODE->type == EText && TEXT_NODE_DATA_TYPE)
+ {
+ return (TXmlEngDOMNodeType)(TUint)TEXT_NODE_DATA_TYPE;
+ }
+ return (TXmlEngDOMNodeType)LIBXML_NODE->type;
+ }
+
+// Note: "" is used for undefined name; 0 means "to use libxml node's name field"
+static const char* const KNodeNames[]={
+ 0,
+ 0, // EElement = 1,
+ 0, // EAttribute = 2,
+ "#text", // EText = 3,
+ "#cdata-section", // ECDATASection = 4,
+ 0, // EEntityReference = 5,
+ "", // EEntity = 6,
+ 0, // EProcessingInstruction = 7,
+ "#comment", // EComment = 8,
+ 0, // EDocument = 9,
+ 0, // EDocumentType = 10,
+ "#document-fragment", // EDocumentFragment = 11,
+ "", // ENotation = 12,
+ 0, // ENamespaceDeclaration = 18 // not in use
+ "", // EBinaryContainer = 30,
+ "", // EChunkContainer = 31,
+ "" // EFileContainer = 32
+};
+
+const TInt KNodeNamesSize = sizeof(KNodeNames);
+
+// ---------------------------------------------------------------------------------------------
+// @return Name of the node
+//
+// This method generally follows DOM spec :
+// \verbatim
+// -------------------------------------------------------------------------------
+// The values of nodeName, nodeValue, and attributes vary according to the node
+// type as follows:
+//
+// interface nodeName nodeValue attributes
+// -------------------------------------------------------------------------------
+// Attr = Attr.name = Attr.value = null
+// CDATASection = "#cdata-section" = CharacterData.data = null
+// Comment = "#comment" = CharacterData.data = null
+// Document = "#document" = null = null
+// DocumentFragment = "#document-fragment" = null = null
+// DocumentType = DocumentType.name = null = null
+// Element = Element.tagName = null = NamedNodeMap
+// Entity = entity name = null = null
+// EntityReference = name of entity referenced = null = null
+// Notation = notation name = null = null
+// ProcessingInstruction = target = data = null
+// Text = "#text" = CharacterData.data = null
+// -------------------------------------------------------------------------------
+// \endverbatim
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TPtrC8 TXmlEngNode::Name() const
+ {
+ // DONE: OPTIMIZE: Create static array of names with nodetype as index
+ // Use NULL if name is not constant and then use such switch..
+ //
+ TUint type = (TUint) LIBXML_NODE->type;
+ if (type < KNodeNamesSize /sizeof(char*))
+ {
+ const char* KName = KNodeNames[type];
+ if(KName)
+ {
+ return TXmlEngConstString(KName).PtrC8();
+ }
+ return TXmlEngConstString((char*)LIBXML_NODE->name).PtrC8();
+ }
+ return KNullDesC8();
+ }
+
+
+// ---------------------------------------------------------------------------------------------
+// Fetches value of this node, depending on its type.
+//
+// @note It is better to always cast nodes to specific type and then use specific
+// method for getting "node value"
+//
+// @return Node value
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TPtrC8 TXmlEngNode::Value() const
+ {
+ if (iInternal)
+ {
+ switch(LIBXML_NODE->type)
+ {
+ // The content of first Text child is returned
+ case XML_ATTRIBUTE_NODE:
+ return AsAttr().Value();
+ // Note: in DOM spec element's value is Null, but we can
+ // access it: the content of first TXmlEngTextNode child node is returned
+ case XML_ELEMENT_NODE:
+ return AsElement().Text();
+ // TXmlEngTextNode, TXmlEngCDATASection, TXmlEngProcessingInstruction and Comments store
+ // content in the same way.
+ case XML_TEXT_NODE:
+ case XML_CDATA_SECTION_NODE:
+ case XML_COMMENT_NODE:
+ case XML_PI_NODE:
+ return ((TXmlEngConstString)CAST_XMLCHAR_TO_DOMSTRING(LIBXML_NODE->content)).PtrC8();
+
+ default:
+ ;
+ }
+ }
+ return NULL;
+}
+// ---------------------------------------------------------------------------------------------
+// Sets value of this node.
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C void TXmlEngNode::SetValueL(
+ const TDesC8& aValue )
+ {
+ if (iInternal)
+ {
+ switch(LIBXML_NODE->type)
+ {
+ // The content of first TXmlEngTextNode child is returned
+ case XML_ATTRIBUTE_NODE:
+ case XML_ELEMENT_NODE:
+ // Note: in DOM spec element's value is Null, but we can
+ // access it: the content of first TXmlEngTextNode child node is returned
+ AsAttr().SetValueL(aValue); // same as TXmlEngElement::SetTextL(aValue);
+ return;
+ // TXmlEngTextNode, TXmlEngCDATASection, TXmlEngProcessingInstruction and Comments store
+ // content in the same way.
+ case XML_TEXT_NODE:
+ case XML_CDATA_SECTION_NODE:
+ case XML_COMMENT_NODE:
+ case XML_PI_NODE:
+ AsText().SetContentsL(aValue);
+ return;
+ default:
+ ;
+ }
+ }
+ }
+
+
+// ---------------------------------------------------------------------------------------------
+// @return Whether the value of the node is presented by only one TXmlEngTextNode node
+//
+// If the value is <i>"simple text"</i> then it is possible to access it as TDOMString
+// without making copy, which combines values of all text nodes and entity reference nodes.
+//
+// @see TXmlEngNode::Value(), TXmlEngAttr::Value(), TXmlEngElement::Text()
+//
+// This method is applicable to TXmlEngElement and TXmlEngAttr nodes. On other nodes FALSE is returned.
+//
+// @note
+// Values (contents) of TXmlEngComment, TXmlEngCDATASection, TXmlEngTextNode, ProcessingInstuction data are
+// always "simple".
+//
+// When the returned result is FALSE, getting value of the node would not returned
+// whole contents because of either entity references present in the contents or
+// the contents is mixed (for TXmlEngElement node). In this case WholeTextContentsCopyL()
+// should be used.
+//
+// @see TXmlEngNode::WholeTextContentsCopyL()
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TBool TXmlEngNode::IsSimpleTextContents() const
+ {
+ if (!LIBXML_NODE)
+ return false;
+ xmlElementType type = LIBXML_NODE->type;
+ if (type == XML_ELEMENT_NODE ||
+ type == XML_ATTRIBUTE_NODE)
+ {
+ xmlNodePtr children = LIBXML_NODE->children;
+
+ return children && children->type == XML_TEXT_NODE &&
+ !(children->next);
+ }
+ return false; // incorrect type node
+}
+
+// ---------------------------------------------------------------------------------------------
+// @return the content of the node
+//
+// What is returned depends on the node type.
+// Method caller is responsible for freeing returned string.
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C void TXmlEngNode::WholeTextContentsCopyL(RBuf8& aOutput) const
+ {
+ XE_ASSERT_DEBUG(LIBXML_NODE);
+ //
+ xmlChar* text = xmlNodeGetContent(LIBXML_NODE);
+ if (xmlOOMFlag())
+ {
+ if(text)
+ xmlFree(text);
+ OOM_HAPPENED;
+ }
+ xmlCharAssignToRbuf8L(aOutput,text);
+ }
+// -----------------------------------------------------------------------------
+
+EXPORT_C TBool TXmlEngNode::HasChildNodes() const
+ {
+ //
+ return (TBool)LIBXML_NODE->children;
+ }
+
+// ---------------------------------------------------------------------------------------------
+// @return Namespace URI of a node
+// - NULL is returned for elements and attributes that do not
+// belong to any namespace.
+// - bound namespace URI is returned for namespace declaration nodes (instances of TXmlEngNamespace).
+// - NULL is returned to all other types of node.
+// @note use IsNull() and NotNull() for testing returned result on the subject
+// of having some URI
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TPtrC8 TXmlEngNode::NamespaceUri() const
+ {
+ //
+ switch(LIBXML_NODE->type)
+ {
+ case XML_ELEMENT_NODE:
+ case XML_ATTRIBUTE_NODE:
+ return TXmlEngNamespace(LIBXML_NODE->ns).Uri();
+ case XML_NAMESPACE_DECL:
+ return AsNamespace().Uri();
+ default:
+ return NULL;
+ }
+ }
+
+// ---------------------------------------------------------------------------------------------
+// @return Prefix of a node
+//
+// Returns NULL for elements and attributes that do not have prefix
+// (node belongs to the default namespace or does not belong to any namespace)
+// NULL is also returned for all types of node other than TXmlEngElement or TXmlEngAttr
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TPtrC8 TXmlEngNode::Prefix() const
+ {
+ if (LIBXML_NODE->type < XML_TEXT_NODE) // NOTE: XML_ELEMENT_NODE = 1 and XML_ATTRIBUTE_NODE = 2
+ {
+ xmlNs* ns = LIBXML_NODE->ns;
+ if (ns)
+ return ((TXmlEngConstString)CAST_XMLCHAR_TO_DOMSTRING(ns->prefix)).PtrC8();
+ }
+ return KNullDesC8();
+ }
+
+
+// ---------------------------------------------------------------------------------------------
+// @return True if the node is TXmlEngElement and has at least one attribute
+//
+// @note Namespace-to-prefix bindings are not attributes.
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TBool TXmlEngNode::HasAttributes() const
+ {
+ return iInternal &&
+ LIBXML_NODE->type == XML_ELEMENT_NODE &&
+ LIBXML_NODE->properties;
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Evaluates active base URI for the node by processing xml:base attributes of parents
+//
+// @return A copy of effective base URI for the node
+// @note It's up to the caller to free the string with TDOMString::Free()
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C void TXmlEngNode::BaseUriL(RBuf8& aBaseUri) const
+ {
+ //
+ xmlChar* uri = xmlNodeGetBase(LIBXML_NODE->doc, LIBXML_NODE);
+ if (xmlOOMFlag())
+ {
+ if(uri)
+ xmlFree(uri); // partial construction is possible
+ OOM_HAPPENED;
+ }
+ xmlCharAssignToRbuf8L(aBaseUri,uri);
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Searches the prefix that is bound to the given aNamespaceUri and
+// applicable in the scope of this TXmlEngNode.
+//
+// @return A sought prefix or NULL if not found or aNamespaceUri is the default namespace
+// @see TXmlEngElement::LookupNamespaceByUri(TXmlEngNode,TDOMString)
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TPtrC8 TXmlEngNode::LookupPrefixL(
+ const TDesC8& aNamespaceUri ) const
+ {
+ if ( !LIBXML_NODE )
+ {
+ User::Leave(KXmlEngErrNullNode);
+ }
+ //
+ if (LIBXML_NODE->type == XML_ATTRIBUTE_NODE ||
+ LIBXML_NODE->type == XML_ELEMENT_NODE)
+ {
+ return AsElement().LookupNamespaceByUriL(aNamespaceUri).Prefix();
+ }
+ if(!ParentNode().IsNull())
+ {
+ return ParentNode().AsElement().LookupNamespaceByUriL(aNamespaceUri).Prefix();
+ }
+ return KNullDesC8();
+ }
+
+// ---------------------------------------------------------------------------------------------
+// @return True if given namespace URI is a default one for the node (applicable to elements only)
+//
+// @note "" or NULL can be used to denote undefined namespace
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TBool TXmlEngNode::IsDefaultNamespaceL(
+ const TDesC8& aNamespaceUri ) const
+ {
+ if (LIBXML_NODE->type == XML_ELEMENT_NODE) // No default namespaces for attributes
+ {
+ return !AsElement().DefaultNamespaceL().Uri().Compare(aNamespaceUri);
+ }
+ return false;
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Searches the namespace URI that is bound to the given prefix.
+//
+// @return - a sought URI or NULL if the prefix is not bound
+// @see TXmlEngElement::LookupNamespaceByPrefix(TXmlEngNode,TDOMString)
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TPtrC8 TXmlEngNode::LookupNamespaceUriL(
+ const TDesC8& aPrefix ) const
+ {
+ if ( !LIBXML_NODE )
+ {
+ User::Leave(KXmlEngErrNullNode);
+ }
+ //
+ if (LIBXML_NODE->type == XML_ATTRIBUTE_NODE ||
+ LIBXML_NODE->type == XML_ELEMENT_NODE)
+ {
+ return AsElement().LookupNamespaceByPrefixL(aPrefix).Uri();
+ }
+ if(!ParentNode().IsNull())
+ {
+ return ParentNode().AsElement().LookupNamespaceByPrefixL(aPrefix).Uri();
+ }
+ return KNullDesC8();
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Returns the user data object attached to this node. Ownership is not transferred.
+//
+// @return Pointer to data object or NULL if it doesn't exist.
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C MXmlEngUserData* TXmlEngNode::UserData() const
+ {
+ return
+ (LIBXML_NODE &&
+ (LIBXML_NODE->type == XML_ATTRIBUTE_NODE ||
+ LIBXML_NODE->type == XML_ELEMENT_NODE))
+ ?
+ static_cast<MXmlEngUserData*>(LIBXML_NODE->_private)
+ :
+ NULL;
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Removes the user data onject attached to this node. Ownership is transferred
+// (the object is not deleted).
+//
+// @return Pointer to data object or NULL if it doesn't exist.
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C MXmlEngUserData* TXmlEngNode::RemoveUserData()
+ {
+ MXmlEngUserData* data = UserData();
+ if (data)
+ {
+ // node type has been checked by UserData()
+ LIBXML_NODE->_private = NULL;
+ }
+ return data;
+ }
+
+// ---------------------------------------------------------------------------------------------
+// Attaches a user data object to this node. The ownership of the object is transferred.
+// When the (underlying) node is deleted the Destroy method of the MXmlEngUserData class will be
+// called. If there already is a user data object associated with this node, it will be
+// deleted before attaching the new object. Notet that only TXmlEngElement and Attribute nodes
+// currently support this feature.
+//
+// @param[in] aData Pointer to the data object.
+// @return true if successful, false if for example underlying node type doesn't support
+// attaching user data.
+// ---------------------------------------------------------------------------------------------
+//
+EXPORT_C TBool TXmlEngNode::AddUserData(
+ MXmlEngUserData* aData )
+ {
+ TBool ret = false;
+ if (iInternal)
+ {
+ if (LIBXML_NODE->type == XML_ATTRIBUTE_NODE ||
+ LIBXML_NODE->type == XML_ELEMENT_NODE)
+ {
+ // release previous data
+ if (LIBXML_NODE->_private)
+ {
+ MXmlEngUserData* oldData = RemoveUserData();
+ oldData->Destroy();
+ }
+ LIBXML_NODE->_private = aData;
+ ret = true;
+ }
+ }
+ return ret;
+ }
+