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