/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #if defined(_MSC_VER) && (_MSC_VER > 1310) #pragma warning(disable : 4701) #endif #include "saxbuilder.hxx" #include namespace DOM { Reference< XInterface > CSAXDocumentBuilder::_getInstance(const Reference< XMultiServiceFactory >& rSMgr) { return static_cast< XSAXDocumentBuilder* >(new CSAXDocumentBuilder(rSMgr)); } const char* CSAXDocumentBuilder::aImplementationName = "com.sun.star.comp.xml.dom.SAXDocumentBuilder"; const char* CSAXDocumentBuilder::aSupportedServiceNames[] = { "com.sun.star.xml.dom.SAXDocumentBuilder", NULL }; CSAXDocumentBuilder::CSAXDocumentBuilder(const Reference< XMultiServiceFactory >& mgr) : m_aServiceManager(mgr) , m_aState( SAXDocumentBuilderState_READY) {} OUString CSAXDocumentBuilder::_getImplementationName() { return OUString::createFromAscii(aImplementationName); } Sequence CSAXDocumentBuilder::_getSupportedServiceNames() { Sequence aSequence; for (int i=0; aSupportedServiceNames[i]!=NULL; i++) { aSequence.realloc(i+1); aSequence[i]=(OUString::createFromAscii(aSupportedServiceNames[i])); } return aSequence; } Sequence< OUString > SAL_CALL CSAXDocumentBuilder::getSupportedServiceNames() throw (RuntimeException) { return CSAXDocumentBuilder::_getSupportedServiceNames(); } OUString SAL_CALL CSAXDocumentBuilder::getImplementationName() throw (RuntimeException) { return CSAXDocumentBuilder::_getImplementationName(); } sal_Bool SAL_CALL CSAXDocumentBuilder::supportsService(const OUString& aServiceName) throw (RuntimeException) { Sequence< OUString > supported = CSAXDocumentBuilder::_getSupportedServiceNames(); for (sal_Int32 i=0; i(); m_aFragment = Reference< XDocumentFragment >(); while (!m_aNodeStack.empty()) m_aNodeStack.pop(); while (!m_aNSStack.empty()) m_aNSStack.pop(); m_aState = SAXDocumentBuilderState_READY; } Reference< XDocument > SAL_CALL CSAXDocumentBuilder::getDocument() throw (RuntimeException) { ::osl::MutexGuard g(m_Mutex); if (m_aState != SAXDocumentBuilderState_DOCUMENT_FINISHED) throw RuntimeException(); return m_aDocument; } Reference< XDocumentFragment > SAL_CALL CSAXDocumentBuilder::getDocumentFragment() throw (RuntimeException) { ::osl::MutexGuard g(m_Mutex); if (m_aState != SAXDocumentBuilderState_FRAGMENT_FINISHED) throw RuntimeException(); return m_aFragment; } void SAL_CALL CSAXDocumentBuilder::startDocumentFragment(const Reference< XDocument >& ownerDoc) throw (RuntimeException) { ::osl::MutexGuard g(m_Mutex); // start a new document fragment and push it onto the stack // we have to be in a clean state to do this if (!m_aState == SAXDocumentBuilderState_READY) throw RuntimeException(); m_aDocument = ownerDoc; Reference< XDocumentFragment > aFragment = m_aDocument->createDocumentFragment(); m_aNodeStack.push(Reference< XNode >(aFragment, UNO_QUERY)); m_aFragment = aFragment; m_aState = SAXDocumentBuilderState_BUILDING_FRAGMENT; } void SAL_CALL CSAXDocumentBuilder::endDocumentFragment() throw (RuntimeException) { ::osl::MutexGuard g(m_Mutex); // there should only be the document left on the node stack if (m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) throw RuntimeException(); Reference< XNode > aNode = m_aNodeStack.top(); if ( aNode->getNodeType() != NodeType_DOCUMENT_FRAGMENT_NODE) throw RuntimeException(); m_aNodeStack.pop(); m_aState = SAXDocumentBuilderState_FRAGMENT_FINISHED; } // document handler void SAL_CALL CSAXDocumentBuilder::startDocument() throw (RuntimeException, SAXException) { ::osl::MutexGuard g(m_Mutex); // start a new document and push it onto the stack // we have to be in a clean state to do this if (!m_aState == SAXDocumentBuilderState_READY) throw SAXException(); Reference< XDocumentBuilder > aBuilder(m_aServiceManager->createInstance( OUString::createFromAscii("com.sun.star.xml.dom.DocumentBuilder")), UNO_QUERY_THROW); Reference< XDocument > aDocument = aBuilder->newDocument(); m_aNodeStack.push(Reference< XNode >(aDocument, UNO_QUERY)); m_aDocument = aDocument; m_aState = SAXDocumentBuilderState_BUILDING_DOCUMENT; } void SAL_CALL CSAXDocumentBuilder::endDocument() throw (RuntimeException, SAXException) { ::osl::MutexGuard g(m_Mutex); // there should only be the document left on the node stack if (!m_aState == SAXDocumentBuilderState_BUILDING_DOCUMENT) throw SAXException(); Reference< XNode > aNode = m_aNodeStack.top(); if ( aNode->getNodeType() != NodeType_DOCUMENT_NODE) throw SAXException(); m_aNodeStack.pop(); m_aState = SAXDocumentBuilderState_DOCUMENT_FINISHED; } void SAL_CALL CSAXDocumentBuilder::startElement(const OUString& aName, const Reference< XAttributeList>& attribs) throw (RuntimeException, SAXException) { ::osl::MutexGuard g(m_Mutex); if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) { throw SAXException(); } // start with mappings in effect for last level NSMap aNSMap; if (!m_aNSStack.empty()) aNSMap = NSMap(m_aNSStack.top()); // handle xmlns: attributes and add to mappings OUString attr_qname; OUString attr_value; OUString newprefix; AttrMap aAttrMap; sal_Int32 idx=-1; sal_Int16 nAttributes = attribs->getLength(); for (sal_Int16 i=0; igetNameByIndex(i); attr_value = attribs->getValueByIndex(i); // new prefix mapping if (attr_qname.indexOf(OUString::createFromAscii("xmlns:")) == 0) { newprefix = attr_qname.copy(attr_qname.indexOf(':')+1); aNSMap.insert(NSMap::value_type(newprefix, attr_value)); } else if (attr_qname == OUString::createFromAscii("xmlns")) { // new default prefix aNSMap.insert(NSMap::value_type(OUString(), attr_value)); } else { aAttrMap.insert(AttrMap::value_type(attr_qname, attr_value)); } } // does the element have a prefix? OUString aPrefix; OUString aURI; Reference< XElement > aElement; idx = aName.indexOf(':'); if (idx != -1) { aPrefix = aName.copy(0, idx); } else aPrefix = OUString(); NSMap::const_iterator result = aNSMap.find(aPrefix); if ( result != aNSMap.end()) { // found a URI for prefix // qualified name aElement = m_aDocument->createElementNS( result->second, aName); } else { // no URI for prefix aElement = m_aDocument->createElement(aName); } aElement = Reference< XElement > ( m_aNodeStack.top()->appendChild(Reference< XNode >(aElement, UNO_QUERY)), UNO_QUERY); m_aNodeStack.push(Reference< XNode >(aElement, UNO_QUERY)); // set non xmlns attributes aPrefix = OUString(); aURI = OUString(); AttrMap::const_iterator a = aAttrMap.begin(); while (a != aAttrMap.end()) { attr_qname = a->first; attr_value = a->second; idx = attr_qname.indexOf(':'); if(idx != -1) { aPrefix = attr_qname.copy(0, idx); } else aPrefix = OUString(); result = aNSMap.find(aPrefix); if (result != aNSMap.end()) { // set attribute with namespace aElement->setAttributeNS(result->second, attr_qname, attr_value); } else { // set attribute without namespace aElement->setAttribute(attr_qname, attr_value); } a++; } m_aNSStack.push(aNSMap); } void SAL_CALL CSAXDocumentBuilder::endElement(const OUString& aName) throw (RuntimeException, SAXException) { ::osl::MutexGuard g(m_Mutex); // pop the current element from the stack if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) throw SAXException(); Reference< XNode > aNode(m_aNodeStack.top()); if (aNode->getNodeType() != NodeType_ELEMENT_NODE) throw SAXException(); Reference< XElement > aElement(aNode, UNO_QUERY); OUString aRefName; OUString aPrefix = aElement->getPrefix(); if (aPrefix.getLength() > 0) aRefName = aPrefix + OUString::createFromAscii(":") + aElement->getTagName(); else aRefName = aElement->getTagName(); if (aRefName != aName) // consistency check throw SAXException(); // pop it m_aNodeStack.pop(); m_aNSStack.pop(); } void SAL_CALL CSAXDocumentBuilder::characters(const OUString& aChars) throw (RuntimeException, SAXException) { ::osl::MutexGuard g(m_Mutex); // append text node to the current top element if (m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) throw SAXException(); Reference< XText > aText = m_aDocument->createTextNode(aChars); m_aNodeStack.top()->appendChild(Reference< XNode >(aText, UNO_QUERY)); } void SAL_CALL CSAXDocumentBuilder::ignorableWhitespace(const OUString& ) throw (RuntimeException, SAXException) { ::osl::MutexGuard g(m_Mutex); // ignore ignorable whitespace if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) throw SAXException(); } void SAL_CALL CSAXDocumentBuilder::processingInstruction(const OUString& aTarget, const OUString& aData) throw (RuntimeException, SAXException) { ::osl::MutexGuard g(m_Mutex); // append PI node to the current top if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) throw SAXException(); Reference< XProcessingInstruction > aInstruction = m_aDocument->createProcessingInstruction( aTarget, aData); m_aNodeStack.top()->appendChild(Reference< XNode >(aInstruction, UNO_QUERY)); } void SAL_CALL CSAXDocumentBuilder::setDocumentLocator(const Reference< XLocator >& aLocator) throw (RuntimeException, SAXException) { ::osl::MutexGuard g(m_Mutex); // set the document locator... m_aLocator = aLocator; } }