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 #if defined(_MSC_VER) && (_MSC_VER > 1310) 28 #pragma warning(disable : 4701) 29 #endif 30 31 #include "saxbuilder.hxx" 32 33 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp> 34 35 36 namespace DOM 37 { 38 Reference< XInterface > CSAXDocumentBuilder::_getInstance(const Reference< XMultiServiceFactory >& rSMgr) 39 { 40 return static_cast< XSAXDocumentBuilder* >(new CSAXDocumentBuilder(rSMgr)); 41 } 42 43 const char* CSAXDocumentBuilder::aImplementationName = "com.sun.star.comp.xml.dom.SAXDocumentBuilder"; 44 const char* CSAXDocumentBuilder::aSupportedServiceNames[] = { 45 "com.sun.star.xml.dom.SAXDocumentBuilder", 46 NULL 47 }; 48 49 CSAXDocumentBuilder::CSAXDocumentBuilder(const Reference< XMultiServiceFactory >& mgr) 50 : m_aServiceManager(mgr) 51 , m_aState( SAXDocumentBuilderState_READY) 52 {} 53 54 OUString CSAXDocumentBuilder::_getImplementationName() 55 { 56 return OUString::createFromAscii(aImplementationName); 57 } 58 Sequence<OUString> CSAXDocumentBuilder::_getSupportedServiceNames() 59 { 60 Sequence<OUString> aSequence; 61 for (int i=0; aSupportedServiceNames[i]!=NULL; i++) { 62 aSequence.realloc(i+1); 63 aSequence[i]=(OUString::createFromAscii(aSupportedServiceNames[i])); 64 } 65 return aSequence; 66 } 67 68 Sequence< OUString > SAL_CALL CSAXDocumentBuilder::getSupportedServiceNames() 69 throw (RuntimeException) 70 { 71 return CSAXDocumentBuilder::_getSupportedServiceNames(); 72 } 73 74 OUString SAL_CALL CSAXDocumentBuilder::getImplementationName() 75 throw (RuntimeException) 76 { 77 return CSAXDocumentBuilder::_getImplementationName(); 78 } 79 80 sal_Bool SAL_CALL CSAXDocumentBuilder::supportsService(const OUString& aServiceName) 81 throw (RuntimeException) 82 { 83 Sequence< OUString > supported = CSAXDocumentBuilder::_getSupportedServiceNames(); 84 for (sal_Int32 i=0; i<supported.getLength(); i++) 85 { 86 if (supported[i] == aServiceName) return sal_True; 87 } 88 return sal_False; 89 } 90 91 92 SAXDocumentBuilderState SAL_CALL CSAXDocumentBuilder::getState() 93 throw (RuntimeException) 94 { 95 ::osl::MutexGuard g(m_Mutex); 96 97 return m_aState; 98 } 99 100 void SAL_CALL CSAXDocumentBuilder::reset() 101 throw (RuntimeException) 102 { 103 ::osl::MutexGuard g(m_Mutex); 104 105 m_aDocument = Reference< XDocument >(); 106 m_aFragment = Reference< XDocumentFragment >(); 107 while (!m_aNodeStack.empty()) m_aNodeStack.pop(); 108 while (!m_aNSStack.empty()) m_aNSStack.pop(); 109 m_aState = SAXDocumentBuilderState_READY; 110 } 111 112 Reference< XDocument > SAL_CALL CSAXDocumentBuilder::getDocument() 113 throw (RuntimeException) 114 { 115 ::osl::MutexGuard g(m_Mutex); 116 117 if (m_aState != SAXDocumentBuilderState_DOCUMENT_FINISHED) 118 throw RuntimeException(); 119 120 return m_aDocument; 121 } 122 123 Reference< XDocumentFragment > SAL_CALL CSAXDocumentBuilder::getDocumentFragment() 124 throw (RuntimeException) 125 { 126 ::osl::MutexGuard g(m_Mutex); 127 128 if (m_aState != SAXDocumentBuilderState_FRAGMENT_FINISHED) 129 throw RuntimeException(); 130 return m_aFragment; 131 } 132 133 void SAL_CALL CSAXDocumentBuilder::startDocumentFragment(const Reference< XDocument >& ownerDoc) 134 throw (RuntimeException) 135 { 136 ::osl::MutexGuard g(m_Mutex); 137 138 // start a new document fragment and push it onto the stack 139 // we have to be in a clean state to do this 140 if (!m_aState == SAXDocumentBuilderState_READY) 141 throw RuntimeException(); 142 143 m_aDocument = ownerDoc; 144 Reference< XDocumentFragment > aFragment = m_aDocument->createDocumentFragment(); 145 m_aNodeStack.push(Reference< XNode >(aFragment, UNO_QUERY)); 146 m_aFragment = aFragment; 147 m_aState = SAXDocumentBuilderState_BUILDING_FRAGMENT; 148 } 149 150 void SAL_CALL CSAXDocumentBuilder::endDocumentFragment() 151 throw (RuntimeException) 152 { 153 ::osl::MutexGuard g(m_Mutex); 154 155 // there should only be the document left on the node stack 156 if (m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) 157 throw RuntimeException(); 158 159 Reference< XNode > aNode = m_aNodeStack.top(); 160 if ( aNode->getNodeType() != NodeType_DOCUMENT_FRAGMENT_NODE) 161 throw RuntimeException(); 162 m_aNodeStack.pop(); 163 m_aState = SAXDocumentBuilderState_FRAGMENT_FINISHED; 164 } 165 166 // document handler 167 168 void SAL_CALL CSAXDocumentBuilder::startDocument() throw (RuntimeException, SAXException) 169 { 170 ::osl::MutexGuard g(m_Mutex); 171 172 // start a new document and push it onto the stack 173 // we have to be in a clean state to do this 174 if (!m_aState == SAXDocumentBuilderState_READY) 175 throw SAXException(); 176 177 Reference< XDocumentBuilder > aBuilder(m_aServiceManager->createInstance( 178 OUString::createFromAscii("com.sun.star.xml.dom.DocumentBuilder")), UNO_QUERY_THROW); 179 Reference< XDocument > aDocument = aBuilder->newDocument(); 180 m_aNodeStack.push(Reference< XNode >(aDocument, UNO_QUERY)); 181 m_aDocument = aDocument; 182 m_aState = SAXDocumentBuilderState_BUILDING_DOCUMENT; 183 } 184 185 void SAL_CALL CSAXDocumentBuilder::endDocument() throw (RuntimeException, SAXException) 186 { 187 ::osl::MutexGuard g(m_Mutex); 188 189 // there should only be the document left on the node stack 190 if (!m_aState == SAXDocumentBuilderState_BUILDING_DOCUMENT) 191 throw SAXException(); 192 193 Reference< XNode > aNode = m_aNodeStack.top(); 194 if ( aNode->getNodeType() != NodeType_DOCUMENT_NODE) 195 throw SAXException(); 196 m_aNodeStack.pop(); 197 m_aState = SAXDocumentBuilderState_DOCUMENT_FINISHED; 198 } 199 200 void SAL_CALL CSAXDocumentBuilder::startElement(const OUString& aName, const Reference< XAttributeList>& attribs) 201 throw (RuntimeException, SAXException) 202 { 203 ::osl::MutexGuard g(m_Mutex); 204 205 if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && 206 m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) 207 { 208 throw SAXException(); 209 } 210 211 // start with mappings in effect for last level 212 NSMap aNSMap; 213 if (!m_aNSStack.empty()) 214 aNSMap = NSMap(m_aNSStack.top()); 215 216 // handle xmlns: attributes and add to mappings 217 OUString attr_qname; 218 OUString attr_value; 219 OUString newprefix; 220 AttrMap aAttrMap; 221 sal_Int32 idx=-1; 222 sal_Int16 nAttributes = attribs->getLength(); 223 for (sal_Int16 i=0; i<nAttributes; i++) 224 { 225 attr_qname = attribs->getNameByIndex(i); 226 attr_value = attribs->getValueByIndex(i); 227 // new prefix mapping 228 if (attr_qname.indexOf(OUString::createFromAscii("xmlns:")) == 0) 229 { 230 newprefix = attr_qname.copy(attr_qname.indexOf(':')+1); 231 aNSMap.insert(NSMap::value_type(newprefix, attr_value)); 232 } 233 else if (attr_qname == OUString::createFromAscii("xmlns")) 234 { 235 // new default prefix 236 aNSMap.insert(NSMap::value_type(OUString(), attr_value)); 237 } 238 else 239 { 240 aAttrMap.insert(AttrMap::value_type(attr_qname, attr_value)); 241 } 242 } 243 244 // does the element have a prefix? 245 OUString aPrefix; 246 OUString aURI; 247 Reference< XElement > aElement; 248 idx = aName.indexOf(':'); 249 if (idx != -1) 250 { 251 aPrefix = aName.copy(0, idx); 252 } 253 else 254 aPrefix = OUString(); 255 256 NSMap::const_iterator result = aNSMap.find(aPrefix); 257 if ( result != aNSMap.end()) 258 { 259 // found a URI for prefix 260 // qualified name 261 aElement = m_aDocument->createElementNS( result->second, aName); 262 } 263 else 264 { 265 // no URI for prefix 266 aElement = m_aDocument->createElement(aName); 267 } 268 aElement = Reference< XElement > ( 269 m_aNodeStack.top()->appendChild(Reference< XNode >(aElement, UNO_QUERY)), 270 UNO_QUERY); 271 m_aNodeStack.push(Reference< XNode >(aElement, UNO_QUERY)); 272 273 // set non xmlns attributes 274 aPrefix = OUString(); 275 aURI = OUString(); 276 AttrMap::const_iterator a = aAttrMap.begin(); 277 while (a != aAttrMap.end()) 278 { 279 attr_qname = a->first; 280 attr_value = a->second; 281 idx = attr_qname.indexOf(':'); 282 if(idx != -1) 283 { 284 aPrefix = attr_qname.copy(0, idx); 285 } 286 else 287 aPrefix = OUString(); 288 289 result = aNSMap.find(aPrefix); 290 if (result != aNSMap.end()) 291 { 292 // set attribute with namespace 293 aElement->setAttributeNS(result->second, attr_qname, attr_value); 294 } else { 295 // set attribute without namespace 296 aElement->setAttribute(attr_qname, attr_value); 297 } 298 a++; 299 } 300 m_aNSStack.push(aNSMap); 301 } 302 303 void SAL_CALL CSAXDocumentBuilder::endElement(const OUString& aName) 304 throw (RuntimeException, SAXException) 305 { 306 ::osl::MutexGuard g(m_Mutex); 307 308 // pop the current element from the stack 309 if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && 310 m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) 311 throw SAXException(); 312 313 Reference< XNode > aNode(m_aNodeStack.top()); 314 if (aNode->getNodeType() != NodeType_ELEMENT_NODE) 315 throw SAXException(); 316 317 Reference< XElement > aElement(aNode, UNO_QUERY); 318 OUString aRefName; 319 OUString aPrefix = aElement->getPrefix(); 320 if (aPrefix.getLength() > 0) 321 aRefName = aPrefix + OUString::createFromAscii(":") + aElement->getTagName(); 322 else 323 aRefName = aElement->getTagName(); 324 if (aRefName != aName) // consistency check 325 throw SAXException(); 326 327 // pop it 328 m_aNodeStack.pop(); 329 m_aNSStack.pop(); 330 } 331 332 void SAL_CALL CSAXDocumentBuilder::characters(const OUString& aChars) 333 throw (RuntimeException, SAXException) 334 { 335 ::osl::MutexGuard g(m_Mutex); 336 337 // append text node to the current top element 338 if (m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && 339 m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) 340 throw SAXException(); 341 342 Reference< XText > aText = m_aDocument->createTextNode(aChars); 343 m_aNodeStack.top()->appendChild(Reference< XNode >(aText, UNO_QUERY)); 344 } 345 346 void SAL_CALL CSAXDocumentBuilder::ignorableWhitespace(const OUString& ) 347 throw (RuntimeException, SAXException) 348 { 349 ::osl::MutexGuard g(m_Mutex); 350 351 // ignore ignorable whitespace 352 if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && 353 m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) 354 throw SAXException(); 355 } 356 357 void SAL_CALL CSAXDocumentBuilder::processingInstruction(const OUString& aTarget, const OUString& aData) 358 throw (RuntimeException, SAXException) 359 { 360 ::osl::MutexGuard g(m_Mutex); 361 362 // append PI node to the current top 363 if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && 364 m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) 365 throw SAXException(); 366 367 Reference< XProcessingInstruction > aInstruction = m_aDocument->createProcessingInstruction( 368 aTarget, aData); 369 m_aNodeStack.top()->appendChild(Reference< XNode >(aInstruction, UNO_QUERY)); 370 } 371 372 void SAL_CALL CSAXDocumentBuilder::setDocumentLocator(const Reference< XLocator >& aLocator) 373 throw (RuntimeException, SAXException) 374 { 375 ::osl::MutexGuard g(m_Mutex); 376 377 // set the document locator... 378 m_aLocator = aLocator; 379 } 380 } 381