xref: /aoo42x/main/unoxml/source/dom/element.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include <element.hxx>
29 
30 #include <string.h>
31 
32 #include <boost/shared_ptr.hpp>
33 
34 #include <rtl/ustrbuf.hxx>
35 
36 #include <com/sun/star/xml/sax/FastToken.hdl>
37 
38 #include <comphelper/attributelist.hxx>
39 
40 #include <node.hxx>
41 #include <attr.hxx>
42 #include <elementlist.hxx>
43 #include <attributesmap.hxx>
44 #include <document.hxx>
45 
46 #include "../events/mutationevent.hxx"
47 
48 
49 namespace DOM
50 {
51 
52     CElement::CElement(CDocument const& rDocument, ::osl::Mutex const& rMutex,
53             xmlNodePtr const pNode)
54         : CElement_Base(rDocument, rMutex, NodeType_ELEMENT_NODE, pNode)
55     {
56     }
57 
58     void CElement::saxify(const Reference< XDocumentHandler >& i_xHandler)
59     {
60         if (!i_xHandler.is()) throw RuntimeException();
61         comphelper::AttributeList *pAttrs =
62             new comphelper::AttributeList();
63         OUString type = OUString::createFromAscii("");
64         // add namespace definitions to attributes
65         for (xmlNsPtr pNs = m_aNodePtr->nsDef; pNs != 0; pNs = pNs->next) {
66             const xmlChar *pPrefix = pNs->prefix;
67             OUString prefix(reinterpret_cast<const sal_Char*>(pPrefix),
68                 strlen(reinterpret_cast<const char*>(pPrefix)),
69                 RTL_TEXTENCODING_UTF8);
70             OUString name = (prefix.equalsAscii(""))
71                 ? OUString::createFromAscii("xmlns")
72                 : OUString::createFromAscii("xmlns:") + prefix;
73             const xmlChar *pHref = pNs->href;
74             OUString val(reinterpret_cast<const sal_Char*>(pHref),
75                 strlen(reinterpret_cast<const char*>(pHref)),
76                 RTL_TEXTENCODING_UTF8);
77             pAttrs->AddAttribute(name, type, val);
78         }
79         // add attributes
80         for (xmlAttrPtr pAttr = m_aNodePtr->properties;
81                         pAttr != 0; pAttr = pAttr->next) {
82             ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(
83                     reinterpret_cast<xmlNodePtr>(pAttr));
84             OSL_ENSURE(pNode != 0, "CNode::get returned 0");
85             OUString prefix = pNode->getPrefix();
86             OUString name = (prefix.getLength() == 0)
87                 ? pNode->getLocalName()
88                 : prefix + OUString(static_cast<sal_Unicode>(':')) + pNode->getLocalName();
89             OUString val  = pNode->getNodeValue();
90             pAttrs->AddAttribute(name, type, val);
91         }
92         OUString prefix = getPrefix();
93         OUString name = (prefix.getLength() == 0)
94             ? getLocalName()
95             : prefix + OUString(static_cast<sal_Unicode>(':')) + getLocalName();
96         Reference< XAttributeList > xAttrList(pAttrs);
97         i_xHandler->startElement(name, xAttrList);
98         // recurse
99         for (xmlNodePtr pChild = m_aNodePtr->children;
100                         pChild != 0; pChild = pChild->next) {
101             ::rtl::Reference<CNode> const pNode(
102                     GetOwnerDocument().GetCNode(pChild));
103             OSL_ENSURE(pNode != 0, "CNode::get returned 0");
104             pNode->saxify(i_xHandler);
105         }
106         i_xHandler->endElement(name);
107     }
108 
109     void CElement::fastSaxify( Context& i_rContext )
110     {
111         if (!i_rContext.mxDocHandler.is()) throw RuntimeException();
112         pushContext(i_rContext);
113         addNamespaces(i_rContext,m_aNodePtr);
114 
115         // add attributes
116         i_rContext.mxAttribList->clear();
117         for (xmlAttrPtr pAttr = m_aNodePtr->properties;
118                         pAttr != 0; pAttr = pAttr->next) {
119             ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(
120                     reinterpret_cast<xmlNodePtr>(pAttr));
121             OSL_ENSURE(pNode != 0, "CNode::get returned 0");
122 
123             const xmlChar* xName = pAttr->name;
124             sal_Int32 nAttributeToken=FastToken::DONTKNOW;
125 
126             if( pAttr->ns && strlen((char*)pAttr->ns->prefix) )
127                 nAttributeToken = getTokenWithPrefix( i_rContext,
128                                                       (sal_Char*)pAttr->ns->prefix,
129                                                       (sal_Char*)xName );
130             else
131                 nAttributeToken = getToken( i_rContext, (sal_Char*)xName );
132 
133             if( nAttributeToken != FastToken::DONTKNOW )
134                 i_rContext.mxAttribList->add( nAttributeToken,
135                                               OUStringToOString(pNode->getNodeValue(),
136                                                                 RTL_TEXTENCODING_UTF8));
137         }
138 
139         const xmlChar* xPrefix = m_aNodePtr->ns ? m_aNodePtr->ns->prefix : (const xmlChar*)"";
140         const xmlChar* xName = m_aNodePtr->name;
141         sal_Int32 nElementToken=FastToken::DONTKNOW;
142         if( strlen((char*)xPrefix) )
143             nElementToken = getTokenWithPrefix( i_rContext, (sal_Char*)xPrefix, (sal_Char*)xName );
144         else
145             nElementToken = getToken( i_rContext, (sal_Char*)xName );
146 
147         Reference<XFastContextHandler> xParentHandler(i_rContext.mxCurrentHandler);
148         try
149         {
150             Reference< XFastAttributeList > xAttr( i_rContext.mxAttribList.get() );
151             if( nElementToken == FastToken::DONTKNOW )
152             {
153                 const OUString aNamespace;
154                 const OUString aElementName( (sal_Char*)xPrefix,
155                                              strlen((char*)xPrefix),
156                                              RTL_TEXTENCODING_UTF8 );
157 
158                 if( xParentHandler.is() )
159                     i_rContext.mxCurrentHandler = xParentHandler->createUnknownChildContext( aNamespace, aElementName, xAttr );
160                 else
161                     i_rContext.mxCurrentHandler = i_rContext.mxDocHandler->createUnknownChildContext( aNamespace, aElementName, xAttr );
162 
163                 if( i_rContext.mxCurrentHandler.is() )
164                     i_rContext.mxCurrentHandler->startUnknownElement( aNamespace, aElementName, xAttr );
165             }
166             else
167             {
168                 if( xParentHandler.is() )
169                     i_rContext.mxCurrentHandler = xParentHandler->createFastChildContext( nElementToken, xAttr );
170                 else
171                     i_rContext.mxCurrentHandler = i_rContext.mxDocHandler->createFastChildContext( nElementToken, xAttr );
172 
173                 if( i_rContext.mxCurrentHandler.is() )
174                     i_rContext.mxCurrentHandler->startFastElement( nElementToken, xAttr );
175             }
176         }
177         catch( Exception& )
178         {}
179 
180         // recurse
181         for (xmlNodePtr pChild = m_aNodePtr->children;
182                         pChild != 0; pChild = pChild->next) {
183             ::rtl::Reference<CNode> const pNode(
184                     GetOwnerDocument().GetCNode(pChild));
185             OSL_ENSURE(pNode != 0, "CNode::get returned 0");
186             pNode->fastSaxify(i_rContext);
187         }
188 
189 		if( i_rContext.mxCurrentHandler.is() ) try
190 		{
191 			if( nElementToken != FastToken::DONTKNOW )
192 				i_rContext.mxCurrentHandler->endFastElement( nElementToken );
193 			else
194             {
195                 const OUString aNamespace;
196                 const OUString aElementName( (sal_Char*)xPrefix,
197                                              strlen((char*)xPrefix),
198                                              RTL_TEXTENCODING_UTF8 );
199 
200 				i_rContext.mxCurrentHandler->endUnknownElement( aNamespace, aElementName );
201             }
202 		}
203 		catch( Exception& )
204 		{}
205 
206         // restore after children have been processed
207         i_rContext.mxCurrentHandler = xParentHandler;
208         popContext(i_rContext);
209     }
210 
211     bool CElement::IsChildTypeAllowed(NodeType const nodeType)
212     {
213         switch (nodeType) {
214             case NodeType_ELEMENT_NODE:
215             case NodeType_TEXT_NODE:
216             case NodeType_COMMENT_NODE:
217             case NodeType_PROCESSING_INSTRUCTION_NODE:
218             case NodeType_CDATA_SECTION_NODE:
219             case NodeType_ENTITY_REFERENCE_NODE:
220                 return true;
221             case NodeType_ATTRIBUTE_NODE:
222                 /* this is not relly allowed by the DOM spec, but this
223                    implementation has evidently supported it (by special case
224                    handling, so the attribute does not actually become a child)
225                    so allow it for backward compatiblity */
226                 return true;
227             default:
228                 return false;
229         }
230     }
231 
232 
233     /**
234 		Retrieves an attribute value by name.
235 		return empty string if attribute is not set
236     */
237     OUString SAL_CALL CElement::getAttribute(OUString const& name)
238         throw (RuntimeException)
239     {
240         ::osl::MutexGuard const g(m_rMutex);
241 
242         if (0 == m_aNodePtr) {
243             return ::rtl::OUString();
244         }
245         // search properties
246         OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
247         ::boost::shared_ptr<xmlChar const> const pValue(
248             xmlGetProp(m_aNodePtr, (xmlChar*)o1.getStr()), xmlFree);
249         OUString const ret( (pValue)
250             ?   OUString(reinterpret_cast<sal_Char const*>(pValue.get()),
251                         strlen(reinterpret_cast<char const*>(pValue.get())),
252                         RTL_TEXTENCODING_UTF8)
253             :   OUString() );
254         return ret;
255     }
256 
257     /**
258     Retrieves an attribute node by name.
259     */
260     Reference< XAttr > SAL_CALL CElement::getAttributeNode(OUString const& name)
261         throw (RuntimeException)
262     {
263         ::osl::MutexGuard const g(m_rMutex);
264 
265         if (0 == m_aNodePtr) {
266             return 0;
267         }
268         OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
269         xmlChar const*const pName =
270             reinterpret_cast<xmlChar const*>(o1.getStr());
271         xmlAttrPtr const pAttr = xmlHasProp(m_aNodePtr, pName);
272         if (0 == pAttr) {
273             return 0;
274         }
275         Reference< XAttr > const xRet(
276             static_cast< XNode* >(GetOwnerDocument().GetCNode(
277                     reinterpret_cast<xmlNodePtr>(pAttr)).get()),
278             UNO_QUERY_THROW);
279         return xRet;
280     }
281 
282     /**
283     Retrieves an Attr node by local name and namespace URI.
284     */
285     Reference< XAttr > SAL_CALL CElement::getAttributeNodeNS(
286             const OUString& namespaceURI, const OUString& localName)
287         throw (RuntimeException)
288     {
289         ::osl::MutexGuard const g(m_rMutex);
290 
291         if (0 == m_aNodePtr) {
292             return 0;
293         }
294         OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
295         xmlChar const*const pName =
296             reinterpret_cast<xmlChar const*>(o1.getStr());
297         OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
298         xmlChar const*const pNS =
299             reinterpret_cast<xmlChar const*>(o2.getStr());
300         xmlAttrPtr const pAttr = xmlHasNsProp(m_aNodePtr, pName, pNS);
301         if (0 == pAttr) {
302             return 0;
303         }
304         Reference< XAttr > const xRet(
305             static_cast< XNode* >(GetOwnerDocument().GetCNode(
306                     reinterpret_cast<xmlNodePtr>(pAttr)).get()),
307             UNO_QUERY_THROW);
308         return xRet;
309     }
310 
311     /**
312     Retrieves an attribute value by local name and namespace URI.
313 	return empty string if attribute is not set
314     */
315     OUString SAL_CALL
316     CElement::getAttributeNS(
317             OUString const& namespaceURI, OUString const& localName)
318         throw (RuntimeException)
319     {
320         ::osl::MutexGuard const g(m_rMutex);
321 
322         if (0 == m_aNodePtr) {
323             return ::rtl::OUString();
324         }
325         OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
326         xmlChar const*const pName =
327             reinterpret_cast<xmlChar const*>(o1.getStr());
328         OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
329         xmlChar const*const pNS =
330             reinterpret_cast<xmlChar const*>(o2.getStr());
331         ::boost::shared_ptr<xmlChar const> const pValue(
332                 xmlGetNsProp(m_aNodePtr, pName, pNS), xmlFree);
333         if (0 == pValue) {
334             return ::rtl::OUString();
335         }
336         OUString const ret(reinterpret_cast<sal_Char const*>(pValue.get()),
337                         strlen(reinterpret_cast<char const*>(pValue.get())),
338                         RTL_TEXTENCODING_UTF8);
339         return ret;
340     }
341 
342     /**
343     Returns a NodeList of all descendant Elements with a given tag name,
344     in the order in which they are
345     encountered in a preorder traversal of this Element tree.
346     */
347     Reference< XNodeList > SAL_CALL
348     CElement::getElementsByTagName(OUString const& rLocalName)
349         throw (RuntimeException)
350     {
351         ::osl::MutexGuard const g(m_rMutex);
352 
353         Reference< XNodeList > const xList(
354                 new CElementList(this, m_rMutex, rLocalName));
355         return xList;
356     }
357 
358     /**
359     Returns a NodeList of all the descendant Elements with a given local
360     name and namespace URI in the order in which they are encountered in
361     a preorder traversal of this Element tree.
362     */
363     Reference< XNodeList > SAL_CALL
364     CElement::getElementsByTagNameNS(
365             OUString const& rNamespaceURI, OUString const& rLocalName)
366         throw (RuntimeException)
367     {
368         ::osl::MutexGuard const g(m_rMutex);
369 
370         Reference< XNodeList > const xList(
371             new CElementList(this, m_rMutex, rLocalName, &rNamespaceURI));
372         return xList;
373     }
374 
375     /**
376     The name of the element.
377     */
378     OUString SAL_CALL CElement::getTagName()
379         throw (RuntimeException)
380     {
381         ::osl::MutexGuard const g(m_rMutex);
382 
383         if (0 == m_aNodePtr) {
384             return ::rtl::OUString();
385         }
386         OUString const ret((sal_Char*)m_aNodePtr->name,
387                 strlen((char*)m_aNodePtr->name), RTL_TEXTENCODING_UTF8);
388         return ret;
389     }
390 
391 
392     /**
393     Returns true when an attribute with a given name is specified on this
394     element or has a default value, false otherwise.
395     */
396     sal_Bool SAL_CALL CElement::hasAttribute(OUString const& name)
397         throw (RuntimeException)
398     {
399         ::osl::MutexGuard const g(m_rMutex);
400 
401         OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
402         xmlChar *xName = (xmlChar*)o1.getStr();
403         return (m_aNodePtr != NULL && xmlHasProp(m_aNodePtr, xName) != NULL);
404     }
405 
406     /**
407     Returns true when an attribute with a given local name and namespace
408     URI is specified on this element or has a default value, false otherwise.
409     */
410     sal_Bool SAL_CALL CElement::hasAttributeNS(
411             OUString const& namespaceURI, OUString const& localName)
412         throw (RuntimeException)
413     {
414         ::osl::MutexGuard const g(m_rMutex);
415 
416         OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
417         xmlChar *xName = (xmlChar*)o1.getStr();
418         OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
419         xmlChar *xNs = (xmlChar*)o2.getStr();
420         return (m_aNodePtr != NULL && xmlHasNsProp(m_aNodePtr, xName, xNs) != NULL);
421     }
422 
423     /**
424     Removes an attribute by name.
425     */
426     void SAL_CALL CElement::removeAttribute(OUString const& name)
427         throw (RuntimeException, DOMException)
428     {
429         ::osl::MutexGuard const g(m_rMutex);
430 
431         if (0 == m_aNodePtr) {
432             return;
433         }
434         OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
435         xmlChar const*const pName =
436             reinterpret_cast<xmlChar const*>(o1.getStr());
437         xmlAttrPtr const pAttr = xmlHasProp(m_aNodePtr, pName);
438         if (0 == xmlUnsetProp(m_aNodePtr, pName)) {
439             ::rtl::Reference<CNode> const pCNode(GetOwnerDocument().GetCNode(
440                     reinterpret_cast<xmlNodePtr>(pAttr), false));
441             if (pCNode.is()) {
442                 pCNode->invalidate(); // freed by xmlUnsetProp
443             }
444         }
445     }
446 
447     /**
448     Removes an attribute by local name and namespace URI.
449     */
450     void SAL_CALL CElement::removeAttributeNS(
451             OUString const& namespaceURI, OUString const& localName)
452         throw (RuntimeException, DOMException)
453     {
454         ::osl::MutexGuard const g(m_rMutex);
455 
456         if (0 == m_aNodePtr) {
457             return;
458         }
459         OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
460         xmlChar const*const pName =
461             reinterpret_cast<xmlChar const*>(o1.getStr());
462         OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
463         xmlChar const*const pURI =
464             reinterpret_cast<xmlChar const*>(o2.getStr());
465         xmlNsPtr const pNs =
466             xmlSearchNsByHref(m_aNodePtr->doc, m_aNodePtr, pURI);
467         xmlAttrPtr const pAttr = xmlHasNsProp(m_aNodePtr, pName, pURI);
468         if (0 == xmlUnsetNsProp(m_aNodePtr, pNs, pName)) {
469             ::rtl::Reference<CNode> const pCNode(GetOwnerDocument().GetCNode(
470                     reinterpret_cast<xmlNodePtr>(pAttr), false));
471             if (pCNode.is()) {
472                 pCNode->invalidate(); // freed by xmlUnsetNsProp
473             }
474         }
475     }
476 
477     /**
478     Removes the specified attribute node.
479     */
480     Reference< XAttr > SAL_CALL
481     CElement::removeAttributeNode(Reference< XAttr > const& oldAttr)
482         throw (RuntimeException, DOMException)
483     {
484         ::osl::MutexGuard const g(m_rMutex);
485 
486         if (0 == m_aNodePtr) {
487             return 0;
488         }
489 
490         ::rtl::Reference<CNode> const pCNode(
491             CNode::GetImplementation(Reference<XNode>(oldAttr.get())));
492         if (!pCNode.is()) { throw RuntimeException(); }
493 
494         xmlNodePtr const pNode = pCNode->GetNodePtr();
495         xmlAttrPtr const pAttr = (xmlAttrPtr) pNode;
496         if (!pAttr) { throw RuntimeException(); }
497 
498         if (pAttr->parent != m_aNodePtr)
499         {
500             DOMException e;
501             e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
502             throw e;
503         }
504         if (pAttr->doc != m_aNodePtr->doc)
505         {
506             DOMException e;
507             e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
508             throw e;
509         }
510 
511         Reference< XAttr > aAttr;
512         if (oldAttr->getNamespaceURI().getLength() > 0) {
513             ::rtl::OUStringBuffer qname(oldAttr->getPrefix());
514             if (0 != qname.getLength()) {
515                 qname.append(sal_Unicode(':'));
516             }
517             qname.append(oldAttr->getName());
518             aAttr = GetOwnerDocument().createAttributeNS(
519                 oldAttr->getNamespaceURI(), qname.makeStringAndClear());
520         } else {
521             aAttr = GetOwnerDocument().createAttribute(oldAttr->getName());
522         }
523         aAttr->setValue(oldAttr->getValue());
524         xmlRemoveProp(pAttr);
525         pCNode->invalidate(); // freed by xmlRemoveProp
526 
527         return aAttr;
528     }
529 
530     /**
531     Adds a new attribute node.
532     */
533     Reference< XAttr >
534     CElement::setAttributeNode_Impl_Lock(
535             Reference< XAttr > const& xNewAttr, bool const bNS)
536     {
537         if (xNewAttr->getOwnerDocument() != getOwnerDocument()) {
538             DOMException e;
539             e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
540             throw e;
541         }
542 
543         ::osl::ClearableMutexGuard guard(m_rMutex);
544 
545         if (0 == m_aNodePtr) {
546             throw RuntimeException();
547         }
548 
549         // get the implementation
550         CAttr *const pCAttr = dynamic_cast<CAttr*>(
551                 CNode::GetImplementation(xNewAttr));
552         if (!pCAttr) { throw RuntimeException(); }
553         xmlAttrPtr const pAttr =
554             reinterpret_cast<xmlAttrPtr>(pCAttr->GetNodePtr());
555         if (!pAttr) { throw RuntimeException(); }
556 
557         // check whether the attribute is not in use by another element
558         if (pAttr->parent) {
559             DOMException e;
560             e.Code = DOMExceptionType_INUSE_ATTRIBUTE_ERR;
561             throw e;
562         }
563 
564         xmlAttrPtr res = NULL;
565         xmlChar const*const pContent(
566                 (pAttr->children) ? pAttr->children->content : 0);
567 
568         if (bNS) {
569             xmlNsPtr const pNs( pCAttr->GetNamespace(m_aNodePtr) );
570             res = xmlNewNsProp(m_aNodePtr, pNs, pAttr->name, pContent);
571         } else {
572             res = xmlNewProp(m_aNodePtr, pAttr->name, pContent);
573         }
574 
575         // get the new attr node
576         Reference< XAttr > const xAttr(
577             static_cast< XNode* >(GetOwnerDocument().GetCNode(
578                     reinterpret_cast<xmlNodePtr>(res)).get()),
579             UNO_QUERY_THROW);
580 
581         // attribute adition event
582         // dispatch DOMAttrModified event
583         Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
584         Reference< XMutationEvent > event(docevent->createEvent(
585             OUString::createFromAscii("DOMAttrModified")), UNO_QUERY);
586         event->initMutationEvent(OUString::createFromAscii("DOMAttrModified"),
587             sal_True, sal_False, Reference< XNode >(xAttr, UNO_QUERY),
588             OUString(), xAttr->getValue(), xAttr->getName(),
589             AttrChangeType_ADDITION);
590 
591         guard.clear(); // release mutex before calling event handlers
592 
593         dispatchEvent(Reference< XEvent >(event, UNO_QUERY));
594         dispatchSubtreeModified();
595 
596         return xAttr;
597     }
598 
599     Reference< XAttr >
600     CElement::setAttributeNode(const Reference< XAttr >& newAttr)
601         throw (RuntimeException, DOMException)
602     {
603         return setAttributeNode_Impl_Lock(newAttr, false);
604     }
605 
606     /**
607     Adds a new attribute.
608     */
609     Reference< XAttr >
610     CElement::setAttributeNodeNS(const Reference< XAttr >& newAttr)
611         throw (RuntimeException, DOMException)
612     {
613         return setAttributeNode_Impl_Lock(newAttr, true);
614     }
615 
616     /**
617     Adds a new attribute.
618     */
619     void SAL_CALL
620     CElement::setAttribute(OUString const& name, OUString const& value)
621         throw (RuntimeException, DOMException)
622     {
623         ::osl::ClearableMutexGuard guard(m_rMutex);
624 
625         OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
626         xmlChar *xName = (xmlChar*)o1.getStr();
627         OString o2 = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
628         xmlChar *xValue = (xmlChar*)o2.getStr();
629 
630         if (0 == m_aNodePtr) {
631             throw RuntimeException();
632         }
633         OUString oldValue;
634         AttrChangeType aChangeType = AttrChangeType_MODIFICATION;
635         ::boost::shared_ptr<xmlChar const> const pOld(
636             xmlGetProp(m_aNodePtr, xName), xmlFree);
637         if (pOld == NULL) {
638             aChangeType = AttrChangeType_ADDITION;
639             xmlNewProp(m_aNodePtr, xName, xValue);
640         } else {
641             oldValue = OUString(reinterpret_cast<sal_Char const*>(pOld.get()),
642                         strlen(reinterpret_cast<char const*>(pOld.get())),
643                         RTL_TEXTENCODING_UTF8);
644             xmlSetProp(m_aNodePtr, xName, xValue);
645         }
646 
647         // dispatch DOMAttrModified event
648         Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
649         Reference< XMutationEvent > event(docevent->createEvent(
650             OUString::createFromAscii("DOMAttrModified")), UNO_QUERY);
651         event->initMutationEvent(OUString::createFromAscii("DOMAttrModified"),
652             sal_True, sal_False,
653             Reference< XNode >(getAttributeNode(name), UNO_QUERY),
654             oldValue, value, name, aChangeType);
655 
656         guard.clear(); // release mutex before calling event handlers
657         dispatchEvent(Reference< XEvent >(event, UNO_QUERY));
658         dispatchSubtreeModified();
659     }
660 
661     /**
662     Adds a new attribute.
663     */
664     void SAL_CALL
665     CElement::setAttributeNS(OUString const& namespaceURI,
666             OUString const& qualifiedName, OUString const& value)
667         throw (RuntimeException, DOMException)
668     {
669         if (namespaceURI.getLength() == 0) throw RuntimeException();
670 
671         ::osl::ClearableMutexGuard guard(m_rMutex);
672 
673         OString o1, o2, o3, o4, o5;
674         xmlChar *xPrefix = NULL;
675         xmlChar *xLName = NULL;
676         o1 = OUStringToOString(qualifiedName, RTL_TEXTENCODING_UTF8);
677         xmlChar *xQName = (xmlChar*)o1.getStr();
678         sal_Int32 idx = qualifiedName.indexOf(':');
679         if (idx != -1)
680         {
681             o2 = OUStringToOString(
682                 qualifiedName.copy(0,idx),
683                 RTL_TEXTENCODING_UTF8);
684             xPrefix = (xmlChar*)o2.getStr();
685             o3 = OUStringToOString(
686                 qualifiedName.copy(idx+1),
687                 RTL_TEXTENCODING_UTF8);
688             xLName = (xmlChar*)o3.getStr();
689         }  else {
690             xPrefix = (xmlChar*)"";
691             xLName = xQName;
692         }
693         o4 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
694         o5 = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
695         xmlChar *xURI= (xmlChar*)o4.getStr();
696         xmlChar *xValue = (xmlChar*)o5.getStr();
697 
698         if (0 == m_aNodePtr) {
699             throw RuntimeException();
700         }
701 
702         //find the right namespace
703         xmlNsPtr pNs = xmlSearchNs(m_aNodePtr->doc, m_aNodePtr, xPrefix);
704         // if no namespace found, create a new one
705         if (pNs == NULL) {
706             pNs = xmlNewNs(m_aNodePtr, xURI, xPrefix);
707         }
708 
709         if (strcmp((char*)pNs->href, (char*)xURI) != 0) {
710             // ambiguous ns prefix
711             throw RuntimeException();
712         }
713 
714         // found namespace matches
715 
716         OUString oldValue;
717         AttrChangeType aChangeType = AttrChangeType_MODIFICATION;
718         ::boost::shared_ptr<xmlChar const> const pOld(
719                 xmlGetNsProp(m_aNodePtr, xLName, pNs->href), xmlFree);
720         if (pOld == NULL) {
721             aChangeType = AttrChangeType_ADDITION;
722             xmlNewNsProp(m_aNodePtr, pNs, xLName, xValue);
723         } else {
724             oldValue = OUString(reinterpret_cast<sal_Char const*>(pOld.get()),
725                         strlen(reinterpret_cast<char const*>(pOld.get())),
726                         RTL_TEXTENCODING_UTF8);
727             xmlSetNsProp(m_aNodePtr, pNs, xLName, xValue);
728         }
729         // dispatch DOMAttrModified event
730         Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
731         Reference< XMutationEvent > event(docevent->createEvent(
732             OUString::createFromAscii("DOMAttrModified")), UNO_QUERY);
733         event->initMutationEvent(
734             OUString::createFromAscii("DOMAttrModified"),
735             sal_True, sal_False,
736             Reference< XNode >(getAttributeNodeNS(namespaceURI, OUString((char*)xLName, strlen((char*)xLName), RTL_TEXTENCODING_UTF8)), UNO_QUERY),
737             oldValue, value, qualifiedName, aChangeType);
738 
739         guard.clear(); // release mutex before calling event handlers
740         dispatchEvent(Reference< XEvent >(event, UNO_QUERY));
741         dispatchSubtreeModified();
742     }
743 
744     Reference< XNamedNodeMap > SAL_CALL
745     CElement::getAttributes() throw (RuntimeException)
746     {
747         ::osl::MutexGuard const g(m_rMutex);
748 
749         Reference< XNamedNodeMap > const xMap(
750                 new CAttributesMap(this, m_rMutex));
751         return xMap;
752     }
753 
754     OUString SAL_CALL CElement::getNodeName()throw (RuntimeException)
755     {
756         return getLocalName();
757     }
758 
759     OUString SAL_CALL CElement::getLocalName()throw (RuntimeException)
760     {
761         ::osl::MutexGuard const g(m_rMutex);
762 
763         OUString aName;
764         if (m_aNodePtr != NULL)
765         {
766             const xmlChar* xName = m_aNodePtr->name;
767             aName = OUString((const sal_Char*)xName, strlen((const char*)xName), RTL_TEXTENCODING_UTF8);
768         }
769         return aName;
770     }
771 
772     OUString SAL_CALL CElement::getNodeValue() throw (RuntimeException)
773     {
774         return OUString();
775     }
776 
777     void SAL_CALL CElement::setElementName(const OUString& aName)
778         throw (RuntimeException, DOMException)
779     {
780         if ((aName.getLength() <= 0) ||
781             (0 <= aName.indexOf(OUString::createFromAscii(":"))))
782         {
783             DOMException e;
784             e.Code = DOMExceptionType_INVALID_CHARACTER_ERR;
785             throw e;
786         }
787 
788         ::osl::MutexGuard const g(m_rMutex);
789 
790         if (0 == m_aNodePtr) {
791             throw RuntimeException();
792         }
793         OString oName = OUStringToOString(aName, RTL_TEXTENCODING_UTF8);
794         xmlChar *xName = (xmlChar*)oName.getStr();
795         xmlNodeSetName(m_aNodePtr, xName);
796     }
797 
798 }
799