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"
38 #include <mutationevent.hxx>
39 #include <uievent.hxx>
40 #include <mouseevent.hxx>
41 #include <eventdispatcher.hxx>
45 #include <osl/diagnose.h>
47 #include <com/sun/star/xml/sax/FastToken.hpp>
50 using namespace css::io
;
51 using namespace css::uno
;
52 using namespace css::xml::dom
;
53 using namespace css::xml::dom::events
;
54 using namespace css::xml::sax
;
58 static xmlNodePtr
lcl_getDocumentType(xmlDocPtr
const i_pDocument
)
61 xmlNodePtr cur
= i_pDocument
->children
;
62 while (cur
!= nullptr)
64 if ((cur
->type
== XML_DOCUMENT_TYPE_NODE
) ||
65 (cur
->type
== XML_DTD_NODE
)) {
72 /// get the pointer to the root element node of the document
73 static xmlNodePtr
lcl_getDocumentRootPtr(xmlDocPtr
const i_pDocument
)
75 // find the document element
76 xmlNodePtr cur
= i_pDocument
->children
;
77 while (cur
!= nullptr)
79 if (cur
->type
== XML_ELEMENT_NODE
)
86 CDocument::CDocument(xmlDocPtr
const pDoc
)
87 : CDocument_Base(*this, m_Mutex
,
88 NodeType_DOCUMENT_NODE
, reinterpret_cast<xmlNodePtr
>(pDoc
))
90 , m_pEventDispatcher(new events::CEventDispatcher
)
94 ::rtl::Reference
<CDocument
> CDocument::CreateCDocument(xmlDocPtr
const pDoc
)
96 ::rtl::Reference
<CDocument
> const xDoc(new CDocument(pDoc
));
97 // add the doc itself to its nodemap!
98 xDoc
->m_NodeMap
.emplace(
99 reinterpret_cast<xmlNodePtr
>(pDoc
),
101 WeakReference
<XNode
>(static_cast<XDocument
*>(xDoc
.get())),
106 CDocument::~CDocument()
108 ::osl::MutexGuard
const g(m_Mutex
);
110 // node map must be empty now, otherwise CDocument must not die!
111 for (const auto& rEntry
: m_NodeMap
)
113 Reference
<XNode
> const xNode(rEntry
.second
.first
);
114 OSL_ENSURE(!xNode
.is(),
115 "CDocument::~CDocument(): ERROR: live node in document node map!");
118 xmlFreeDoc(m_aDocPtr
);
122 events::CEventDispatcher
& CDocument::GetEventDispatcher()
124 return *m_pEventDispatcher
;
127 ::rtl::Reference
< CElement
> CDocument::GetDocumentElement()
129 xmlNodePtr
const pNode
= lcl_getDocumentRootPtr(m_aDocPtr
);
130 ::rtl::Reference
< CElement
> const xRet(
131 dynamic_cast<CElement
*>(GetCNode(pNode
).get()));
136 CDocument::RemoveCNode(xmlNodePtr
const pNode
, CNode
const*const pCNode
)
138 nodemap_t::iterator
const i
= m_NodeMap
.find(pNode
);
139 if (i
== m_NodeMap
.end())
142 // #i113681# consider this scenario:
144 // T2 calls getCNode: lookup will find i->second->first invalid
145 // so a new CNode is created and inserted
146 // T1 calls removeCNode: i->second->second now points to a
147 // different CNode instance!
149 // check that the CNode is the right one
150 CNode
*const pCurrent
= i
->second
.second
;
151 if (pCurrent
== pCNode
) {
156 /** NB: this is the CNode factory.
157 it is the only place where CNodes may be instantiated.
158 all CNodes must be registered at the m_NodeMap.
160 ::rtl::Reference
<CNode
>
161 CDocument::GetCNode(xmlNodePtr
const pNode
, bool const bCreate
)
163 if (nullptr == pNode
) {
166 //check whether there is already an instance for this node
167 nodemap_t::const_iterator
const i
= m_NodeMap
.find(pNode
);
168 if (i
!= m_NodeMap
.end()) {
169 // #i113681# check that the CNode is still alive
170 uno::Reference
<XNode
> const xNode(i
->second
.first
);
173 ::rtl::Reference
<CNode
> ret(i
->second
.second
);
174 OSL_ASSERT(ret
.is());
179 if (!bCreate
) { return nullptr; }
181 // there is not yet an instance wrapping this node,
182 // create it and store it in the map
184 ::rtl::Reference
<CNode
> pCNode
;
187 case XML_ELEMENT_NODE
:
188 // m_aNodeType = NodeType::ELEMENT_NODE;
189 pCNode
= new CElement(*this, m_Mutex
, pNode
);
192 // m_aNodeType = NodeType::TEXT_NODE;
193 pCNode
= new CText(*this, m_Mutex
, pNode
);
195 case XML_CDATA_SECTION_NODE
:
196 // m_aNodeType = NodeType::CDATA_SECTION_NODE;
197 pCNode
= new CCDATASection(*this, m_Mutex
, pNode
);
199 case XML_ENTITY_REF_NODE
:
200 // m_aNodeType = NodeType::ENTITY_REFERENCE_NODE;
201 pCNode
= new CEntityReference(*this, m_Mutex
, pNode
);
203 case XML_ENTITY_NODE
:
204 // m_aNodeType = NodeType::ENTITY_NODE;
205 pCNode
= new CEntity(*this, m_Mutex
, reinterpret_cast<xmlEntityPtr
>(pNode
));
208 // m_aNodeType = NodeType::PROCESSING_INSTRUCTION_NODE;
209 pCNode
= new CProcessingInstruction(*this, m_Mutex
, pNode
);
211 case XML_COMMENT_NODE
:
212 // m_aNodeType = NodeType::COMMENT_NODE;
213 pCNode
= 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
= new CDocument(reinterpret_cast<xmlDocPtr
>(pNode
));
221 case XML_DOCUMENT_TYPE_NODE
:
223 // m_aNodeType = NodeType::DOCUMENT_TYPE_NODE;
224 pCNode
= new CDocumentType(*this, m_Mutex
, reinterpret_cast<xmlDtdPtr
>(pNode
));
226 case XML_DOCUMENT_FRAG_NODE
:
227 // m_aNodeType = NodeType::DOCUMENT_FRAGMENT_NODE;
228 pCNode
= new CDocumentFragment(*this, m_Mutex
, pNode
);
230 case XML_NOTATION_NODE
:
231 // m_aNodeType = NodeType::NOTATION_NODE;
232 pCNode
= new CNotation(*this, m_Mutex
, reinterpret_cast<xmlNotationPtr
>(pNode
));
234 case XML_ATTRIBUTE_NODE
:
235 // m_aNodeType = NodeType::ATTRIBUTE_NODE;
236 pCNode
= new CAttr(*this, m_Mutex
, reinterpret_cast<xmlAttrPtr
>(pNode
));
238 // unsupported node types
239 case XML_HTML_DOCUMENT_NODE
:
240 case XML_ELEMENT_DECL
:
241 case XML_ATTRIBUTE_DECL
:
242 case XML_ENTITY_DECL
:
243 case XML_NAMESPACE_DECL
:
248 if (pCNode
!= nullptr) {
249 bool const bInserted
= m_NodeMap
.emplace(
251 ::std::make_pair(WeakReference
<XNode
>(pCNode
), pCNode
.get())
253 OSL_ASSERT(bInserted
);
255 // if insertion failed, delete new instance and return null
260 OSL_ENSURE(pCNode
.is(), "no node produced during CDocument::GetCNode!");
265 CDocument
& CDocument::GetOwnerDocument()
270 void CDocument::saxify(const Reference
< XDocumentHandler
>& i_xHandler
)
272 i_xHandler
->startDocument();
273 for (xmlNodePtr pChild
= m_aNodePtr
->children
;
274 pChild
!= nullptr; pChild
= pChild
->next
) {
275 ::rtl::Reference
<CNode
> const pNode
= GetCNode(pChild
);
276 OSL_ENSURE(pNode
!= nullptr, "CNode::get returned 0");
277 pNode
->saxify(i_xHandler
);
279 i_xHandler
->endDocument();
282 void CDocument::fastSaxify( Context
& rContext
)
284 rContext
.mxDocHandler
->startDocument();
285 for (xmlNodePtr pChild
= m_aNodePtr
->children
;
286 pChild
!= nullptr; pChild
= pChild
->next
) {
287 ::rtl::Reference
<CNode
> const pNode
= GetCNode(pChild
);
288 OSL_ENSURE(pNode
!= nullptr, "CNode::get returned 0");
289 pNode
->fastSaxify(rContext
);
291 rContext
.mxDocHandler
->endDocument();
294 bool CDocument::IsChildTypeAllowed(NodeType
const nodeType
, NodeType
const*const pReplacedNodeType
)
297 case NodeType_PROCESSING_INSTRUCTION_NODE
:
298 case NodeType_COMMENT_NODE
:
300 case NodeType_ELEMENT_NODE
:
301 // there may be only one!
302 return (pReplacedNodeType
&& *pReplacedNodeType
== nodeType
)
303 || nullptr == lcl_getDocumentRootPtr(m_aDocPtr
);
304 case NodeType_DOCUMENT_TYPE_NODE
:
305 // there may be only one!
306 return (pReplacedNodeType
&& *pReplacedNodeType
== nodeType
)
307 || nullptr == lcl_getDocumentType(m_aDocPtr
);
314 void SAL_CALL
CDocument::addListener(const Reference
< XStreamListener
>& aListener
)
316 ::osl::MutexGuard
const g(m_Mutex
);
318 m_streamListeners
.insert(aListener
);
321 void SAL_CALL
CDocument::removeListener(const Reference
< XStreamListener
>& aListener
)
323 ::osl::MutexGuard
const g(m_Mutex
);
325 m_streamListeners
.erase(aListener
);
330 // IO context functions for libxml2 interaction
332 Reference
< XOutputStream
> stream
;
340 // int xmlOutputWriteCallback (void * context, const char * buffer, int len)
341 static int writeCallback(void *context
, const char* buffer
, int len
){
342 // create a sequence and write it to the stream
343 IOContext
*pContext
= static_cast<IOContext
*>(context
);
344 Sequence
<sal_Int8
> bs(reinterpret_cast<const sal_Int8
*>(buffer
), len
);
345 pContext
->stream
->writeBytes(bs
);
350 //int xmlOutputCloseCallback (void * context)
351 static int closeCallback(void *context
)
353 IOContext
*pContext
= static_cast<IOContext
*>(context
);
354 if (pContext
->allowClose
) {
355 pContext
->stream
->closeOutput();
361 void SAL_CALL
CDocument::start()
363 listenerlist_t streamListeners
;
365 ::osl::MutexGuard
const g(m_Mutex
);
367 if (! m_rOutputStream
.is()) { throw RuntimeException(); }
368 streamListeners
= m_streamListeners
;
371 // notify listeners about start
372 for (const Reference
< XStreamListener
>& aListener
: streamListeners
) {
373 aListener
->started();
377 ::osl::MutexGuard
const g(m_Mutex
);
379 // check again! could have been reset...
380 if (! m_rOutputStream
.is()) { throw RuntimeException(); }
382 // setup libxml IO and write data to output stream
383 IOContext ioctx
= {m_rOutputStream
, false};
384 xmlOutputBufferPtr pOut
= xmlOutputBufferCreateIO(
385 writeCallback
, closeCallback
, &ioctx
, nullptr);
386 xmlSaveFileTo(pOut
, m_aNodePtr
->doc
, nullptr);
390 for (const Reference
< XStreamListener
>& aListener
: streamListeners
) {
395 void SAL_CALL
CDocument::terminate()
400 void SAL_CALL
CDocument::setOutputStream( const Reference
< XOutputStream
>& aStream
)
402 ::osl::MutexGuard
const g(m_Mutex
);
404 m_rOutputStream
= aStream
;
407 Reference
< XOutputStream
> SAL_CALL
CDocument::getOutputStream()
409 ::osl::MutexGuard
const g(m_Mutex
);
411 return m_rOutputStream
;
414 // Creates an Attr of the given name.
415 Reference
< XAttr
> SAL_CALL
CDocument::createAttribute(const OUString
& name
)
417 ::osl::MutexGuard
const g(m_Mutex
);
419 OString o1
= OUStringToOString(name
, RTL_TEXTENCODING_UTF8
);
420 xmlChar
const *pName
= reinterpret_cast<xmlChar
const *>(o1
.getStr());
421 xmlAttrPtr
const pAttr
= xmlNewDocProp(m_aDocPtr
, pName
, nullptr);
422 ::rtl::Reference
< CAttr
> const pCAttr(
423 dynamic_cast< CAttr
* >(GetCNode(
424 reinterpret_cast<xmlNodePtr
>(pAttr
)).get()));
425 if (!pCAttr
.is()) { throw RuntimeException(); }
426 pCAttr
->m_bUnlinked
= true;
430 // Creates an attribute of the given qualified name and namespace URI.
431 Reference
< XAttr
> SAL_CALL
CDocument::createAttributeNS(
432 const OUString
& ns
, const OUString
& qname
)
434 ::osl::MutexGuard
const g(m_Mutex
);
436 // libxml does not allow a NS definition to be attached to an
437 // attribute node - which is a good thing, since namespaces are
438 // only defined as parts of element nodes
439 // thus the namespace data is stored in CAttr::m_pNamespace
440 sal_Int32 i
= qname
.indexOf(':');
441 OString oPrefix
, oName
, oUri
;
444 oPrefix
= OUStringToOString(qname
.subView(0, i
), RTL_TEXTENCODING_UTF8
);
445 oName
= OUStringToOString(qname
.subView(i
+1), RTL_TEXTENCODING_UTF8
);
449 oName
= OUStringToOString(qname
, RTL_TEXTENCODING_UTF8
);
451 oUri
= OUStringToOString(ns
, RTL_TEXTENCODING_UTF8
);
452 xmlAttrPtr
const pAttr
= xmlNewDocProp(m_aDocPtr
,
453 reinterpret_cast<xmlChar
const*>(oName
.getStr()), nullptr);
454 ::rtl::Reference
< CAttr
> const pCAttr(
455 dynamic_cast< CAttr
* >(GetCNode(
456 reinterpret_cast<xmlNodePtr
>(pAttr
)).get()));
457 if (!pCAttr
.is()) { throw RuntimeException(); }
458 // store the namespace data!
459 pCAttr
->m_oNamespace
.emplace( oUri
, oPrefix
);
460 pCAttr
->m_bUnlinked
= true;
465 // Creates a CDATASection node whose value is the specified string.
466 Reference
< XCDATASection
> SAL_CALL
CDocument::createCDATASection(const OUString
& data
)
468 ::osl::MutexGuard
const g(m_Mutex
);
471 OUStringToOString(data
, RTL_TEXTENCODING_UTF8
));
472 xmlChar
const*const pData
=
473 reinterpret_cast<xmlChar
const*>(oData
.getStr());
474 xmlNodePtr
const pText
=
475 xmlNewCDataBlock(m_aDocPtr
, pData
, oData
.getLength());
476 Reference
< XCDATASection
> const xRet(
477 static_cast< XNode
* >(GetCNode(pText
).get()),
482 // Creates a Comment node given the specified string.
483 Reference
< XComment
> SAL_CALL
CDocument::createComment(const OUString
& data
)
485 ::osl::MutexGuard
const g(m_Mutex
);
487 OString o1
= OUStringToOString(data
, RTL_TEXTENCODING_UTF8
);
488 xmlChar
const *pData
= reinterpret_cast<xmlChar
const *>(o1
.getStr());
489 xmlNodePtr pComment
= xmlNewDocComment(m_aDocPtr
, pData
);
490 Reference
< XComment
> const xRet(
491 static_cast< XNode
* >(GetCNode(pComment
).get()),
496 //Creates an empty DocumentFragment object.
497 Reference
< XDocumentFragment
> SAL_CALL
CDocument::createDocumentFragment()
499 ::osl::MutexGuard
const g(m_Mutex
);
501 xmlNodePtr pFrag
= xmlNewDocFragment(m_aDocPtr
);
502 Reference
< XDocumentFragment
> const xRet(
503 static_cast< XNode
* >(GetCNode(pFrag
).get()),
508 // Creates an element of the type specified.
509 Reference
< XElement
> SAL_CALL
CDocument::createElement(const OUString
& tagName
)
511 ::osl::MutexGuard
const g(m_Mutex
);
513 OString o1
= OUStringToOString(tagName
, RTL_TEXTENCODING_UTF8
);
514 xmlChar
const *pName
= reinterpret_cast<xmlChar
const *>(o1
.getStr());
515 xmlNodePtr
const pNode
= xmlNewDocNode(m_aDocPtr
, nullptr, pName
, nullptr);
516 Reference
< XElement
> const xRet(
517 static_cast< XNode
* >(GetCNode(pNode
).get()),
522 // Creates an element of the given qualified name and namespace URI.
523 Reference
< XElement
> SAL_CALL
CDocument::createElementNS(
524 const OUString
& ns
, const OUString
& qname
)
526 ::osl::MutexGuard
const g(m_Mutex
);
528 sal_Int32 i
= qname
.indexOf(':');
529 if (ns
.isEmpty()) throw RuntimeException();
530 xmlChar
const *pPrefix
;
531 xmlChar
const *pName
;
534 o1
= OUStringToOString(qname
.subView(0, i
), RTL_TEXTENCODING_UTF8
);
535 pPrefix
= reinterpret_cast<xmlChar
const *>(o1
.getStr());
536 o2
= OUStringToOString(qname
.subView(i
+1), RTL_TEXTENCODING_UTF8
);
537 pName
= reinterpret_cast<xmlChar
const *>(o2
.getStr());
540 pPrefix
= reinterpret_cast<xmlChar
const *>("");
541 o2
= OUStringToOString(qname
, RTL_TEXTENCODING_UTF8
);
542 pName
= reinterpret_cast<xmlChar
const *>(o2
.getStr());
544 o3
= OUStringToOString(ns
, RTL_TEXTENCODING_UTF8
);
545 xmlChar
const *pUri
= reinterpret_cast<xmlChar
const *>(o3
.getStr());
547 // xmlNsPtr aNsPtr = xmlNewReconciledNs?
548 // xmlNsPtr aNsPtr = xmlNewGlobalNs?
549 xmlNodePtr
const pNode
= xmlNewDocNode(m_aDocPtr
, nullptr, pName
, nullptr);
550 xmlNsPtr
const pNs
= xmlNewNs(pNode
, pUri
, pPrefix
);
551 xmlSetNs(pNode
, pNs
);
552 Reference
< XElement
> const xRet(
553 static_cast< XNode
* >(GetCNode(pNode
).get()),
558 //Creates an EntityReference object.
559 Reference
< XEntityReference
> SAL_CALL
CDocument::createEntityReference(const OUString
& name
)
561 ::osl::MutexGuard
const g(m_Mutex
);
563 OString o1
= OUStringToOString(name
, RTL_TEXTENCODING_UTF8
);
564 xmlChar
const *pName
= reinterpret_cast<xmlChar
const *>(o1
.getStr());
565 xmlNodePtr
const pNode
= xmlNewReference(m_aDocPtr
, pName
);
566 Reference
< XEntityReference
> const xRet(
567 static_cast< XNode
* >(GetCNode(pNode
).get()),
572 // Creates a ProcessingInstruction node given the specified name and
574 Reference
< XProcessingInstruction
> SAL_CALL
CDocument::createProcessingInstruction(
575 const OUString
& target
, const OUString
& data
)
577 ::osl::MutexGuard
const g(m_Mutex
);
579 OString o1
= OUStringToOString(target
, RTL_TEXTENCODING_UTF8
);
580 xmlChar
const *pTarget
= reinterpret_cast<xmlChar
const *>(o1
.getStr());
581 OString o2
= OUStringToOString(data
, RTL_TEXTENCODING_UTF8
);
582 xmlChar
const *pData
= reinterpret_cast<xmlChar
const *>(o2
.getStr());
583 xmlNodePtr
const pNode
= xmlNewDocPI(m_aDocPtr
, pTarget
, pData
);
584 pNode
->doc
= m_aDocPtr
;
585 Reference
< XProcessingInstruction
> const xRet(
586 static_cast< XNode
* >(GetCNode(pNode
).get()),
591 // Creates a Text node given the specified string.
592 Reference
< XText
> SAL_CALL
CDocument::createTextNode(const OUString
& data
)
594 ::osl::MutexGuard
const g(m_Mutex
);
596 OString o1
= OUStringToOString(data
, RTL_TEXTENCODING_UTF8
);
597 xmlChar
const *pData
= reinterpret_cast<xmlChar
const *>(o1
.getStr());
598 xmlNodePtr
const pNode
= xmlNewDocText(m_aDocPtr
, pData
);
599 Reference
< XText
> const xRet(
600 static_cast< XNode
* >(GetCNode(pNode
).get()),
605 // The Document Type Declaration (see DocumentType) associated with this
607 Reference
< XDocumentType
> SAL_CALL
CDocument::getDoctype()
609 ::osl::MutexGuard
const g(m_Mutex
);
611 xmlNodePtr
const pDocType(lcl_getDocumentType(m_aDocPtr
));
612 Reference
< XDocumentType
> const xRet(
613 static_cast< XNode
* >(GetCNode(pDocType
).get()),
618 // This is a convenience attribute that allows direct access to the child
619 // node that is the root element of the document.
620 Reference
< XElement
> SAL_CALL
CDocument::getDocumentElement()
622 ::osl::MutexGuard
const g(m_Mutex
);
624 xmlNodePtr
const pNode
= lcl_getDocumentRootPtr(m_aDocPtr
);
625 if (!pNode
) { return nullptr; }
626 Reference
< XElement
> const xRet(
627 static_cast< XNode
* >(GetCNode(pNode
).get()),
633 lcl_search_element_by_id(const xmlNodePtr cur
, const xmlChar
* id
)
637 // look in current node
638 if (cur
->type
== XML_ELEMENT_NODE
)
640 xmlAttrPtr a
= cur
->properties
;
643 if (a
->atype
== XML_ATTRIBUTE_ID
) {
644 if (strcmp(reinterpret_cast<char*>(a
->children
->content
), reinterpret_cast<char const *>(id
)) == 0)
651 xmlNodePtr result
= lcl_search_element_by_id(cur
->children
, id
);
652 if (result
!= nullptr)
654 result
= lcl_search_element_by_id(cur
->next
, id
);
658 // Returns the Element whose ID is given by elementId.
659 Reference
< XElement
> SAL_CALL
660 CDocument::getElementById(const OUString
& elementId
)
662 ::osl::MutexGuard
const g(m_Mutex
);
664 // search the tree for an element with the given ID
665 OString o1
= OUStringToOString(elementId
, RTL_TEXTENCODING_UTF8
);
666 xmlChar
const *pId
= reinterpret_cast<xmlChar
const *>(o1
.getStr());
667 xmlNodePtr
const pStart
= lcl_getDocumentRootPtr(m_aDocPtr
);
668 if (!pStart
) { return nullptr; }
669 xmlNodePtr
const pNode
= lcl_search_element_by_id(pStart
, pId
);
670 Reference
< XElement
> const xRet(
671 static_cast< XNode
* >(GetCNode(pNode
).get()),
677 Reference
< XNodeList
> SAL_CALL
678 CDocument::getElementsByTagName(OUString
const& rTagname
)
680 ::osl::MutexGuard
const g(m_Mutex
);
682 Reference
< XNodeList
> const xRet(
683 new CElementList(GetDocumentElement(), m_Mutex
, rTagname
));
687 Reference
< XNodeList
> SAL_CALL
CDocument::getElementsByTagNameNS(
688 OUString
const& rNamespaceURI
, OUString
const& rLocalName
)
690 ::osl::MutexGuard
const g(m_Mutex
);
692 Reference
< XNodeList
> const xRet(
693 new CElementList(GetDocumentElement(), m_Mutex
,
694 rLocalName
, &rNamespaceURI
));
698 Reference
< XDOMImplementation
> SAL_CALL
CDocument::getImplementation()
700 // does not need mutex currently
701 return Reference
< XDOMImplementation
>(CDOMImplementation::get());
704 // helper function to recursively import siblings
705 static void lcl_ImportSiblings(
706 Reference
< XDocument
> const& xTargetDocument
,
707 Reference
< XNode
> const& xTargetParent
,
708 Reference
< XNode
> const& xChild
)
710 Reference
< XNode
> xSibling
= xChild
;
711 while (xSibling
.is())
713 Reference
< XNode
> const xTmp(
714 xTargetDocument
->importNode(xSibling
, true));
715 xTargetParent
->appendChild(xTmp
);
716 xSibling
= xSibling
->getNextSibling();
720 static Reference
< XNode
>
721 lcl_ImportNode( Reference
< XDocument
> const& xDocument
,
722 Reference
< XNode
> const& xImportedNode
, bool deep
)
724 Reference
< XNode
> xNode
;
725 NodeType aNodeType
= xImportedNode
->getNodeType();
728 case NodeType_ATTRIBUTE_NODE
:
730 Reference
< XAttr
> const xAttr(xImportedNode
, UNO_QUERY_THROW
);
731 Reference
< XAttr
> const xNew
=
732 xDocument
->createAttribute(xAttr
->getName());
733 xNew
->setValue(xAttr
->getValue());
737 case NodeType_CDATA_SECTION_NODE
:
739 Reference
< XCDATASection
> const xCData(xImportedNode
,
741 Reference
< XCDATASection
> const xNewCData
=
742 xDocument
->createCDATASection(xCData
->getData());
746 case NodeType_COMMENT_NODE
:
748 Reference
< XComment
> const xComment(xImportedNode
,
750 Reference
< XComment
> const xNewComment
=
751 xDocument
->createComment(xComment
->getData());
755 case NodeType_DOCUMENT_FRAGMENT_NODE
:
757 Reference
< XDocumentFragment
> const xFrag(xImportedNode
,
759 Reference
< XDocumentFragment
> const xNewFrag
=
760 xDocument
->createDocumentFragment();
764 case NodeType_ELEMENT_NODE
:
766 Reference
< XElement
> const xElement(xImportedNode
,
768 OUString
const aNsUri
= xImportedNode
->getNamespaceURI();
769 OUString
const aNsPrefix
= xImportedNode
->getPrefix();
770 OUString aQName
= xElement
->getTagName();
771 Reference
< XElement
> xNewElement
;
772 if (!aNsUri
.isEmpty())
774 if (!aNsPrefix
.isEmpty()) {
775 aQName
= aNsPrefix
+ ":" + aQName
;
777 xNewElement
= xDocument
->createElementNS(aNsUri
, aQName
);
779 xNewElement
= xDocument
->createElement(aQName
);
783 if (xElement
->hasAttributes())
785 Reference
< XNamedNodeMap
> attribs
= xElement
->getAttributes();
786 for (sal_Int32 i
= 0; i
< attribs
->getLength(); i
++)
788 Reference
< XAttr
> const curAttr(attribs
->item(i
),
790 OUString
const aAttrUri
= curAttr
->getNamespaceURI();
791 OUString
const aAttrPrefix
= curAttr
->getPrefix();
792 OUString aAttrName
= curAttr
->getName();
793 OUString
const sValue
= curAttr
->getValue();
794 if (!aAttrUri
.isEmpty())
796 if (!aAttrPrefix
.isEmpty()) {
797 aAttrName
= aAttrPrefix
+ ":" + aAttrName
;
799 xNewElement
->setAttributeNS(
800 aAttrUri
, aAttrName
, sValue
);
802 xNewElement
->setAttribute(aAttrName
, sValue
);
809 case NodeType_ENTITY_REFERENCE_NODE
:
811 Reference
< XEntityReference
> const xRef(xImportedNode
,
813 Reference
< XEntityReference
> const xNewRef(
814 xDocument
->createEntityReference(xRef
->getNodeName()));
818 case NodeType_PROCESSING_INSTRUCTION_NODE
:
820 Reference
< XProcessingInstruction
> const xPi(xImportedNode
,
822 Reference
< XProcessingInstruction
> const xNewPi(
823 xDocument
->createProcessingInstruction(
824 xPi
->getTarget(), xPi
->getData()));
828 case NodeType_TEXT_NODE
:
830 Reference
< XText
> const xText(xImportedNode
, UNO_QUERY_THROW
);
831 Reference
< XText
> const xNewText(
832 xDocument
->createTextNode(xText
->getData()));
836 case NodeType_ENTITY_NODE
:
837 case NodeType_DOCUMENT_NODE
:
838 case NodeType_DOCUMENT_TYPE_NODE
:
839 case NodeType_NOTATION_NODE
:
842 throw RuntimeException();
847 // get children and import them
848 Reference
< XNode
> const xChild
= xImportedNode
->getFirstChild();
851 lcl_ImportSiblings(xDocument
, xNode
, xChild
);
855 /* DOMNodeInsertedIntoDocument
856 * Fired when a node is being inserted into a document,
857 * either through direct insertion of the Node or insertion of a
858 * subtree in which it is contained. This event is dispatched after
859 * the insertion has taken place. The target of this event is the node
860 * being inserted. If the Node is being directly inserted the DOMNodeInserted
861 * event will fire before the DOMNodeInsertedIntoDocument event.
868 Reference
< XDocumentEvent
> const xDocevent(xDocument
, UNO_QUERY
);
869 Reference
< XMutationEvent
> const event(xDocevent
->createEvent(
870 "DOMNodeInsertedIntoDocument"), UNO_QUERY_THROW
);
871 event
->initMutationEvent(
872 "DOMNodeInsertedIntoDocument", true, false, Reference
< XNode
>(),
873 OUString(), OUString(), OUString(), AttrChangeType(0) );
874 Reference
< XEventTarget
> const xDocET(xDocument
, UNO_QUERY
);
875 xDocET
->dispatchEvent(event
);
881 Reference
< XNode
> SAL_CALL
CDocument::importNode(
882 Reference
< XNode
> const& xImportedNode
, sal_Bool deep
)
884 if (!xImportedNode
.is()) { throw RuntimeException(); }
886 // NB: this whole operation inherently accesses 2 distinct documents.
887 // The imported node could even be from a different DOM implementation,
888 // so this implementation cannot make any assumptions about the
889 // locking strategy of the imported node.
890 // So the import takes no lock on this document;
891 // it only calls UNO methods on this document that temporarily
892 // lock the document, and UNO methods on the imported node that
893 // may temporarily lock the other document.
894 // As a consequence, the import is not atomic with regard to
895 // concurrent modifications of either document, but it should not
897 // To ensure that no members are accessed, the implementation is in
898 // static non-member functions.
900 Reference
< XDocument
> const xDocument(this);
902 if (xImportedNode
->getOwnerDocument() == xDocument
) {
903 return xImportedNode
;
906 Reference
< XNode
> const xNode(
907 lcl_ImportNode(xDocument
, xImportedNode
, deep
) );
911 OUString SAL_CALL
CDocument::getNodeName()
913 // does not need mutex currently
917 OUString SAL_CALL
CDocument::getNodeValue()
919 // does not need mutex currently
923 Reference
< XNode
> SAL_CALL
CDocument::cloneNode(sal_Bool bDeep
)
925 ::osl::MutexGuard
const g(m_rMutex
);
927 OSL_ASSERT(nullptr != m_aNodePtr
);
928 if (nullptr == m_aNodePtr
) {
931 xmlDocPtr
const pClone(xmlCopyDoc(m_aDocPtr
, bDeep
? 1 : 0));
932 if (nullptr == pClone
) { return nullptr; }
933 Reference
< XNode
> const xRet(
934 static_cast<CNode
*>(CDocument::CreateCDocument(pClone
).get()));
938 Reference
< XEvent
> SAL_CALL
CDocument::createEvent(const OUString
& aType
)
940 // does not need mutex currently
941 rtl::Reference
<events::CEvent
> pEvent
;
942 if ( aType
== "DOMSubtreeModified" || aType
== "DOMNodeInserted" || aType
== "DOMNodeRemoved"
943 || aType
== "DOMNodeRemovedFromDocument" || aType
== "DOMNodeInsertedIntoDocument" || aType
== "DOMAttrModified"
944 || aType
== "DOMCharacterDataModified")
946 pEvent
= new events::CMutationEvent
;
948 } else if ( aType
== "DOMFocusIn" || aType
== "DOMFocusOut" || aType
== "DOMActivate")
950 pEvent
= new events::CUIEvent
;
951 } else if ( aType
== "click" || aType
== "mousedown" || aType
== "mouseup"
952 || aType
== "mouseover" || aType
== "mousemove" || aType
== "mouseout" )
954 pEvent
= new events::CMouseEvent
;
956 else // generic event
958 pEvent
= new events::CEvent
;
963 // css::xml::sax::XSAXSerializable
964 void SAL_CALL
CDocument::serialize(
965 const Reference
< XDocumentHandler
>& i_xHandler
,
966 const Sequence
< beans::StringPair
>& i_rNamespaces
)
968 ::osl::MutexGuard
const g(m_Mutex
);
970 // add new namespaces to root node
971 xmlNodePtr
const pRoot
= lcl_getDocumentRootPtr(m_aDocPtr
);
972 if (nullptr != pRoot
) {
973 for (const beans::StringPair
& rNsDef
: i_rNamespaces
) {
974 OString prefix
= OUStringToOString(rNsDef
.First
,
975 RTL_TEXTENCODING_UTF8
);
976 OString href
= OUStringToOString(rNsDef
.Second
,
977 RTL_TEXTENCODING_UTF8
);
978 // this will only add the ns if it does not exist already
979 xmlNewNs(pRoot
, reinterpret_cast<const xmlChar
*>(href
.getStr()),
980 reinterpret_cast<const xmlChar
*>(prefix
.getStr()));
982 // eliminate duplicate namespace declarations
983 nscleanup(pRoot
->children
, pRoot
);
988 // css::xml::sax::XFastSAXSerializable
989 void SAL_CALL
CDocument::fastSerialize( const Reference
< XFastDocumentHandler
>& i_xHandler
,
990 const Reference
< XFastTokenHandler
>& i_xTokenHandler
,
991 const Sequence
< beans::StringPair
>& i_rNamespaces
,
992 const Sequence
< beans::Pair
< OUString
, sal_Int32
> >& i_rRegisterNamespaces
)
994 ::osl::MutexGuard
const g(m_Mutex
);
996 // add new namespaces to root node
997 xmlNodePtr
const pRoot
= lcl_getDocumentRootPtr(m_aDocPtr
);
998 if (nullptr != pRoot
) {
999 for (const beans::StringPair
& rNsDef
: i_rNamespaces
) {
1000 OString prefix
= OUStringToOString(rNsDef
.First
,
1001 RTL_TEXTENCODING_UTF8
);
1002 OString href
= OUStringToOString(rNsDef
.Second
,
1003 RTL_TEXTENCODING_UTF8
);
1004 // this will only add the ns if it does not exist already
1005 xmlNewNs(pRoot
, reinterpret_cast<const xmlChar
*>(href
.getStr()),
1006 reinterpret_cast<const xmlChar
*>(prefix
.getStr()));
1008 // eliminate duplicate namespace declarations
1009 nscleanup(pRoot
->children
, pRoot
);
1012 Context
aContext(i_xHandler
,
1013 dynamic_cast<sax_fastparser::FastTokenHandlerBase
*>(i_xTokenHandler
.get()));
1015 // register namespace ids
1016 for (const beans::Pair
<OUString
,sal_Int32
>& rNs
: i_rRegisterNamespaces
)
1018 OSL_ENSURE(rNs
.Second
>= FastToken::NAMESPACE
,
1019 "CDocument::fastSerialize(): invalid NS token id");
1020 aContext
.maNamespaceMap
[ rNs
.First
] = rNs
.Second
;
1023 fastSaxify(aContext
);
1027 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */