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>
31 Reference
< XInterface
> CSAXDocumentBuilder::_getInstance(const Reference
< XMultiServiceFactory
>& rSMgr
)
33 return static_cast< XSAXDocumentBuilder
* >(new CSAXDocumentBuilder(rSMgr
));
36 const char* CSAXDocumentBuilder::aImplementationName
= "com.sun.star.comp.xml.dom.SAXDocumentBuilder";
37 const char* CSAXDocumentBuilder::aSupportedServiceNames
[] = {
38 "com.sun.star.xml.dom.SAXDocumentBuilder",
42 CSAXDocumentBuilder::CSAXDocumentBuilder(const Reference
< XMultiServiceFactory
>& mgr
)
43 : m_aServiceManager(mgr
)
44 , m_aState( SAXDocumentBuilderState_READY
)
47 OUString
CSAXDocumentBuilder::_getImplementationName()
49 return OUString::createFromAscii(aImplementationName
);
51 Sequence
<OUString
> CSAXDocumentBuilder::_getSupportedServiceNames()
53 Sequence
<OUString
> aSequence
;
54 for (int i
=0; aSupportedServiceNames
[i
]!=NULL
; i
++) {
55 aSequence
.realloc(i
+1);
56 aSequence
[i
]=(OUString::createFromAscii(aSupportedServiceNames
[i
]));
61 Sequence
< OUString
> SAL_CALL
CSAXDocumentBuilder::getSupportedServiceNames()
62 throw (RuntimeException
)
64 return CSAXDocumentBuilder::_getSupportedServiceNames();
67 OUString SAL_CALL
CSAXDocumentBuilder::getImplementationName()
68 throw (RuntimeException
)
70 return CSAXDocumentBuilder::_getImplementationName();
73 sal_Bool SAL_CALL
CSAXDocumentBuilder::supportsService(const OUString
& aServiceName
)
74 throw (RuntimeException
)
76 Sequence
< OUString
> supported
= CSAXDocumentBuilder::_getSupportedServiceNames();
77 for (sal_Int32 i
=0; i
<supported
.getLength(); i
++)
79 if (supported
[i
] == aServiceName
) return sal_True
;
85 SAXDocumentBuilderState SAL_CALL
CSAXDocumentBuilder::getState()
86 throw (RuntimeException
)
88 ::osl::MutexGuard
g(m_Mutex
);
93 void SAL_CALL
CSAXDocumentBuilder::reset()
94 throw (RuntimeException
)
96 ::osl::MutexGuard
g(m_Mutex
);
98 m_aDocument
= Reference
< XDocument
>();
99 m_aFragment
= Reference
< XDocumentFragment
>();
100 while (!m_aNodeStack
.empty()) m_aNodeStack
.pop();
101 while (!m_aNSStack
.empty()) m_aNSStack
.pop();
102 m_aState
= SAXDocumentBuilderState_READY
;
105 Reference
< XDocument
> SAL_CALL
CSAXDocumentBuilder::getDocument()
106 throw (RuntimeException
)
108 ::osl::MutexGuard
g(m_Mutex
);
110 if (m_aState
!= SAXDocumentBuilderState_DOCUMENT_FINISHED
)
111 throw RuntimeException();
116 Reference
< XDocumentFragment
> SAL_CALL
CSAXDocumentBuilder::getDocumentFragment()
117 throw (RuntimeException
)
119 ::osl::MutexGuard
g(m_Mutex
);
121 if (m_aState
!= SAXDocumentBuilderState_FRAGMENT_FINISHED
)
122 throw RuntimeException();
126 void SAL_CALL
CSAXDocumentBuilder::startDocumentFragment(const Reference
< XDocument
>& ownerDoc
)
127 throw (RuntimeException
)
129 ::osl::MutexGuard
g(m_Mutex
);
131 // start a new document fragment and push it onto the stack
132 // we have to be in a clean state to do this
133 if (!m_aState
== SAXDocumentBuilderState_READY
)
134 throw RuntimeException();
136 m_aDocument
= ownerDoc
;
137 Reference
< XDocumentFragment
> aFragment
= m_aDocument
->createDocumentFragment();
138 m_aNodeStack
.push(Reference
< XNode
>(aFragment
, UNO_QUERY
));
139 m_aFragment
= aFragment
;
140 m_aState
= SAXDocumentBuilderState_BUILDING_FRAGMENT
;
143 void SAL_CALL
CSAXDocumentBuilder::endDocumentFragment()
144 throw (RuntimeException
)
146 ::osl::MutexGuard
g(m_Mutex
);
148 // there should only be the document left on the node stack
149 if (m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
150 throw RuntimeException();
152 Reference
< XNode
> aNode
= m_aNodeStack
.top();
153 if ( aNode
->getNodeType() != NodeType_DOCUMENT_FRAGMENT_NODE
)
154 throw RuntimeException();
156 m_aState
= SAXDocumentBuilderState_FRAGMENT_FINISHED
;
161 void SAL_CALL
CSAXDocumentBuilder::startDocument() throw (RuntimeException
, SAXException
)
163 ::osl::MutexGuard
g(m_Mutex
);
165 // start a new document and push it onto the stack
166 // we have to be in a clean state to do this
167 if (!m_aState
== SAXDocumentBuilderState_READY
)
168 throw SAXException();
170 Reference
< XDocumentBuilder
> aBuilder(DocumentBuilder::create(comphelper::getComponentContext(m_aServiceManager
)));
171 Reference
< XDocument
> aDocument
= aBuilder
->newDocument();
172 m_aNodeStack
.push(Reference
< XNode
>(aDocument
, UNO_QUERY
));
173 m_aDocument
= aDocument
;
174 m_aState
= SAXDocumentBuilderState_BUILDING_DOCUMENT
;
177 void SAL_CALL
CSAXDocumentBuilder::endDocument() throw (RuntimeException
, SAXException
)
179 ::osl::MutexGuard
g(m_Mutex
);
181 // there should only be the document left on the node stack
182 if (!m_aState
== SAXDocumentBuilderState_BUILDING_DOCUMENT
)
183 throw SAXException();
185 Reference
< XNode
> aNode
= m_aNodeStack
.top();
186 if ( aNode
->getNodeType() != NodeType_DOCUMENT_NODE
)
187 throw SAXException();
189 m_aState
= SAXDocumentBuilderState_DOCUMENT_FINISHED
;
192 void SAL_CALL
CSAXDocumentBuilder::startElement(const OUString
& aName
, const Reference
< XAttributeList
>& attribs
)
193 throw (RuntimeException
, SAXException
)
195 ::osl::MutexGuard
g(m_Mutex
);
197 if ( m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
&&
198 m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
200 throw SAXException();
203 // start with mappings in effect for last level
205 if (!m_aNSStack
.empty())
206 aNSMap
= NSMap(m_aNSStack
.top());
208 // handle xmlns: attributes and add to mappings
214 sal_Int16 nAttributes
= attribs
->getLength();
215 for (sal_Int16 i
=0; i
<nAttributes
; i
++)
217 attr_qname
= attribs
->getNameByIndex(i
);
218 attr_value
= attribs
->getValueByIndex(i
);
219 // new prefix mapping
220 if (attr_qname
.indexOf("xmlns:") == 0)
222 newprefix
= attr_qname
.copy(attr_qname
.indexOf(':')+1);
223 aNSMap
.insert(NSMap::value_type(newprefix
, attr_value
));
225 else if ( attr_qname
== "xmlns" )
227 // new default prefix
228 aNSMap
.insert(NSMap::value_type(OUString(), attr_value
));
232 aAttrMap
.insert(AttrMap::value_type(attr_qname
, attr_value
));
236 // does the element have a prefix?
239 Reference
< XElement
> aElement
;
240 idx
= aName
.indexOf(':');
243 aPrefix
= aName
.copy(0, idx
);
246 aPrefix
= OUString();
248 NSMap::const_iterator result
= aNSMap
.find(aPrefix
);
249 if ( result
!= aNSMap
.end())
251 // found a URI for prefix
253 aElement
= m_aDocument
->createElementNS( result
->second
, aName
);
258 aElement
= m_aDocument
->createElement(aName
);
260 aElement
= Reference
< XElement
> (
261 m_aNodeStack
.top()->appendChild(Reference
< XNode
>(aElement
, UNO_QUERY
)),
263 m_aNodeStack
.push(Reference
< XNode
>(aElement
, UNO_QUERY
));
265 // set non xmlns attributes
266 aPrefix
= OUString();
268 AttrMap::const_iterator a
= aAttrMap
.begin();
269 while (a
!= aAttrMap
.end())
271 attr_qname
= a
->first
;
272 attr_value
= a
->second
;
273 idx
= attr_qname
.indexOf(':');
275 aPrefix
= attr_qname
.copy(0, idx
);
277 aPrefix
= OUString();
279 result
= aNSMap
.find(aPrefix
);
280 if (result
!= aNSMap
.end())
282 // set attribute with namespace
283 aElement
->setAttributeNS(result
->second
, attr_qname
, attr_value
);
287 // set attribute without namespace
288 aElement
->setAttribute(attr_qname
, attr_value
);
292 m_aNSStack
.push(aNSMap
);
295 void SAL_CALL
CSAXDocumentBuilder::endElement(const OUString
& aName
)
296 throw (RuntimeException
, SAXException
)
298 ::osl::MutexGuard
g(m_Mutex
);
300 // pop the current element from the stack
301 if ( m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
&&
302 m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
303 throw SAXException();
305 Reference
< XNode
> aNode(m_aNodeStack
.top());
306 if (aNode
->getNodeType() != NodeType_ELEMENT_NODE
)
307 throw SAXException();
309 Reference
< XElement
> aElement(aNode
, UNO_QUERY
);
311 OUString aPrefix
= aElement
->getPrefix();
312 if (!aPrefix
.isEmpty())
313 aRefName
= aPrefix
+ ":" + aElement
->getTagName();
315 aRefName
= aElement
->getTagName();
316 if (aRefName
!= aName
) // consistency check
317 throw SAXException();
324 void SAL_CALL
CSAXDocumentBuilder::characters(const OUString
& aChars
)
325 throw (RuntimeException
, SAXException
)
327 ::osl::MutexGuard
g(m_Mutex
);
329 // append text node to the current top element
330 if (m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
&&
331 m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
332 throw SAXException();
334 Reference
< XText
> aText
= m_aDocument
->createTextNode(aChars
);
335 m_aNodeStack
.top()->appendChild(Reference
< XNode
>(aText
, UNO_QUERY
));
338 void SAL_CALL
CSAXDocumentBuilder::ignorableWhitespace(const OUString
& )
339 throw (RuntimeException
, SAXException
)
341 ::osl::MutexGuard
g(m_Mutex
);
343 // ignore ignorable whitespace
344 if ( m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
&&
345 m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
346 throw SAXException();
349 void SAL_CALL
CSAXDocumentBuilder::processingInstruction(const OUString
& aTarget
, const OUString
& aData
)
350 throw (RuntimeException
, SAXException
)
352 ::osl::MutexGuard
g(m_Mutex
);
354 // append PI node to the current top
355 if ( m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
&&
356 m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
357 throw SAXException();
359 Reference
< XProcessingInstruction
> aInstruction
= m_aDocument
->createProcessingInstruction(
361 m_aNodeStack
.top()->appendChild(Reference
< XNode
>(aInstruction
, UNO_QUERY
));
364 void SAL_CALL
CSAXDocumentBuilder::setDocumentLocator(const Reference
< XLocator
>& aLocator
)
365 throw (RuntimeException
, SAXException
)
367 ::osl::MutexGuard
g(m_Mutex
);
369 // set the document locator...
370 m_aLocator
= aLocator
;
374 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */