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