blob: 91e204abe5424ada69e750790a7217c2690262a8 [file] [log] [blame]
/**************************************************************
*
* 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 <com/sun/star/xml/dom/XDocumentBuilder.hpp>
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<OUString> CSAXDocumentBuilder::_getSupportedServiceNames()
{
Sequence<OUString> 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<supported.getLength(); i++)
{
if (supported[i] == aServiceName) return sal_True;
}
return sal_False;
}
SAXDocumentBuilderState SAL_CALL CSAXDocumentBuilder::getState()
throw (RuntimeException)
{
::osl::MutexGuard g(m_Mutex);
return m_aState;
}
void SAL_CALL CSAXDocumentBuilder::reset()
throw (RuntimeException)
{
::osl::MutexGuard g(m_Mutex);
m_aDocument = Reference< XDocument >();
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; i<nAttributes; i++)
{
attr_qname = attribs->getNameByIndex(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;
}
}