merge the formfield patch from ooo-build
[ooovba.git] / unoxml / source / dom / node.cxx
blob84533ab5372748c07ec17d5833c19c5b86bf4067
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: node.cxx,v $
10 * $Revision: 1.17 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include <stdio.h>
32 #include <string.h>
33 #include "node.hxx"
34 #include "element.hxx"
35 #include "text.hxx"
36 #include "cdatasection.hxx"
37 #include "entityreference.hxx"
38 #include "entity.hxx"
39 #include "processinginstruction.hxx"
40 #include "comment.hxx"
41 #include "document.hxx"
42 #include "documenttype.hxx"
43 #include "documentfragment.hxx"
44 #include "notation.hxx"
45 #include "childlist.hxx"
46 #include "attr.hxx"
48 #include <com/sun/star/xml/sax/FastToken.hpp>
50 #include "../events/eventdispatcher.hxx"
51 #include "../events/mutationevent.hxx"
53 #include <boost/bind.hpp>
54 #include <algorithm>
56 namespace DOM
58 void pushContext(Context& io_rContext)
60 io_rContext.maNamespaces.push_back(
61 io_rContext.maNamespaces.back());
64 void popContext(Context& io_rContext)
66 io_rContext.maNamespaces.pop_back();
69 void addNamespaces(Context& io_rContext, xmlNodePtr pNode)
71 // add node's namespaces to current context
72 for (xmlNsPtr pNs = pNode->nsDef; pNs != 0; pNs = pNs->next) {
73 const xmlChar *pPrefix = pNs->prefix;
74 OString prefix(reinterpret_cast<const sal_Char*>(pPrefix),
75 strlen(reinterpret_cast<const char*>(pPrefix)));
76 const xmlChar *pHref = pNs->href;
77 OUString val(reinterpret_cast<const sal_Char*>(pHref),
78 strlen(reinterpret_cast<const char*>(pHref)),
79 RTL_TEXTENCODING_UTF8);
81 OSL_TRACE("Trying to add namespace %s (prefix %s)",
82 (const char*)pHref, (const char*)pPrefix);
84 Context::NamespaceMapType::iterator aIter=
85 io_rContext.maNamespaceMap.find(val);
86 if( aIter != io_rContext.maNamespaceMap.end() )
88 Context::Namespace aNS;
89 aNS.maPrefix = prefix;
90 aNS.mnToken = aIter->second;
91 aNS.maNamespaceURL = val;
93 io_rContext.maNamespaces.back().push_back(aNS);
95 OSL_TRACE("Added with token 0x%x", aIter->second);
100 sal_Int32 getToken( const Context& rContext, const sal_Char* pToken )
102 const Sequence<sal_Int8> aSeq( (sal_Int8*)pToken, strlen( pToken ) );
103 return rContext.mxTokenHandler->getTokenFromUTF8( aSeq );
106 sal_Int32 getTokenWithPrefix( const Context& rContext, const sal_Char* pPrefix, const sal_Char* pName )
108 sal_Int32 nNamespaceToken = FastToken::DONTKNOW;
109 OString prefix(pPrefix,
110 strlen(reinterpret_cast<const char*>(pPrefix)));
112 OSL_TRACE("getTokenWithPrefix(): prefix %s, name %s",
113 (const char*)pPrefix, (const char*)pName);
115 Context::NamespaceVectorType::value_type::const_iterator aIter;
116 if( (aIter=std::find_if(rContext.maNamespaces.back().begin(),
117 rContext.maNamespaces.back().end(),
118 boost::bind(std::equal_to<OString>(),
119 boost::bind(&Context::Namespace::getPrefix,
120 _1),
121 boost::cref(prefix)))) != rContext.maNamespaces.back().end() )
123 nNamespaceToken = aIter->mnToken;
124 sal_Int32 nNameToken = getToken( rContext, pName );
125 if( nNameToken != FastToken::DONTKNOW )
126 nNamespaceToken |= nNameToken;
129 return nNamespaceToken;
133 nodemap_t CNode::theNodeMap;
135 void CNode::remove(const xmlNodePtr aNode)
137 nodemap_t::iterator i = CNode::theNodeMap.find(aNode);
138 if (i != CNode::theNodeMap.end())
140 // CNode *pNode = i->second;
141 CNode::theNodeMap.erase(i);
146 CNode* CNode::get(const xmlNodePtr aNode, sal_Bool bCreate)
148 CNode* pNode = 0;
149 if (aNode == NULL)
150 return 0;
152 //check whether there is already an instance for this node
153 nodemap_t::const_iterator i = CNode::theNodeMap.find(aNode);
154 if (i != CNode::theNodeMap.end())
156 pNode = i->second;
157 } else
160 // there is not yet an instance wrapping this node,
161 // create it and store it in the map
162 if (!bCreate) return NULL;
164 switch (aNode->type)
166 case XML_ELEMENT_NODE:
167 // m_aNodeType = NodeType::ELEMENT_NODE;
168 pNode = static_cast< CNode* >(new CElement(aNode));
169 break;
170 case XML_TEXT_NODE:
171 // m_aNodeType = NodeType::TEXT_NODE;
172 pNode = static_cast< CNode* >(new CText(aNode));
173 break;
174 case XML_CDATA_SECTION_NODE:
175 // m_aNodeType = NodeType::CDATA_SECTION_NODE;
176 pNode = static_cast< CNode* >(new CCDATASection(aNode));
177 break;
178 case XML_ENTITY_REF_NODE:
179 // m_aNodeType = NodeType::ENTITY_REFERENCE_NODE;
180 pNode = static_cast< CNode* >(new CEntityReference(aNode));
181 break;
182 case XML_ENTITY_NODE:
183 // m_aNodeType = NodeType::ENTITY_NODE;
184 pNode = static_cast< CNode* >(new CEntity((xmlEntityPtr)aNode));
185 break;
186 case XML_PI_NODE:
187 // m_aNodeType = NodeType::PROCESSING_INSTRUCTION_NODE;
188 pNode = static_cast< CNode* >(new CProcessingInstruction(aNode));
189 break;
190 case XML_COMMENT_NODE:
191 // m_aNodeType = NodeType::COMMENT_NODE;
192 pNode = static_cast< CNode* >(new CComment(aNode));
193 break;
194 case XML_DOCUMENT_NODE:
195 // m_aNodeType = NodeType::DOCUMENT_NODE;
196 pNode = static_cast< CNode* >(new CDocument((xmlDocPtr)aNode));
197 break;
198 case XML_DOCUMENT_TYPE_NODE:
199 case XML_DTD_NODE:
200 // m_aNodeType = NodeType::DOCUMENT_TYPE_NODE;
201 pNode = static_cast< CNode* >(new CDocumentType((xmlDtdPtr)aNode));
202 break;
203 case XML_DOCUMENT_FRAG_NODE:
204 // m_aNodeType = NodeType::DOCUMENT_FRAGMENT_NODE;
205 pNode = static_cast< CNode* >(new CDocumentFragment(aNode));
206 break;
207 case XML_NOTATION_NODE:
208 // m_aNodeType = NodeType::NOTATION_NODE;
209 pNode = static_cast< CNode* >(new CNotation((xmlNotationPtr)aNode));
210 break;
211 case XML_ATTRIBUTE_NODE:
212 // m_aNodeType = NodeType::NOTATION_NODE;
213 pNode = static_cast< CNode* >(new CAttr((xmlAttrPtr)aNode));
214 break;
215 // unsopported node types
216 case XML_HTML_DOCUMENT_NODE:
217 case XML_ELEMENT_DECL:
218 case XML_ATTRIBUTE_DECL:
219 case XML_ENTITY_DECL:
220 case XML_NAMESPACE_DECL:
221 default:
222 pNode = 0;
223 break;
226 if ( pNode != 0 )
228 if(CNode::theNodeMap.insert(nodemap_t::value_type(aNode, pNode)).second)
230 // insertion done, register node with document
231 xmlDocPtr doc = aNode->doc;
232 if( doc != NULL)
234 CDocument* pDoc = static_cast< CDocument* >(CNode::get((xmlNodePtr)doc));
235 pDoc->addnode(aNode);
236 } else
238 // if insertion failed, delete the new instance and return null
239 delete pNode;
240 pNode = 0;
244 OSL_ENSURE(pNode, "no node produced during CNode::get!");
245 return pNode;
248 xmlNodePtr CNode::getNodePtr(const Reference< XNode >& aNode)
250 try {
251 CNode* pNode=dynamic_cast<CNode*>(aNode.get());
252 if( pNode )
253 return pNode->m_aNodePtr;
255 catch(...) {}
256 return 0;
259 CNode::CNode()
260 : m_aNodePtr(0)
264 void CNode::init_node(const xmlNodePtr aNode)
266 m_aNodePtr = aNode;
268 // keep containing document alive
269 // (if we are not that document ourselves)
270 if (m_aNodePtr->type != XML_DOCUMENT_NODE)
271 m_rDocument = getOwnerDocument();
274 CNode::~CNode()
276 //remove from list if this wrapper goes away
277 if (m_aNodePtr != 0)
278 CNode::remove(m_aNodePtr);
281 static void _nsexchange(const xmlNodePtr aNode, xmlNsPtr oldNs, xmlNsPtr newNs)
283 // recursively exchange any references to oldNs with references to newNs
284 xmlNodePtr cur = aNode;
285 while (cur != 0)
287 if (cur->ns == oldNs)
288 cur->ns = newNs;
289 if (cur->type == XML_ELEMENT_NODE)
291 xmlAttrPtr curAttr = cur->properties;
292 while(curAttr != 0)
294 if (curAttr->ns == oldNs)
295 curAttr->ns = newNs;
296 curAttr = curAttr->next;
298 _nsexchange(cur->children, oldNs, newNs);
300 cur = cur->next;
304 /*static*/ void _nscleanup(const xmlNodePtr aNode, const xmlNodePtr aParent)
306 xmlNodePtr cur = aNode;
308 //handle attributes
309 if (cur != NULL && cur->type == XML_ELEMENT_NODE)
311 xmlAttrPtr curAttr = cur->properties;
312 while(curAttr != 0)
314 if (curAttr->ns != NULL)
316 xmlNsPtr ns = xmlSearchNs(cur->doc, aParent, curAttr->ns->prefix);
317 if (ns != NULL)
318 curAttr->ns = ns;
320 curAttr = curAttr->next;
324 while (cur != NULL)
326 _nscleanup(cur->children, cur);
327 if (cur->ns != NULL)
329 xmlNsPtr ns = xmlSearchNs(cur->doc, aParent, cur->ns->prefix);
330 if (ns != NULL && ns != cur->ns && strcmp((char*)ns->href, (char*)cur->ns->href)==0)
332 xmlNsPtr curDef = cur->nsDef;
333 xmlNsPtr *refp = &(cur->nsDef); // insert point
334 while (curDef != NULL)
336 ns = xmlSearchNs(cur->doc, aParent, curDef->prefix);
337 if (ns != NULL && ns != curDef && strcmp((char*)ns->href, (char*)curDef->href)==0)
339 // reconnect ns pointers in sub-tree to newly found ns before
340 // removing redundant nsdecl to prevent dangling pointers.
341 _nsexchange(cur, curDef, ns);
342 *refp = curDef->next;
343 xmlFreeNs(curDef);
344 curDef = *refp;
345 } else {
346 refp = &(curDef->next);
347 curDef = curDef->next;
352 cur = cur->next;
356 void SAL_CALL CNode::saxify(
357 const Reference< XDocumentHandler >& i_xHandler) {
358 if (!i_xHandler.is()) throw RuntimeException();
359 // default: do nothing
362 void SAL_CALL CNode::fastSaxify(Context& io_rContext) {
363 if (!io_rContext.mxDocHandler.is()) throw RuntimeException();
364 // default: do nothing
367 /**
368 Adds the node newChild to the end of the list of children of this node.
370 Reference< XNode > CNode::appendChild(const Reference< XNode >& newChild)
371 throw (RuntimeException, DOMException)
373 Reference< XNode> aNode;
374 if (m_aNodePtr != NULL) {
375 xmlNodePtr cur = CNode::getNodePtr(newChild.get());
377 // error checks:
378 // from other document
379 if (cur->doc != m_aNodePtr->doc) {
380 DOMException e;
381 e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
382 throw e;
384 // same node
385 if (cur == m_aNodePtr) {
386 DOMException e;
387 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
388 throw e;
390 // already has parant and is not attribute
391 if (cur->parent != NULL && cur->type != XML_ATTRIBUTE_NODE) {
392 DOMException e;
393 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
394 throw e;
397 // check whether this is an attribute node so we remove it's
398 // carrier node if it has one
399 xmlNodePtr res = NULL;
400 if (cur->type == XML_ATTRIBUTE_NODE)
402 if (cur->parent != NULL)
404 if (m_aNodePtr->type != XML_ELEMENT_NODE ||
405 strcmp((char*)cur->parent->name, "__private") != 0)
407 DOMException e;
408 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
409 throw e;
412 xmlNsPtr pAttrNs = cur->ns;
413 xmlNsPtr pParentNs = xmlSearchNs(m_aNodePtr->doc, m_aNodePtr, pAttrNs->prefix);
414 if (pParentNs == NULL || strcmp((char*)pParentNs->href, (char*)pAttrNs->href) != 0)
415 pParentNs = xmlNewNs(m_aNodePtr, pAttrNs->href, pAttrNs->prefix);
417 if (cur->children != NULL)
418 res = (xmlNodePtr)xmlNewNsProp(m_aNodePtr, pParentNs, cur->name, cur->children->content);
419 else
420 res = (xmlNodePtr)xmlNewProp(m_aNodePtr, cur->name, (xmlChar*) "");
422 xmlFreeNode(cur->parent);
423 cur->parent = NULL;
425 else
427 if (cur->children != NULL)
428 res = (xmlNodePtr)xmlNewProp(m_aNodePtr, cur->name, cur->children->content);
429 else
430 res = (xmlNodePtr)xmlNewProp(m_aNodePtr, cur->name, (xmlChar*) "");
433 else
435 res = xmlAddChild(m_aNodePtr, cur);
438 // libxml can do optimizations, when appending nodes.
439 // if res != cur, something was optimized and the newchild-wrapper
440 // should be updated
441 if (cur != res)
442 CNode::remove(cur);
444 // use custom ns cleanup instaead of
445 // xmlReconciliateNs(m_aNodePtr->doc, m_aNodePtr);
446 // because that will not remove unneeded ns decls
447 _nscleanup(res, m_aNodePtr);
449 aNode = Reference< XNode>(CNode::get(res));
451 //XXX check for errors
453 // dispatch DOMNodeInserted event, target is the new node
454 // this node is the related node
455 // does bubble
456 if (aNode.is())
458 Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
459 Reference< XMutationEvent > event(docevent->createEvent(
460 OUString::createFromAscii("DOMNodeInserted")), UNO_QUERY);
461 event->initMutationEvent(OUString::createFromAscii("DOMNodeInserted")
462 , sal_True, sal_False, Reference< XNode >(CNode::get(m_aNodePtr)),
463 OUString(), OUString(), OUString(), (AttrChangeType)0 );
464 dispatchEvent(Reference< XEvent >(event, UNO_QUERY));
466 // dispatch subtree modified for this node
467 dispatchSubtreeModified();
469 return aNode;
473 Returns a duplicate of this node, i.e., serves as a generic copy
474 constructor for nodes.
476 Reference< XNode > CNode::cloneNode(sal_Bool bDeep)
477 throw (RuntimeException)
479 Reference< XNode> aNode;
480 if (m_aNodePtr != NULL)
482 aNode = Reference< XNode>(CNode::get(
483 xmlCopyNode (m_aNodePtr, static_cast< int >(bDeep))
486 //XXX check for errors
487 return aNode;
491 A NamedNodeMap containing the attributes of this node (if it is an Element)
492 or null otherwise.
494 Reference< XNamedNodeMap > CNode::getAttributes()
495 throw (RuntimeException)
497 // return empty reference
498 // only element node may override this impl
499 return Reference< XNamedNodeMap>();
501 // get all children that are attributes
502 /* --> CElement
503 Reference< NamedNodeMap > aNodeMap(new AttributeNamedNodeMap(m_aNodePtr), UNO_QUERY);
504 return aNodeMap;
509 A NodeList that contains all children of this node.
511 Reference< XNodeList > CNode::getChildNodes()
512 throw (RuntimeException)
514 Reference< XNodeList > aNodeList;
515 if (m_aNodePtr != NULL)
517 aNodeList = Reference< XNodeList >(new CChildList(CNode::get(m_aNodePtr)));
519 // XXX check for errors?
520 return aNodeList;
524 The first child of this node.
526 Reference< XNode > CNode::getFirstChild()
527 throw (RuntimeException)
529 Reference< XNode > aNode;
530 if (m_aNodePtr != NULL) {
531 aNode = Reference< XNode >(CNode::get(m_aNodePtr->children));
533 return aNode;
537 The last child of this node.
539 Reference< XNode > SAL_CALL CNode::getLastChild()
540 throw (RuntimeException)
542 Reference< XNode > aNode;
543 if (m_aNodePtr != NULL) {
544 aNode = Reference< XNode >(CNode::get(xmlGetLastChild(m_aNodePtr)));
546 return aNode;
550 Returns the local part of the qualified name of this node.
552 OUString SAL_CALL CNode::getLocalName()
553 throw (RuntimeException)
555 OUString aName;
557 --> Element / Attribute
558 if(m_aNodePtr != NULL && (m_aNodeType == NodeType::ATTRIBUTE_NODE
559 || m_aNodeType == NodeType::ELEMENT_NODE))
561 aName = OUString(m_aNodePtr->name, RTL_TEXTENCODING_UTF8);
563 //XXX error checking
565 return aName;
570 The namespace URI of this node, or null if it is unspecified.
572 OUString SAL_CALL CNode::getNamespaceURI()
573 throw (RuntimeException)
575 OUString aURI;
576 if (m_aNodePtr != NULL &&
577 (m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) &&
578 m_aNodePtr->ns != NULL)
580 const xmlChar* xHref = m_aNodePtr->ns->href;
581 aURI = OUString((sal_Char*)xHref, strlen((char*)xHref), RTL_TEXTENCODING_UTF8);
583 return aURI;
587 The node immediately following this node.
589 Reference< XNode > SAL_CALL CNode::getNextSibling()
590 throw (RuntimeException)
592 Reference< XNode > aNode;
593 if(m_aNodePtr != NULL)
595 aNode = Reference< XNode >(CNode::get(m_aNodePtr->next));
597 return aNode;
601 The name of this node, depending on its type; see the table above.
603 OUString SAL_CALL CNode::getNodeName()
604 throw (RuntimeException)
607 Interface nodeName nodeValue attributes
608 --------------------------------------------------------------------------------------
609 Attr name of attribute value of attribute null
610 CDATASection "#cdata-section" content of the CDATA Section null
611 Comment "#comment" content of the comment null
612 Document "#document" null null
613 DocumentFragment "#document-fragment" null null
614 DocumentType document type name null null
615 Element tag name null NamedNodeMap
616 Entity entity name null null
617 EntityReference name of entity null null
618 referenced
619 Notation notation name null null
620 Processing\ target entire content excluding null
621 Instruction the target
622 Text "#text" content of the text node null
624 OUString aName;
625 return aName;
629 A code representing the type of the underlying object, as defined above.
631 NodeType SAL_CALL CNode::getNodeType()
632 throw (RuntimeException)
634 return m_aNodeType;
638 The value of this node, depending on its type; see the table above.
640 OUString SAL_CALL CNode::getNodeValue()
641 throw (RuntimeException)
643 OUString aValue;
644 return aValue;
648 The Document object associated with this node.
650 Reference< XDocument > SAL_CALL CNode::getOwnerDocument()
651 throw (RuntimeException)
653 Reference<XDocument> aDoc;
654 if (m_aNodePtr != NULL)
656 aDoc = Reference< XDocument >(static_cast< CDocument* >(
657 CNode::get((xmlNodePtr)m_aNodePtr->doc)));
659 return aDoc;
664 The parent of this node.
666 Reference< XNode > SAL_CALL CNode::getParentNode()
667 throw (RuntimeException)
669 Reference<XNode> aNode;
670 if (m_aNodePtr != NULL)
672 aNode = Reference< XNode >(CNode::get(m_aNodePtr->parent));
674 return aNode;
678 The namespace prefix of this node, or null if it is unspecified.
680 OUString SAL_CALL CNode::getPrefix()
681 throw (RuntimeException)
683 OUString aPrefix;
684 if (m_aNodePtr != NULL &&
685 (m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) &&
686 m_aNodePtr->ns != NULL)
688 const xmlChar* xPrefix = m_aNodePtr->ns->prefix;
689 if( xPrefix != NULL )
690 aPrefix = OUString((sal_Char*)xPrefix, strlen((char*)xPrefix), RTL_TEXTENCODING_UTF8);
692 return aPrefix;
697 The node immediately preceding this node.
699 Reference< XNode > SAL_CALL CNode::getPreviousSibling()
700 throw (RuntimeException)
702 Reference< XNode > aNode;
703 if (m_aNodePtr != NULL)
705 aNode = Reference< XNode >(CNode::get(m_aNodePtr->prev));
707 return aNode;
711 Returns whether this node (if it is an element) has any attributes.
713 sal_Bool SAL_CALL CNode::hasAttributes()
714 throw (RuntimeException)
716 return (m_aNodePtr != NULL && m_aNodePtr->properties != NULL);
720 Returns whether this node has any children.
722 sal_Bool SAL_CALL CNode::hasChildNodes()
723 throw (RuntimeException)
725 return (m_aNodePtr != NULL && m_aNodePtr->children != NULL);
729 Inserts the node newChild before the existing child node refChild.
731 Reference< XNode > SAL_CALL CNode::insertBefore(
732 const Reference< XNode >& newChild, const Reference< XNode >& refChild)
733 throw (RuntimeException, DOMException)
736 if (newChild->getOwnerDocument() != getOwnerDocument()) {
737 DOMException e;
738 e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
739 throw e;
741 if (refChild->getParentNode() != Reference< XNode >(this)) {
742 DOMException e;
743 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
744 throw e;
747 xmlNodePtr pRefChild = CNode::getNodePtr(refChild.get());
748 xmlNodePtr pNewChild = CNode::getNodePtr(newChild.get());
749 xmlNodePtr cur = m_aNodePtr->children;
751 //search cild before which to insert
752 while (cur != NULL)
754 if (cur == pRefChild) {
755 // insert before
756 pNewChild->next = cur;
757 pNewChild->prev = cur->prev;
758 cur->prev = pNewChild;
759 if( pNewChild->prev != NULL)
760 pNewChild->prev->next = pNewChild;
762 cur = cur->next;
764 return refChild;
768 Tests whether the DOM implementation implements a specific feature and
769 that feature is supported by this node.
771 sal_Bool SAL_CALL CNode::isSupported(const OUString& /*feature*/, const OUString& /*ver*/)
772 throw (RuntimeException)
774 // XXX
775 return sal_False;
779 Puts all Text nodes in the full depth of the sub-tree underneath this
780 Node, including attribute nodes, into a "normal" form where only structure
781 (e.g., elements, comments, processing instructions, CDATA sections, and
782 entity references) separates Text nodes, i.e., there are neither adjacent
783 Text nodes nor empty Text nodes.
785 void SAL_CALL CNode::normalize()
786 throw (RuntimeException)
788 //XXX combine adjacent text nodes and remove empty ones
792 Removes the child node indicated by oldChild from the list of children,
793 and returns it.
795 Reference< XNode > SAL_CALL CNode::removeChild(const Reference< XNode >& oldChild)
796 throw (RuntimeException, DOMException)
799 if (oldChild->getParentNode() != Reference< XNode >(this)) {
800 DOMException e;
801 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
802 throw e;
805 Reference<XNode> xReturn( oldChild );
807 xmlNodePtr old = CNode::getNodePtr(oldChild);
809 if( old->type == XML_ATTRIBUTE_NODE )
811 xmlAttrPtr pAttr = (xmlAttrPtr) old;
812 xmlRemoveProp( pAttr );
813 xReturn.clear();
815 else
818 // update .last
819 if (m_aNodePtr->last == old)
820 m_aNodePtr->last = old->prev;
822 xmlNodePtr cur = m_aNodePtr->children;
823 //find old node in child list
824 while (cur != NULL)
826 if(cur == old)
828 // unlink node from list
829 if (cur->prev != NULL)
830 cur->prev->next = cur->next;
831 if (cur->next != NULL)
832 cur->next->prev = cur->prev;
833 if (cur->parent != NULL && cur->parent->children == cur)
834 cur->parent->children = cur->next;
835 cur->prev = NULL;
836 cur->next = NULL;
837 cur->parent = NULL;
839 cur = cur->next;
843 /*DOMNodeRemoved
844 * Fired when a node is being removed from its parent node.
845 * This event is dispatched before the node is removed from the tree.
846 * The target of this event is the node being removed.
847 * Bubbles: Yes
848 * Cancelable: No
849 * Context Info: relatedNode holds the parent node
851 if (oldChild.is())
853 Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
854 Reference< XMutationEvent > event(docevent->createEvent(
855 OUString::createFromAscii("DOMNodeRemoved")), UNO_QUERY);
856 event->initMutationEvent(OUString::createFromAscii("DOMNodeRemoved"), sal_True,
857 sal_False, Reference< XNode >(CNode::get(m_aNodePtr)),
858 OUString(), OUString(), OUString(), (AttrChangeType)0 );
859 dispatchEvent(Reference< XEvent >(event, UNO_QUERY));
861 // subtree modofied for this node
862 dispatchSubtreeModified();
864 return xReturn;
868 Replaces the child node oldChild with newChild in the list of children,
869 and returns the oldChild node.
871 Reference< XNode > SAL_CALL CNode::replaceChild(
872 const Reference< XNode >& newChild, const Reference< XNode >& oldChild)
873 throw (RuntimeException, DOMException)
875 // XXX check node types
877 if (oldChild->getParentNode() != Reference< XNode >(this)) {
878 DOMException e;
879 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
880 throw e;
884 Reference< XNode > aNode = removeChild(oldChild);
885 appendChild(newChild);
887 xmlNodePtr pOld = CNode::getNodePtr(oldChild);
888 xmlNodePtr pNew = CNode::getNodePtr(newChild);
890 if( pOld->type == XML_ATTRIBUTE_NODE )
892 // can only replace attribute with attribute
893 if ( pOld->type != pNew->type )
895 DOMException e;
896 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
897 throw e;
900 xmlAttrPtr pAttr = (xmlAttrPtr)pOld;
901 xmlRemoveProp( pAttr );
902 appendChild( newChild );
904 else
907 xmlNodePtr cur = m_aNodePtr->children;
908 //find old node in child list
909 while (cur != NULL)
911 if(cur == pOld)
913 // exchange nodes
914 pNew->prev = pOld->prev;
915 if (pNew->prev != NULL)
916 pNew->prev->next = pNew;
917 pNew->next = pOld->next;
918 if (pNew->next != NULL)
919 pNew->next->prev = pNew;
920 pNew->parent = pOld->parent;
921 if(pNew->parent->children == pOld)
922 pNew->parent->children = pNew;
923 if(pNew->parent->last == pOld)
924 pNew->parent->last = pNew;
925 pOld->next = NULL;
926 pOld->prev = NULL;
927 pOld->parent = NULL;
929 cur = cur->next;
933 dispatchSubtreeModified();
935 return oldChild;
938 void CNode::dispatchSubtreeModified()
940 // dispatch DOMSubtreeModified
941 // target is _this_ node
942 Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
943 Reference< XMutationEvent > event(docevent->createEvent(
944 OUString::createFromAscii("DOMSubtreeModified")), UNO_QUERY);
945 event->initMutationEvent(OUString::createFromAscii("DOMSubtreeModified"), sal_True,
946 sal_False, Reference< XNode >(),
947 OUString(), OUString(), OUString(), (AttrChangeType)0 );
948 dispatchEvent(Reference< XEvent >(event, UNO_QUERY));
952 The value of this node, depending on its type; see the table above.
954 void SAL_CALL CNode::setNodeValue(const OUString& /*nodeValue*/)
955 throw (RuntimeException, DOMException)
957 // use specific node implememntation
958 // if we end up down here, something went wrong
959 DOMException e;
960 e.Code = DOMExceptionType_NO_MODIFICATION_ALLOWED_ERR;
961 throw e;
965 The namespace prefix of this node, or null if it is unspecified.
967 void SAL_CALL CNode::setPrefix(const OUString& prefix)
968 throw (RuntimeException, DOMException)
970 OString o1 = OUStringToOString(prefix, RTL_TEXTENCODING_UTF8);
971 xmlChar *pBuf = (xmlChar*)o1.getStr();
972 // XXX copy buf?
973 // XXX free old string? (leak?)
974 if (m_aNodePtr != NULL && m_aNodePtr->ns != NULL)
976 m_aNodePtr->ns->prefix = pBuf;
981 // --- XEventTarget
982 void SAL_CALL CNode::addEventListener(const OUString& eventType,
983 const Reference< com::sun::star::xml::dom::events::XEventListener >& listener,
984 sal_Bool useCapture)
985 throw (RuntimeException)
987 events::CEventDispatcher::addListener(m_aNodePtr, eventType, listener, useCapture);
990 void SAL_CALL CNode::removeEventListener(const OUString& eventType,
991 const Reference< com::sun::star::xml::dom::events::XEventListener >& listener,
992 sal_Bool useCapture)
993 throw (RuntimeException)
995 events::CEventDispatcher::removeListener(m_aNodePtr, eventType, listener, useCapture);
998 sal_Bool SAL_CALL CNode::dispatchEvent(const Reference< XEvent >& evt)
999 throw(RuntimeException, EventException)
1001 events::CEventDispatcher::dispatchEvent(m_aNodePtr, evt);
1002 return sal_True;