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