1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #pragma warning(disable : 4701)
23 #include "saxbuilder.hxx"
25 #include <com/sun/star/xml/dom/DocumentBuilder.hpp>
26 #include <comphelper/processfactory.hxx>
27 #include <cppuhelper/supportsservice.hxx>
29 using namespace css::lang
;
30 using namespace css::uno
;
31 using namespace css::xml::dom
;
32 using namespace css::xml::sax
;
36 Reference
< XInterface
> CSAXDocumentBuilder::_getInstance(const Reference
< XMultiServiceFactory
>& rSMgr
)
38 return static_cast< XSAXDocumentBuilder
* >(new CSAXDocumentBuilder(rSMgr
));
41 const char* CSAXDocumentBuilder::aImplementationName
= "com.sun.star.comp.xml.dom.SAXDocumentBuilder";
42 const char* CSAXDocumentBuilder::aSupportedServiceNames
[] = {
43 "com.sun.star.xml.dom.SAXDocumentBuilder",
47 CSAXDocumentBuilder::CSAXDocumentBuilder(const Reference
< XMultiServiceFactory
>& mgr
)
48 : m_aServiceManager(mgr
)
49 , m_aState( SAXDocumentBuilderState_READY
)
52 OUString
CSAXDocumentBuilder::_getImplementationName()
54 return OUString::createFromAscii(aImplementationName
);
56 Sequence
<OUString
> CSAXDocumentBuilder::_getSupportedServiceNames()
58 Sequence
<OUString
> aSequence
;
59 for (int i
=0; aSupportedServiceNames
[i
]!=nullptr; i
++) {
60 aSequence
.realloc(i
+1);
61 aSequence
[i
]=(OUString::createFromAscii(aSupportedServiceNames
[i
]));
66 Sequence
< OUString
> SAL_CALL
CSAXDocumentBuilder::getSupportedServiceNames()
67 throw (RuntimeException
, std::exception
)
69 return CSAXDocumentBuilder::_getSupportedServiceNames();
72 OUString SAL_CALL
CSAXDocumentBuilder::getImplementationName()
73 throw (RuntimeException
, std::exception
)
75 return CSAXDocumentBuilder::_getImplementationName();
78 sal_Bool SAL_CALL
CSAXDocumentBuilder::supportsService(const OUString
& aServiceName
)
79 throw (RuntimeException
, std::exception
)
81 return cppu::supportsService(this, aServiceName
);
84 SAXDocumentBuilderState SAL_CALL
CSAXDocumentBuilder::getState()
85 throw (RuntimeException
, std::exception
)
87 ::osl::MutexGuard
g(m_Mutex
);
92 void SAL_CALL
CSAXDocumentBuilder::reset()
93 throw (RuntimeException
, std::exception
)
95 ::osl::MutexGuard
g(m_Mutex
);
99 while (!m_aNodeStack
.empty()) m_aNodeStack
.pop();
100 while (!m_aNSStack
.empty()) m_aNSStack
.pop();
101 m_aState
= SAXDocumentBuilderState_READY
;
104 Reference
< XDocument
> SAL_CALL
CSAXDocumentBuilder::getDocument()
105 throw (RuntimeException
, std::exception
)
107 ::osl::MutexGuard
g(m_Mutex
);
109 if (m_aState
!= SAXDocumentBuilderState_DOCUMENT_FINISHED
)
110 throw RuntimeException();
115 Reference
< XDocumentFragment
> SAL_CALL
CSAXDocumentBuilder::getDocumentFragment()
116 throw (RuntimeException
, std::exception
)
118 ::osl::MutexGuard
g(m_Mutex
);
120 if (m_aState
!= SAXDocumentBuilderState_FRAGMENT_FINISHED
)
121 throw RuntimeException();
125 void SAL_CALL
CSAXDocumentBuilder::startDocumentFragment(const Reference
< XDocument
>& ownerDoc
)
126 throw (RuntimeException
, std::exception
)
128 ::osl::MutexGuard
g(m_Mutex
);
130 // start a new document fragment and push it onto the stack
131 // we have to be in a clean state to do this
132 if (m_aState
!= SAXDocumentBuilderState_READY
)
133 throw RuntimeException();
135 m_aDocument
= ownerDoc
;
136 Reference
< XDocumentFragment
> aFragment
= m_aDocument
->createDocumentFragment();
137 m_aNodeStack
.push(aFragment
);
138 m_aFragment
= aFragment
;
139 m_aState
= SAXDocumentBuilderState_BUILDING_FRAGMENT
;
142 void SAL_CALL
CSAXDocumentBuilder::endDocumentFragment()
143 throw (RuntimeException
, std::exception
)
145 ::osl::MutexGuard
g(m_Mutex
);
147 // there should only be the document left on the node stack
148 if (m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
149 throw RuntimeException();
151 Reference
< XNode
> aNode
= m_aNodeStack
.top();
152 if ( aNode
->getNodeType() != NodeType_DOCUMENT_FRAGMENT_NODE
)
153 throw RuntimeException();
155 m_aState
= SAXDocumentBuilderState_FRAGMENT_FINISHED
;
160 void SAL_CALL
CSAXDocumentBuilder::startDocument() throw (RuntimeException
, SAXException
, std::exception
)
162 ::osl::MutexGuard
g(m_Mutex
);
164 // start a new document and push it onto the stack
165 // we have to be in a clean state to do this
166 if (m_aState
!= SAXDocumentBuilderState_READY
)
167 throw SAXException();
169 Reference
< XDocumentBuilder
> aBuilder(DocumentBuilder::create(comphelper::getComponentContext(m_aServiceManager
)));
170 Reference
< XDocument
> aDocument
= aBuilder
->newDocument();
171 m_aNodeStack
.push(aDocument
);
172 m_aDocument
= aDocument
;
173 m_aState
= SAXDocumentBuilderState_BUILDING_DOCUMENT
;
176 void SAL_CALL
CSAXDocumentBuilder::endDocument() throw (RuntimeException
, SAXException
, std::exception
)
178 ::osl::MutexGuard
g(m_Mutex
);
180 // there should only be the document left on the node stack
181 if (m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
)
182 throw SAXException();
184 Reference
< XNode
> aNode
= m_aNodeStack
.top();
185 if ( aNode
->getNodeType() != NodeType_DOCUMENT_NODE
)
186 throw SAXException();
188 m_aState
= SAXDocumentBuilderState_DOCUMENT_FINISHED
;
191 void SAL_CALL
CSAXDocumentBuilder::startElement(const OUString
& aName
, const Reference
< XAttributeList
>& attribs
)
192 throw (RuntimeException
, SAXException
, std::exception
)
194 ::osl::MutexGuard
g(m_Mutex
);
196 if ( m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
&&
197 m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
199 throw SAXException();
202 // start with mappings in effect for last level
204 if (!m_aNSStack
.empty())
205 aNSMap
= NSMap(m_aNSStack
.top());
207 // handle xmlns: attributes and add to mappings
213 sal_Int16 nAttributes
= attribs
->getLength();
214 for (sal_Int16 i
=0; i
<nAttributes
; i
++)
216 attr_qname
= attribs
->getNameByIndex(i
);
217 attr_value
= attribs
->getValueByIndex(i
);
218 // new prefix mapping
219 if (attr_qname
.startsWith("xmlns:"))
221 newprefix
= attr_qname
.copy(attr_qname
.indexOf(':')+1);
222 aNSMap
.insert(NSMap::value_type(newprefix
, attr_value
));
224 else if ( attr_qname
== "xmlns" )
226 // new default prefix
227 aNSMap
.insert(NSMap::value_type(OUString(), attr_value
));
231 aAttrMap
.insert(AttrMap::value_type(attr_qname
, attr_value
));
235 // does the element have a prefix?
238 Reference
< XElement
> aElement
;
239 idx
= aName
.indexOf(':');
242 aPrefix
= aName
.copy(0, idx
);
247 NSMap::const_iterator result
= aNSMap
.find(aPrefix
);
248 if ( result
!= aNSMap
.end())
250 // found a URI for prefix
252 aElement
= m_aDocument
->createElementNS( result
->second
, aName
);
257 aElement
= m_aDocument
->createElement(aName
);
259 aElement
.set( m_aNodeStack
.top()->appendChild(aElement
), UNO_QUERY
);
260 m_aNodeStack
.push(aElement
);
262 // set non xmlns attributes
265 AttrMap::const_iterator a
= aAttrMap
.begin();
266 while (a
!= aAttrMap
.end())
268 attr_qname
= a
->first
;
269 attr_value
= a
->second
;
270 idx
= attr_qname
.indexOf(':');
272 aPrefix
= attr_qname
.copy(0, idx
);
276 result
= aNSMap
.find(aPrefix
);
277 if (result
!= aNSMap
.end())
279 // set attribute with namespace
280 aElement
->setAttributeNS(result
->second
, attr_qname
, attr_value
);
284 // set attribute without namespace
285 aElement
->setAttribute(attr_qname
, attr_value
);
289 m_aNSStack
.push(aNSMap
);
292 void SAL_CALL
CSAXDocumentBuilder::endElement(const OUString
& aName
)
293 throw (RuntimeException
, SAXException
, std::exception
)
295 ::osl::MutexGuard
g(m_Mutex
);
297 // pop the current element from the stack
298 if ( m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
&&
299 m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
300 throw SAXException();
302 Reference
< XNode
> aNode(m_aNodeStack
.top());
303 if (aNode
->getNodeType() != NodeType_ELEMENT_NODE
)
304 throw SAXException();
306 Reference
< XElement
> aElement(aNode
, UNO_QUERY
);
308 OUString aPrefix
= aElement
->getPrefix();
309 if (!aPrefix
.isEmpty())
310 aRefName
= aPrefix
+ ":" + aElement
->getTagName();
312 aRefName
= aElement
->getTagName();
313 if (aRefName
!= aName
) // consistency check
314 throw SAXException();
321 void SAL_CALL
CSAXDocumentBuilder::characters(const OUString
& aChars
)
322 throw (RuntimeException
, SAXException
, std::exception
)
324 ::osl::MutexGuard
g(m_Mutex
);
326 // append text node to the current top element
327 if (m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
&&
328 m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
329 throw SAXException();
331 Reference
< XText
> aText
= m_aDocument
->createTextNode(aChars
);
332 m_aNodeStack
.top()->appendChild(aText
);
335 void SAL_CALL
CSAXDocumentBuilder::ignorableWhitespace(const OUString
& )
336 throw (RuntimeException
, SAXException
, std::exception
)
338 ::osl::MutexGuard
g(m_Mutex
);
340 // ignore ignorable whitespace
341 if ( m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
&&
342 m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
343 throw SAXException();
346 void SAL_CALL
CSAXDocumentBuilder::processingInstruction(const OUString
& aTarget
, const OUString
& aData
)
347 throw (RuntimeException
, SAXException
, std::exception
)
349 ::osl::MutexGuard
g(m_Mutex
);
351 // append PI node to the current top
352 if ( m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
&&
353 m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
354 throw SAXException();
356 Reference
< XProcessingInstruction
> aInstruction
= m_aDocument
->createProcessingInstruction(
358 m_aNodeStack
.top()->appendChild(aInstruction
);
361 void SAL_CALL
CSAXDocumentBuilder::setDocumentLocator(const Reference
< XLocator
>& aLocator
)
362 throw (RuntimeException
, SAXException
, std::exception
)
364 ::osl::MutexGuard
g(m_Mutex
);
366 // set the document locator...
367 m_aLocator
= aLocator
;
371 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */