1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/uno/Sequence.h>
22 #include "document.hxx"
24 #include "element.hxx"
25 #include "cdatasection.hxx"
26 #include "documentfragment.hxx"
28 #include "comment.hxx"
29 #include "processinginstruction.hxx"
30 #include "entityreference.hxx"
31 #include "documenttype.hxx"
32 #include "elementlist.hxx"
33 #include "domimplementation.hxx"
35 #include <notation.hxx>
37 #include "../events/event.hxx"
38 #include "../events/mutationevent.hxx"
39 #include "../events/uievent.hxx"
40 #include "../events/mouseevent.hxx"
41 #include "../events/eventdispatcher.hxx"
45 #include <com/sun/star/xml/sax/FastToken.hpp>
46 #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
50 static xmlNodePtr
lcl_getDocumentType(xmlDocPtr
const i_pDocument
)
53 xmlNodePtr cur
= i_pDocument
->children
;
56 if ((cur
->type
== XML_DOCUMENT_TYPE_NODE
) ||
57 (cur
->type
== XML_DTD_NODE
)) {
64 /// get the pointer to the root element node of the document
65 static xmlNodePtr
lcl_getDocumentRootPtr(xmlDocPtr
const i_pDocument
)
67 // find the document element
68 xmlNodePtr cur
= i_pDocument
->children
;
71 if (cur
->type
== XML_ELEMENT_NODE
)
78 CDocument::CDocument(xmlDocPtr
const pDoc
)
79 : CDocument_Base(*this, m_Mutex
,
80 NodeType_DOCUMENT_NODE
, reinterpret_cast<xmlNodePtr
>(pDoc
))
83 , m_pEventDispatcher(new events::CEventDispatcher())
87 ::rtl::Reference
<CDocument
> CDocument::CreateCDocument(xmlDocPtr
const pDoc
)
89 ::rtl::Reference
<CDocument
> const xDoc(new CDocument(pDoc
));
90 // add the doc itself to its nodemap!
91 xDoc
->m_NodeMap
.insert(
92 nodemap_t::value_type(reinterpret_cast<xmlNodePtr
>(pDoc
),
94 WeakReference
<XNode
>(static_cast<XDocument
*>(xDoc
.get())),
99 CDocument::~CDocument()
101 ::osl::MutexGuard
const g(m_Mutex
);
103 // node map must be empty now, otherwise CDocument must not die!
104 for (nodemap_t::iterator i
= m_NodeMap
.begin();
105 i
!= m_NodeMap
.end(); ++i
)
107 Reference
<XNode
> const xNode(i
->second
.first
);
108 OSL_ENSURE(!xNode
.is(),
109 "CDocument::~CDocument(): ERROR: live node in document node map!");
112 xmlFreeDoc(m_aDocPtr
);
116 events::CEventDispatcher
& CDocument::GetEventDispatcher()
118 return *m_pEventDispatcher
;
121 ::rtl::Reference
< CElement
> CDocument::GetDocumentElement()
123 xmlNodePtr
const pNode
= lcl_getDocumentRootPtr(m_aDocPtr
);
124 ::rtl::Reference
< CElement
> const xRet(
125 dynamic_cast<CElement
*>(GetCNode(pNode
).get()));
130 CDocument::RemoveCNode(xmlNodePtr
const pNode
, CNode
const*const pCNode
)
132 nodemap_t::iterator
const i
= m_NodeMap
.find(pNode
);
133 if (i
!= m_NodeMap
.end()) {
134 // #i113681# consider this scenario:
136 // T2 calls getCNode: lookup will find i->second->first invalid
137 // so a new CNode is created and inserted
138 // T1 calls removeCNode: i->second->second now points to a
139 // different CNode instance!
141 // check that the CNode is the right one
142 CNode
*const pCurrent
= i
->second
.second
;
143 if (pCurrent
== pCNode
) {
149 /** NB: this is the CNode factory.
150 it is the only place where CNodes may be instantiated.
151 all CNodes must be registered at the m_NodeMap.
153 ::rtl::Reference
<CNode
>
154 CDocument::GetCNode(xmlNodePtr
const pNode
, bool const bCreate
)
159 //check whether there is already an instance for this node
160 nodemap_t::const_iterator
const i
= m_NodeMap
.find(pNode
);
161 if (i
!= m_NodeMap
.end()) {
162 // #i113681# check that the CNode is still alive
163 uno::Reference
<XNode
> const xNode(i
->second
.first
);
166 ::rtl::Reference
<CNode
> ret(i
->second
.second
);
167 OSL_ASSERT(ret
.is());
172 if (!bCreate
) { return 0; }
174 // there is not yet an instance wrapping this node,
175 // create it and store it in the map
177 ::rtl::Reference
<CNode
> pCNode
;
180 case XML_ELEMENT_NODE
:
181 // m_aNodeType = NodeType::ELEMENT_NODE;
182 pCNode
= static_cast< CNode
* >(
183 new CElement(*this, m_Mutex
, pNode
));
186 // m_aNodeType = NodeType::TEXT_NODE;
187 pCNode
= static_cast< CNode
* >(
188 new CText(*this, m_Mutex
, pNode
));
190 case XML_CDATA_SECTION_NODE
:
191 // m_aNodeType = NodeType::CDATA_SECTION_NODE;
192 pCNode
= static_cast< CNode
* >(
193 new CCDATASection(*this, m_Mutex
, pNode
));
195 case XML_ENTITY_REF_NODE
:
196 // m_aNodeType = NodeType::ENTITY_REFERENCE_NODE;
197 pCNode
= static_cast< CNode
* >(
198 new CEntityReference(*this, m_Mutex
, pNode
));
200 case XML_ENTITY_NODE
:
201 // m_aNodeType = NodeType::ENTITY_NODE;
202 pCNode
= static_cast< CNode
* >(new CEntity(*this, m_Mutex
,
203 reinterpret_cast<xmlEntityPtr
>(pNode
)));
206 // m_aNodeType = NodeType::PROCESSING_INSTRUCTION_NODE;
207 pCNode
= static_cast< CNode
* >(
208 new CProcessingInstruction(*this, m_Mutex
, pNode
));
210 case XML_COMMENT_NODE
:
211 // m_aNodeType = NodeType::COMMENT_NODE;
212 pCNode
= static_cast< CNode
* >(
213 new CComment(*this, m_Mutex
, pNode
));
215 case XML_DOCUMENT_NODE
:
216 // m_aNodeType = NodeType::DOCUMENT_NODE;
217 OSL_ENSURE(false, "CDocument::GetCNode is not supposed to"
218 " create a CDocument!!!");
219 pCNode
= static_cast< CNode
* >(new CDocument(
220 reinterpret_cast<xmlDocPtr
>(pNode
)));
222 case XML_DOCUMENT_TYPE_NODE
:
224 // m_aNodeType = NodeType::DOCUMENT_TYPE_NODE;
225 pCNode
= static_cast< CNode
* >(new CDocumentType(*this, m_Mutex
,
226 reinterpret_cast<xmlDtdPtr
>(pNode
)));
228 case XML_DOCUMENT_FRAG_NODE
:
229 // m_aNodeType = NodeType::DOCUMENT_FRAGMENT_NODE;
230 pCNode
= static_cast< CNode
* >(
231 new CDocumentFragment(*this, m_Mutex
, pNode
));
233 case XML_NOTATION_NODE
:
234 // m_aNodeType = NodeType::NOTATION_NODE;
235 pCNode
= static_cast< CNode
* >(new CNotation(*this, m_Mutex
,
236 reinterpret_cast<xmlNotationPtr
>(pNode
)));
238 case XML_ATTRIBUTE_NODE
:
239 // m_aNodeType = NodeType::ATTRIBUTE_NODE;
240 pCNode
= static_cast< CNode
* >(new CAttr(*this, m_Mutex
,
241 reinterpret_cast<xmlAttrPtr
>(pNode
)));
243 // unsupported node types
244 case XML_HTML_DOCUMENT_NODE
:
245 case XML_ELEMENT_DECL
:
246 case XML_ATTRIBUTE_DECL
:
247 case XML_ENTITY_DECL
:
248 case XML_NAMESPACE_DECL
:
254 bool const bInserted
= m_NodeMap
.insert(
255 nodemap_t::value_type(pNode
,
256 ::std::make_pair(WeakReference
<XNode
>(pCNode
.get()),
259 OSL_ASSERT(bInserted
);
261 // if insertion failed, delete new instance and return null
266 OSL_ENSURE(pCNode
.is(), "no node produced during CDocument::GetCNode!");
271 CDocument
& CDocument::GetOwnerDocument()
276 void CDocument::saxify(const Reference
< XDocumentHandler
>& i_xHandler
)
278 i_xHandler
->startDocument();
279 for (xmlNodePtr pChild
= m_aNodePtr
->children
;
280 pChild
!= 0; pChild
= pChild
->next
) {
281 ::rtl::Reference
<CNode
> const pNode
= GetCNode(pChild
);
282 OSL_ENSURE(pNode
!= 0, "CNode::get returned 0");
283 pNode
->saxify(i_xHandler
);
285 i_xHandler
->endDocument();
288 void CDocument::fastSaxify( Context
& rContext
)
290 rContext
.mxDocHandler
->startDocument();
291 for (xmlNodePtr pChild
= m_aNodePtr
->children
;
292 pChild
!= 0; pChild
= pChild
->next
) {
293 ::rtl::Reference
<CNode
> const pNode
= GetCNode(pChild
);
294 OSL_ENSURE(pNode
!= 0, "CNode::get returned 0");
295 pNode
->fastSaxify(rContext
);
297 rContext
.mxDocHandler
->endDocument();
300 bool CDocument::IsChildTypeAllowed(NodeType
const nodeType
)
303 case NodeType_PROCESSING_INSTRUCTION_NODE
:
304 case NodeType_COMMENT_NODE
:
306 case NodeType_ELEMENT_NODE
:
307 // there may be only one!
308 return 0 == lcl_getDocumentRootPtr(m_aDocPtr
);
309 case NodeType_DOCUMENT_TYPE_NODE
:
310 // there may be only one!
311 return 0 == lcl_getDocumentType(m_aDocPtr
);
318 void SAL_CALL
CDocument::addListener(const Reference
< XStreamListener
>& aListener
)
319 throw (RuntimeException
)
321 ::osl::MutexGuard
const g(m_Mutex
);
323 m_streamListeners
.insert(aListener
);
326 void SAL_CALL
CDocument::removeListener(const Reference
< XStreamListener
>& aListener
)
327 throw (RuntimeException
)
329 ::osl::MutexGuard
const g(m_Mutex
);
331 m_streamListeners
.erase(aListener
);
334 // IO context functions for libxml2 interaction
336 Reference
< XOutputStream
> stream
;
342 // int xmlOutputWriteCallback (void * context, const char * buffer, int len)
343 static int writeCallback(void *context
, const char* buffer
, int len
){
344 // create a sequence and write it to the stream
345 IOContext
*pContext
= static_cast<IOContext
*>(context
);
346 Sequence
<sal_Int8
> bs(reinterpret_cast<const sal_Int8
*>(buffer
), len
);
347 pContext
->stream
->writeBytes(bs
);
352 //int xmlOutputCloseCallback (void * context)
353 static int closeCallback(void *context
)
355 IOContext
*pContext
= static_cast<IOContext
*>(context
);
356 if (pContext
->allowClose
) {
357 pContext
->stream
->closeOutput();
363 void SAL_CALL
CDocument::start()
364 throw (RuntimeException
)
366 listenerlist_t streamListeners
;
368 ::osl::MutexGuard
const g(m_Mutex
);
370 if (! m_rOutputStream
.is()) { throw RuntimeException(); }
371 streamListeners
= m_streamListeners
;
374 // notify listeners about start
375 listenerlist_t::const_iterator iter1
= streamListeners
.begin();
376 while (iter1
!= streamListeners
.end()) {
377 Reference
< XStreamListener
> aListener
= *iter1
;
378 aListener
->started();
383 ::osl::MutexGuard
const g(m_Mutex
);
385 // check again! could have been reset...
386 if (! m_rOutputStream
.is()) { throw RuntimeException(); }
388 // setup libxml IO and write data to output stream
389 IOContext ioctx
= {m_rOutputStream
, false};
390 xmlOutputBufferPtr pOut
= xmlOutputBufferCreateIO(
391 writeCallback
, closeCallback
, &ioctx
, NULL
);
392 xmlSaveFileTo(pOut
, m_aNodePtr
->doc
, NULL
);
396 listenerlist_t::const_iterator iter2
= streamListeners
.begin();
397 while (iter2
!= streamListeners
.end()) {
398 Reference
< XStreamListener
> aListener
= *iter2
;
404 void SAL_CALL
CDocument::terminate()
405 throw (RuntimeException
)
410 void SAL_CALL
CDocument::setOutputStream( const Reference
< XOutputStream
>& aStream
)
411 throw (RuntimeException
)
413 ::osl::MutexGuard
const g(m_Mutex
);
415 m_rOutputStream
= aStream
;
418 Reference
< XOutputStream
> SAL_CALL
CDocument::getOutputStream() throw (RuntimeException
)
420 ::osl::MutexGuard
const g(m_Mutex
);
422 return m_rOutputStream
;
425 // Creates an Attr of the given name.
426 Reference
< XAttr
> SAL_CALL
CDocument::createAttribute(const OUString
& name
)
427 throw (RuntimeException
, DOMException
)
429 ::osl::MutexGuard
const g(m_Mutex
);
431 OString o1
= OUStringToOString(name
, RTL_TEXTENCODING_UTF8
);
432 xmlChar
*xName
= (xmlChar
*)o1
.getStr();
433 xmlAttrPtr
const pAttr
= xmlNewDocProp(m_aDocPtr
, xName
, NULL
);
434 ::rtl::Reference
< CAttr
> const pCAttr(
435 dynamic_cast< CAttr
* >(GetCNode(
436 reinterpret_cast<xmlNodePtr
>(pAttr
)).get()));
437 pCAttr
->m_bUnlinked
= true;
441 // Creates an attribute of the given qualified name and namespace URI.
442 Reference
< XAttr
> SAL_CALL
CDocument::createAttributeNS(
443 const OUString
& ns
, const OUString
& qname
)
444 throw (RuntimeException
, DOMException
)
446 ::osl::MutexGuard
const g(m_Mutex
);
448 // libxml does not allow a NS definition to be attached to an
449 // attribute node - which is a good thing, since namespaces are
450 // only defined as parts of element nodes
451 // thus the namespace data is stored in CAttr::m_pNamespace
452 sal_Int32 i
= qname
.indexOf(':');
453 OString oPrefix
, oName
, oUri
;
456 oPrefix
= OUStringToOString(qname
.copy(0, i
), RTL_TEXTENCODING_UTF8
);
457 oName
= OUStringToOString(qname
.copy(i
+1, qname
.getLength()-i
-1), RTL_TEXTENCODING_UTF8
);
461 oName
= OUStringToOString(qname
, RTL_TEXTENCODING_UTF8
);
463 oUri
= OUStringToOString(ns
, RTL_TEXTENCODING_UTF8
);
464 xmlAttrPtr
const pAttr
= xmlNewDocProp(m_aDocPtr
,
465 reinterpret_cast<xmlChar
const*>(oName
.getStr()), 0);
466 ::rtl::Reference
< CAttr
> const pCAttr(
467 dynamic_cast< CAttr
* >(GetCNode(
468 reinterpret_cast<xmlNodePtr
>(pAttr
)).get()));
469 if (!pCAttr
.is()) { throw RuntimeException(); }
470 // store the namespace data!
471 pCAttr
->m_pNamespace
.reset( new stringpair_t(oUri
, oPrefix
) );
472 pCAttr
->m_bUnlinked
= true;
477 // Creates a CDATASection node whose value is the specified string.
478 Reference
< XCDATASection
> SAL_CALL
CDocument::createCDATASection(const OUString
& data
)
479 throw (RuntimeException
)
481 ::osl::MutexGuard
const g(m_Mutex
);
484 OUStringToOString(data
, RTL_TEXTENCODING_UTF8
));
485 xmlChar
const*const pData
=
486 reinterpret_cast<xmlChar
const*>(oData
.getStr());
487 xmlNodePtr
const pText
=
488 xmlNewCDataBlock(m_aDocPtr
, pData
, strlen(oData
.getStr()));
489 Reference
< XCDATASection
> const xRet(
490 static_cast< XNode
* >(GetCNode(pText
).get()),
495 // Creates a Comment node given the specified string.
496 Reference
< XComment
> SAL_CALL
CDocument::createComment(const OUString
& data
)
497 throw (RuntimeException
)
499 ::osl::MutexGuard
const g(m_Mutex
);
501 OString o1
= OUStringToOString(data
, RTL_TEXTENCODING_UTF8
);
502 xmlChar
*xData
= (xmlChar
*)o1
.getStr();
503 xmlNodePtr pComment
= xmlNewDocComment(m_aDocPtr
, xData
);
504 Reference
< XComment
> const xRet(
505 static_cast< XNode
* >(GetCNode(pComment
).get()),
510 //Creates an empty DocumentFragment object.
511 Reference
< XDocumentFragment
> SAL_CALL
CDocument::createDocumentFragment()
512 throw (RuntimeException
)
514 ::osl::MutexGuard
const g(m_Mutex
);
516 xmlNodePtr pFrag
= xmlNewDocFragment(m_aDocPtr
);
517 Reference
< XDocumentFragment
> const xRet(
518 static_cast< XNode
* >(GetCNode(pFrag
).get()),
523 // Creates an element of the type specified.
524 Reference
< XElement
> SAL_CALL
CDocument::createElement(const OUString
& tagName
)
525 throw (RuntimeException
, DOMException
)
527 ::osl::MutexGuard
const g(m_Mutex
);
529 OString o1
= OUStringToOString(tagName
, RTL_TEXTENCODING_UTF8
);
530 xmlChar
*xName
= (xmlChar
*)o1
.getStr();
531 xmlNodePtr
const pNode
= xmlNewDocNode(m_aDocPtr
, NULL
, xName
, NULL
);
532 Reference
< XElement
> const xRet(
533 static_cast< XNode
* >(GetCNode(pNode
).get()),
538 // Creates an element of the given qualified name and namespace URI.
539 Reference
< XElement
> SAL_CALL
CDocument::createElementNS(
540 const OUString
& ns
, const OUString
& qname
)
541 throw (RuntimeException
, DOMException
)
543 ::osl::MutexGuard
const g(m_Mutex
);
545 sal_Int32 i
= qname
.indexOf(':');
546 if (ns
.isEmpty()) throw RuntimeException();
551 o1
= OUStringToOString(qname
.copy(0, i
), RTL_TEXTENCODING_UTF8
);
552 xPrefix
= (xmlChar
*)o1
.getStr();
553 o2
= OUStringToOString(qname
.copy(i
+1, qname
.getLength()-i
-1), RTL_TEXTENCODING_UTF8
);
554 xName
= (xmlChar
*)o2
.getStr();
557 xPrefix
= (xmlChar
*)"";
558 o2
= OUStringToOString(qname
, RTL_TEXTENCODING_UTF8
);
559 xName
= (xmlChar
*)o2
.getStr();
561 o3
= OUStringToOString(ns
, RTL_TEXTENCODING_UTF8
);
562 xmlChar
*xUri
= (xmlChar
*)o3
.getStr();
564 // xmlNsPtr aNsPtr = xmlNewReconciledNs?
565 // xmlNsPtr aNsPtr = xmlNewGlobalNs?
566 xmlNodePtr
const pNode
= xmlNewDocNode(m_aDocPtr
, NULL
, xName
, NULL
);
567 xmlNsPtr
const pNs
= xmlNewNs(pNode
, xUri
, xPrefix
);
568 xmlSetNs(pNode
, pNs
);
569 Reference
< XElement
> const xRet(
570 static_cast< XNode
* >(GetCNode(pNode
).get()),
575 //Creates an EntityReference object.
576 Reference
< XEntityReference
> SAL_CALL
CDocument::createEntityReference(const OUString
& name
)
577 throw (RuntimeException
, DOMException
)
579 ::osl::MutexGuard
const g(m_Mutex
);
581 OString o1
= OUStringToOString(name
, RTL_TEXTENCODING_UTF8
);
582 xmlChar
*xName
= (xmlChar
*)o1
.getStr();
583 xmlNodePtr
const pNode
= xmlNewReference(m_aDocPtr
, xName
);
584 Reference
< XEntityReference
> const xRet(
585 static_cast< XNode
* >(GetCNode(pNode
).get()),
590 // Creates a ProcessingInstruction node given the specified name and
592 Reference
< XProcessingInstruction
> SAL_CALL
CDocument::createProcessingInstruction(
593 const OUString
& target
, const OUString
& data
)
594 throw (RuntimeException
, DOMException
)
596 ::osl::MutexGuard
const g(m_Mutex
);
598 OString o1
= OUStringToOString(target
, RTL_TEXTENCODING_UTF8
);
599 xmlChar
*xTarget
= (xmlChar
*)o1
.getStr();
600 OString o2
= OUStringToOString(data
, RTL_TEXTENCODING_UTF8
);
601 xmlChar
*xData
= (xmlChar
*)o2
.getStr();
602 xmlNodePtr
const pNode
= xmlNewDocPI(m_aDocPtr
, xTarget
, xData
);
603 pNode
->doc
= m_aDocPtr
;
604 Reference
< XProcessingInstruction
> const xRet(
605 static_cast< XNode
* >(GetCNode(pNode
).get()),
610 // Creates a Text node given the specified string.
611 Reference
< XText
> SAL_CALL
CDocument::createTextNode(const OUString
& data
)
612 throw (RuntimeException
)
614 ::osl::MutexGuard
const g(m_Mutex
);
616 OString o1
= OUStringToOString(data
, RTL_TEXTENCODING_UTF8
);
617 xmlChar
*xData
= (xmlChar
*)o1
.getStr();
618 xmlNodePtr
const pNode
= xmlNewDocText(m_aDocPtr
, xData
);
619 Reference
< XText
> const xRet(
620 static_cast< XNode
* >(GetCNode(pNode
).get()),
625 // The Document Type Declaration (see DocumentType) associated with this
627 Reference
< XDocumentType
> SAL_CALL
CDocument::getDoctype()
628 throw (RuntimeException
)
630 ::osl::MutexGuard
const g(m_Mutex
);
632 xmlNodePtr
const pDocType(lcl_getDocumentType(m_aDocPtr
));
633 Reference
< XDocumentType
> const xRet(
634 static_cast< XNode
* >(GetCNode(pDocType
).get()),
639 // This is a convenience attribute that allows direct access to the child
640 // node that is the root element of the document.
641 Reference
< XElement
> SAL_CALL
CDocument::getDocumentElement()
642 throw (RuntimeException
)
644 ::osl::MutexGuard
const g(m_Mutex
);
646 xmlNodePtr
const pNode
= lcl_getDocumentRootPtr(m_aDocPtr
);
647 if (!pNode
) { return 0; }
648 Reference
< XElement
> const xRet(
649 static_cast< XNode
* >(GetCNode(pNode
).get()),
655 lcl_search_element_by_id(const xmlNodePtr cur
, const xmlChar
* id
)
659 // look in current node
660 if (cur
->type
== XML_ELEMENT_NODE
)
662 xmlAttrPtr a
= cur
->properties
;
665 if (a
->atype
== XML_ATTRIBUTE_ID
) {
666 if (strcmp((char*)a
->children
->content
, (char*)id
) == 0)
673 xmlNodePtr result
= lcl_search_element_by_id(cur
->children
, id
);
676 result
= lcl_search_element_by_id(cur
->next
, id
);
680 // Returns the Element whose ID is given by elementId.
681 Reference
< XElement
> SAL_CALL
682 CDocument::getElementById(const OUString
& elementId
)
683 throw (RuntimeException
)
685 ::osl::MutexGuard
const g(m_Mutex
);
687 // search the tree for an element with the given ID
688 OString o1
= OUStringToOString(elementId
, RTL_TEXTENCODING_UTF8
);
689 xmlChar
*xId
= (xmlChar
*)o1
.getStr();
690 xmlNodePtr
const pStart
= lcl_getDocumentRootPtr(m_aDocPtr
);
691 if (!pStart
) { return 0; }
692 xmlNodePtr
const pNode
= lcl_search_element_by_id(pStart
, xId
);
693 Reference
< XElement
> const xRet(
694 static_cast< XNode
* >(GetCNode(pNode
).get()),
700 Reference
< XNodeList
> SAL_CALL
701 CDocument::getElementsByTagName(OUString
const& rTagname
)
702 throw (RuntimeException
)
704 ::osl::MutexGuard
const g(m_Mutex
);
706 Reference
< XNodeList
> const xRet(
707 new CElementList(this->GetDocumentElement(), m_Mutex
, rTagname
));
711 Reference
< XNodeList
> SAL_CALL
CDocument::getElementsByTagNameNS(
712 OUString
const& rNamespaceURI
, OUString
const& rLocalName
)
713 throw (RuntimeException
)
715 ::osl::MutexGuard
const g(m_Mutex
);
717 Reference
< XNodeList
> const xRet(
718 new CElementList(this->GetDocumentElement(), m_Mutex
,
719 rLocalName
, &rNamespaceURI
));
723 Reference
< XDOMImplementation
> SAL_CALL
CDocument::getImplementation()
724 throw (RuntimeException
)
726 // does not need mutex currently
727 return Reference
< XDOMImplementation
>(CDOMImplementation::get());
730 // helper function to recursively import siblings
731 static void lcl_ImportSiblings(
732 Reference
< XDocument
> const& xTargetDocument
,
733 Reference
< XNode
> const& xTargetParent
,
734 Reference
< XNode
> const& xChild
)
736 Reference
< XNode
> xSibling
= xChild
;
737 while (xSibling
.is())
739 Reference
< XNode
> const xTmp(
740 xTargetDocument
->importNode(xSibling
, sal_True
));
741 xTargetParent
->appendChild(xTmp
);
742 xSibling
= xSibling
->getNextSibling();
746 static Reference
< XNode
>
747 lcl_ImportNode( Reference
< XDocument
> const& xDocument
,
748 Reference
< XNode
> const& xImportedNode
, sal_Bool deep
)
750 Reference
< XNode
> xNode
;
751 NodeType aNodeType
= xImportedNode
->getNodeType();
754 case NodeType_ATTRIBUTE_NODE
:
756 Reference
< XAttr
> const xAttr(xImportedNode
, UNO_QUERY_THROW
);
757 Reference
< XAttr
> const xNew
=
758 xDocument
->createAttribute(xAttr
->getName());
759 xNew
->setValue(xAttr
->getValue());
760 xNode
.set(xNew
, UNO_QUERY
);
763 case NodeType_CDATA_SECTION_NODE
:
765 Reference
< XCDATASection
> const xCData(xImportedNode
,
767 Reference
< XCDATASection
> const xNewCData
=
768 xDocument
->createCDATASection(xCData
->getData());
769 xNode
.set(xNewCData
, UNO_QUERY
);
772 case NodeType_COMMENT_NODE
:
774 Reference
< XComment
> const xComment(xImportedNode
,
776 Reference
< XComment
> const xNewComment
=
777 xDocument
->createComment(xComment
->getData());
778 xNode
.set(xNewComment
, UNO_QUERY
);
781 case NodeType_DOCUMENT_FRAGMENT_NODE
:
783 Reference
< XDocumentFragment
> const xFrag(xImportedNode
,
785 Reference
< XDocumentFragment
> const xNewFrag
=
786 xDocument
->createDocumentFragment();
787 xNode
.set(xNewFrag
, UNO_QUERY
);
790 case NodeType_ELEMENT_NODE
:
792 Reference
< XElement
> const xElement(xImportedNode
,
794 OUString
const aNsUri
= xImportedNode
->getNamespaceURI();
795 OUString
const aNsPrefix
= xImportedNode
->getPrefix();
796 OUString aQName
= xElement
->getTagName();
797 Reference
< XElement
> xNewElement
;
798 if (!aNsUri
.isEmpty())
800 if (!aNsPrefix
.isEmpty()) {
801 aQName
= aNsPrefix
+ ":" + aQName
;
803 xNewElement
= xDocument
->createElementNS(aNsUri
, aQName
);
805 xNewElement
= xDocument
->createElement(aQName
);
809 if (xElement
->hasAttributes())
811 Reference
< XNamedNodeMap
> attribs
= xElement
->getAttributes();
812 for (sal_Int32 i
= 0; i
< attribs
->getLength(); i
++)
814 Reference
< XAttr
> const curAttr(attribs
->item(i
),
816 OUString
const aAttrUri
= curAttr
->getNamespaceURI();
817 OUString
const aAttrPrefix
= curAttr
->getPrefix();
818 OUString aAttrName
= curAttr
->getName();
819 OUString
const sValue
= curAttr
->getValue();
820 if (!aAttrUri
.isEmpty())
822 if (!aAttrPrefix
.isEmpty()) {
823 aAttrName
= aAttrPrefix
+ ":" + aAttrName
;
825 xNewElement
->setAttributeNS(
826 aAttrUri
, aAttrName
, sValue
);
828 xNewElement
->setAttribute(aAttrName
, sValue
);
832 xNode
.set(xNewElement
, UNO_QUERY
);
835 case NodeType_ENTITY_REFERENCE_NODE
:
837 Reference
< XEntityReference
> const xRef(xImportedNode
,
839 Reference
< XEntityReference
> const xNewRef(
840 xDocument
->createEntityReference(xRef
->getNodeName()));
841 xNode
.set(xNewRef
, UNO_QUERY
);
844 case NodeType_PROCESSING_INSTRUCTION_NODE
:
846 Reference
< XProcessingInstruction
> const xPi(xImportedNode
,
848 Reference
< XProcessingInstruction
> const xNewPi(
849 xDocument
->createProcessingInstruction(
850 xPi
->getTarget(), xPi
->getData()));
851 xNode
.set(xNewPi
, UNO_QUERY
);
854 case NodeType_TEXT_NODE
:
856 Reference
< XText
> const xText(xImportedNode
, UNO_QUERY_THROW
);
857 Reference
< XText
> const xNewText(
858 xDocument
->createTextNode(xText
->getData()));
859 xNode
.set(xNewText
, UNO_QUERY
);
862 case NodeType_ENTITY_NODE
:
863 case NodeType_DOCUMENT_NODE
:
864 case NodeType_DOCUMENT_TYPE_NODE
:
865 case NodeType_NOTATION_NODE
:
868 throw RuntimeException();
873 // get children and import them
874 Reference
< XNode
> const xChild
= xImportedNode
->getFirstChild();
877 lcl_ImportSiblings(xDocument
, xNode
, xChild
);
881 /* DOMNodeInsertedIntoDocument
882 * Fired when a node is being inserted into a document,
883 * either through direct insertion of the Node or insertion of a
884 * subtree in which it is contained. This event is dispatched after
885 * the insertion has taken place. The target of this event is the node
886 * being inserted. If the Node is being directly inserted the DOMNodeInserted
887 * event will fire before the DOMNodeInsertedIntoDocument event.
894 Reference
< XDocumentEvent
> const xDocevent(xDocument
, UNO_QUERY
);
895 Reference
< XMutationEvent
> const event(xDocevent
->createEvent(
896 "DOMNodeInsertedIntoDocument"), UNO_QUERY_THROW
);
897 event
->initMutationEvent(
898 "DOMNodeInsertedIntoDocument", sal_True
, sal_False
, Reference
< XNode
>(),
899 OUString(), OUString(), OUString(), (AttrChangeType
)0 );
900 Reference
< XEventTarget
> const xDocET(xDocument
, UNO_QUERY
);
901 xDocET
->dispatchEvent(Reference
< XEvent
>(event
, UNO_QUERY
));
907 Reference
< XNode
> SAL_CALL
CDocument::importNode(
908 Reference
< XNode
> const& xImportedNode
, sal_Bool deep
)
909 throw (RuntimeException
, DOMException
)
911 if (!xImportedNode
.is()) { throw RuntimeException(); }
913 // NB: this whole operation inherently accesses 2 distinct documents.
914 // The imported node could even be from a different DOM implementation,
915 // so this implementation cannot make any assumptions about the
916 // locking strategy of the imported node.
917 // So the import takes no lock on this document;
918 // it only calls UNO methods on this document that temporarily
919 // lock the document, and UNO methods on the imported node that
920 // may temporarily lock the other document.
921 // As a consequence, the import is not atomic with regard to
922 // concurrent modifications of either document, but it should not
924 // To ensure that no members are accessed, the implementation is in
925 // static non-member functions.
927 Reference
< XDocument
> const xDocument(this);
929 if (xImportedNode
->getOwnerDocument() == xDocument
) {
930 return xImportedNode
;
933 Reference
< XNode
> const xNode(
934 lcl_ImportNode(xDocument
, xImportedNode
, deep
) );
938 OUString SAL_CALL
CDocument::getNodeName()throw (RuntimeException
)
940 // does not need mutex currently
941 return OUString("#document");
944 OUString SAL_CALL
CDocument::getNodeValue() throw (RuntimeException
)
946 // does not need mutex currently
950 Reference
< XNode
> SAL_CALL
CDocument::cloneNode(sal_Bool bDeep
)
951 throw (RuntimeException
)
953 ::osl::MutexGuard
const g(m_rMutex
);
955 OSL_ASSERT(0 != m_aNodePtr
);
956 if (0 == m_aNodePtr
) {
959 xmlDocPtr
const pClone(xmlCopyDoc(m_aDocPtr
, (bDeep
) ? 1 : 0));
960 if (0 == pClone
) { return 0; }
961 Reference
< XNode
> const xRet(
962 static_cast<CNode
*>(CDocument::CreateCDocument(pClone
).get()));
966 Reference
< XEvent
> SAL_CALL
CDocument::createEvent(const OUString
& aType
) throw (RuntimeException
)
968 // does not need mutex currently
969 events::CEvent
*pEvent
= 0;
970 if ( aType
== "DOMSubtreeModified" || aType
== "DOMNodeInserted" || aType
== "DOMNodeRemoved"
971 || aType
== "DOMNodeRemovedFromDocument" || aType
== "DOMNodeInsertedIntoDocument" || aType
== "DOMAttrModified"
972 || aType
== "DOMCharacterDataModified")
974 pEvent
= new events::CMutationEvent
;
976 } else if ( aType
== "DOMFocusIn" || aType
== "DOMFocusOut" || aType
== "DOMActivate")
978 pEvent
= new events::CUIEvent
;
979 } else if ( aType
== "click" || aType
== "mousedown" || aType
== "mouseup"
980 || aType
== "mouseover" || aType
== "mousemove" || aType
== "mouseout" )
982 pEvent
= new events::CMouseEvent
;
984 else // generic event
986 pEvent
= new events::CEvent
;
988 return Reference
< XEvent
>(pEvent
);
991 // ::com::sun::star::xml::sax::XSAXSerializable
992 void SAL_CALL
CDocument::serialize(
993 const Reference
< XDocumentHandler
>& i_xHandler
,
994 const Sequence
< beans::StringPair
>& i_rNamespaces
)
995 throw (RuntimeException
, SAXException
)
997 ::osl::MutexGuard
const g(m_Mutex
);
999 // add new namespaces to root node
1000 xmlNodePtr
const pRoot
= lcl_getDocumentRootPtr(m_aDocPtr
);
1002 const beans::StringPair
* pSeq
= i_rNamespaces
.getConstArray();
1003 for (const beans::StringPair
*pNsDef
= pSeq
;
1004 pNsDef
< pSeq
+ i_rNamespaces
.getLength(); ++pNsDef
) {
1005 OString prefix
= OUStringToOString(pNsDef
->First
,
1006 RTL_TEXTENCODING_UTF8
);
1007 OString href
= OUStringToOString(pNsDef
->Second
,
1008 RTL_TEXTENCODING_UTF8
);
1009 // this will only add the ns if it does not exist already
1010 xmlNewNs(pRoot
, reinterpret_cast<const xmlChar
*>(href
.getStr()),
1011 reinterpret_cast<const xmlChar
*>(prefix
.getStr()));
1013 // eliminate duplicate namespace declarations
1014 nscleanup(pRoot
->children
, pRoot
);
1019 // ::com::sun::star::xml::sax::XFastSAXSerializable
1020 void SAL_CALL
CDocument::fastSerialize( const Reference
< XFastDocumentHandler
>& i_xHandler
,
1021 const Reference
< XFastTokenHandler
>& i_xTokenHandler
,
1022 const Sequence
< beans::StringPair
>& i_rNamespaces
,
1023 const Sequence
< beans::Pair
< OUString
, sal_Int32
> >& i_rRegisterNamespaces
)
1024 throw (SAXException
, RuntimeException
)
1026 ::osl::MutexGuard
const g(m_Mutex
);
1028 // add new namespaces to root node
1029 xmlNodePtr
const pRoot
= lcl_getDocumentRootPtr(m_aDocPtr
);
1031 const beans::StringPair
* pSeq
= i_rNamespaces
.getConstArray();
1032 for (const beans::StringPair
*pNsDef
= pSeq
;
1033 pNsDef
< pSeq
+ i_rNamespaces
.getLength(); ++pNsDef
) {
1034 OString prefix
= OUStringToOString(pNsDef
->First
,
1035 RTL_TEXTENCODING_UTF8
);
1036 OString href
= OUStringToOString(pNsDef
->Second
,
1037 RTL_TEXTENCODING_UTF8
);
1038 // this will only add the ns if it does not exist already
1039 xmlNewNs(pRoot
, reinterpret_cast<const xmlChar
*>(href
.getStr()),
1040 reinterpret_cast<const xmlChar
*>(prefix
.getStr()));
1042 // eliminate duplicate namespace declarations
1043 nscleanup(pRoot
->children
, pRoot
);
1046 Context
aContext(i_xHandler
,
1049 // register namespace ids
1050 const beans::Pair
<OUString
,sal_Int32
>* pSeq
= i_rRegisterNamespaces
.getConstArray();
1051 for (const beans::Pair
<OUString
,sal_Int32
>* pNs
= pSeq
;
1052 pNs
< pSeq
+ i_rRegisterNamespaces
.getLength(); ++pNs
)
1054 OSL_ENSURE(pNs
->Second
>= FastToken::NAMESPACE
,
1055 "CDocument::fastSerialize(): invalid NS token id");
1056 aContext
.maNamespaceMap
[ pNs
->First
] = pNs
->Second
;
1059 fastSaxify(aContext
);
1063 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */