1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: saxbuilder.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
30 #if defined(_MSC_VER) && (_MSC_VER > 1310)
31 #pragma warning(disable : 4701)
35 #include "saxbuilder.hxx"
36 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
37 #include <libxml/tree.h>
38 #include <com/sun/star/uno/Sequence.h>
42 Reference
< XInterface
> CSAXDocumentBuilder::_getInstance(const Reference
< XMultiServiceFactory
>& rSMgr
)
44 return static_cast< XSAXDocumentBuilder
* >(new CSAXDocumentBuilder(rSMgr
));
47 const char* CSAXDocumentBuilder::aImplementationName
= "com.sun.star.comp.xml.dom.SAXDocumentBuilder";
48 const char* CSAXDocumentBuilder::aSupportedServiceNames
[] = {
49 "com.sun.star.xml.dom.SAXDocumentBuilder",
53 CSAXDocumentBuilder::CSAXDocumentBuilder(const Reference
< XMultiServiceFactory
>& mgr
)
54 : m_aServiceManager(mgr
)
55 , m_aState( SAXDocumentBuilderState_READY
)
58 OUString
CSAXDocumentBuilder::_getImplementationName()
60 return OUString::createFromAscii(aImplementationName
);
62 Sequence
<OUString
> CSAXDocumentBuilder::_getSupportedServiceNames()
64 Sequence
<OUString
> aSequence
;
65 for (int i
=0; aSupportedServiceNames
[i
]!=NULL
; i
++) {
66 aSequence
.realloc(i
+1);
67 aSequence
[i
]=(OUString::createFromAscii(aSupportedServiceNames
[i
]));
72 Sequence
< OUString
> SAL_CALL
CSAXDocumentBuilder::getSupportedServiceNames()
73 throw (RuntimeException
)
75 return CSAXDocumentBuilder::_getSupportedServiceNames();
78 OUString SAL_CALL
CSAXDocumentBuilder::getImplementationName()
79 throw (RuntimeException
)
81 return CSAXDocumentBuilder::_getImplementationName();
84 sal_Bool SAL_CALL
CSAXDocumentBuilder::supportsService(const OUString
& aServiceName
)
85 throw (RuntimeException
)
87 Sequence
< OUString
> supported
= CSAXDocumentBuilder::_getSupportedServiceNames();
88 for (sal_Int32 i
=0; i
<supported
.getLength(); i
++)
90 if (supported
[i
] == aServiceName
) return sal_True
;
96 SAXDocumentBuilderState SAL_CALL
CSAXDocumentBuilder::getState()
97 throw (RuntimeException
)
102 void SAL_CALL
CSAXDocumentBuilder::reset()
103 throw (RuntimeException
)
105 m_aDocument
= Reference
< XDocument
>();
106 m_aFragment
= Reference
< XDocumentFragment
>();
107 while (!m_aNodeStack
.empty()) m_aNodeStack
.pop();
108 while (!m_aNSStack
.empty()) m_aNSStack
.pop();
109 m_aState
= SAXDocumentBuilderState_READY
;
112 Reference
< XDocument
> SAL_CALL
CSAXDocumentBuilder::getDocument()
113 throw (RuntimeException
)
115 if (m_aState
!= SAXDocumentBuilderState_DOCUMENT_FINISHED
)
116 throw RuntimeException();
121 Reference
< XDocumentFragment
> SAL_CALL
CSAXDocumentBuilder::getDocumentFragment()
122 throw (RuntimeException
)
124 if (m_aState
!= SAXDocumentBuilderState_FRAGMENT_FINISHED
)
125 throw RuntimeException();
129 void SAL_CALL
CSAXDocumentBuilder::startDocumentFragment(const Reference
< XDocument
>& ownerDoc
)
130 throw (RuntimeException
)
132 // start a new document fragment and push it onto the stack
133 // we have to be in a clean state to do this
134 if (!m_aState
== SAXDocumentBuilderState_READY
)
135 throw RuntimeException();
137 m_aDocument
= ownerDoc
;
138 Reference
< XDocumentFragment
> aFragment
= m_aDocument
->createDocumentFragment();
139 m_aNodeStack
.push(Reference
< XNode
>(aFragment
, UNO_QUERY
));
140 m_aFragment
= aFragment
;
141 m_aState
= SAXDocumentBuilderState_BUILDING_FRAGMENT
;
144 void SAL_CALL
CSAXDocumentBuilder::endDocumentFragment()
145 throw (RuntimeException
)
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
)
163 // start a new document and push it onto the stack
164 // we have to be in a clean state to do this
165 if (!m_aState
== SAXDocumentBuilderState_READY
)
166 throw SAXException();
168 Reference
< XDocumentBuilder
> aBuilder(m_aServiceManager
->createInstance(
169 OUString::createFromAscii("com.sun.star.xml.dom.DocumentBuilder")), UNO_QUERY_THROW
);
170 Reference
< XDocument
> aDocument
= aBuilder
->newDocument();
171 m_aNodeStack
.push(Reference
< XNode
>(aDocument
, UNO_QUERY
));
172 m_aDocument
= aDocument
;
173 m_aState
= SAXDocumentBuilderState_BUILDING_DOCUMENT
;
176 void SAL_CALL
CSAXDocumentBuilder::endDocument() throw (RuntimeException
, SAXException
)
178 // there should only be the document left on the node stack
179 if (!m_aState
== SAXDocumentBuilderState_BUILDING_DOCUMENT
)
180 throw SAXException();
182 Reference
< XNode
> aNode
= m_aNodeStack
.top();
183 if ( aNode
->getNodeType() != NodeType_DOCUMENT_NODE
)
184 throw SAXException();
186 m_aState
= SAXDocumentBuilderState_DOCUMENT_FINISHED
;
189 void SAL_CALL
CSAXDocumentBuilder::startElement(const OUString
& aName
, const Reference
< XAttributeList
>& attribs
)
190 throw (RuntimeException
, SAXException
)
192 if ( m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
&&
193 m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
195 throw SAXException();
198 // start with mappings in effect for last level
200 if (!m_aNSStack
.empty())
201 aNSMap
= NSMap(m_aNSStack
.top());
203 // handle xmlns: attributes and add to mappings
209 sal_Int16 nAttributes
= attribs
->getLength();
210 for (sal_Int16 i
=0; i
<nAttributes
; i
++)
212 attr_qname
= attribs
->getNameByIndex(i
);
213 attr_value
= attribs
->getValueByIndex(i
);
214 // new prefix mapping
215 if (attr_qname
.indexOf(OUString::createFromAscii("xmlns:")) == 0)
217 newprefix
= attr_qname
.copy(attr_qname
.indexOf(':')+1);
218 aNSMap
.insert(NSMap::value_type(newprefix
, attr_value
));
220 else if (attr_qname
== OUString::createFromAscii("xmlns"))
222 // new default prefix
223 aNSMap
.insert(NSMap::value_type(OUString(), attr_value
));
227 aAttrMap
.insert(AttrMap::value_type(attr_qname
, attr_value
));
231 // does the element have a prefix?
234 Reference
< XElement
> aElement
;
235 idx
= aName
.indexOf(':');
238 aPrefix
= aName
.copy(0, idx
);
241 aPrefix
= OUString();
243 NSMap::const_iterator result
= aNSMap
.find(aPrefix
);
244 if ( result
!= aNSMap
.end())
246 // found a URI for prefix
247 aElement
= m_aDocument
->createElementNS( result
->second
, aName
); // qualified name
252 aElement
= m_aDocument
->createElement(aName
);
254 aElement
= Reference
< XElement
> (
255 m_aNodeStack
.top()->appendChild(Reference
< XNode
>(aElement
, UNO_QUERY
)),
257 m_aNodeStack
.push(Reference
< XNode
>(aElement
, UNO_QUERY
));
259 // set non xmlns attributes
260 aPrefix
= OUString();
262 AttrMap::const_iterator a
= aAttrMap
.begin();
263 while (a
!= aAttrMap
.end())
265 attr_qname
= a
->first
;
266 attr_value
= a
->second
;
267 idx
= attr_qname
.indexOf(':');
270 aPrefix
= attr_qname
.copy(0, idx
);
273 aPrefix
= OUString();
275 result
= aNSMap
.find(aPrefix
);
276 if (result
!= aNSMap
.end())
278 // set attribute with namespace
279 aElement
->setAttributeNS(result
->second
, attr_qname
, attr_value
);
281 // set attribute without namespace
282 aElement
->setAttribute(attr_qname
, attr_value
);
286 m_aNSStack
.push(aNSMap
);
289 void SAL_CALL
CSAXDocumentBuilder::endElement(const OUString
& aName
)
290 throw (RuntimeException
, SAXException
)
292 // pop the current element from the stack
293 if ( m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
&&
294 m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
295 throw SAXException();
297 Reference
< XNode
> aNode(m_aNodeStack
.top());
298 if (aNode
->getNodeType() != NodeType_ELEMENT_NODE
)
299 throw SAXException();
301 Reference
< XElement
> aElement(aNode
, UNO_QUERY
);
303 OUString aPrefix
= aElement
->getPrefix();
304 if (aPrefix
.getLength() > 0)
305 aRefName
= aPrefix
+ OUString::createFromAscii(":") + aElement
->getTagName();
307 aRefName
= aElement
->getTagName();
308 if (aRefName
!= aName
) // consistency check
309 throw SAXException();
316 void SAL_CALL
CSAXDocumentBuilder::characters(const OUString
& aChars
)
317 throw (RuntimeException
, SAXException
)
319 // append text node to the current top element
320 if (m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
&&
321 m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
322 throw SAXException();
324 Reference
< XText
> aText
= m_aDocument
->createTextNode(aChars
);
325 m_aNodeStack
.top()->appendChild(Reference
< XNode
>(aText
, UNO_QUERY
));
328 void SAL_CALL
CSAXDocumentBuilder::ignorableWhitespace(const OUString
& )
329 throw (RuntimeException
, SAXException
)
331 // ignore ignorable whitespace
332 if ( m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
&&
333 m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
334 throw SAXException();
337 void SAL_CALL
CSAXDocumentBuilder::processingInstruction(const OUString
& aTarget
, const OUString
& aData
)
338 throw (RuntimeException
, SAXException
)
340 // append PI node to the current top
341 if ( m_aState
!= SAXDocumentBuilderState_BUILDING_DOCUMENT
&&
342 m_aState
!= SAXDocumentBuilderState_BUILDING_FRAGMENT
)
343 throw SAXException();
345 Reference
< XProcessingInstruction
> aInstruction
= m_aDocument
->createProcessingInstruction(
347 m_aNodeStack
.top()->appendChild(Reference
< XNode
>(aInstruction
, UNO_QUERY
));
350 void SAL_CALL
CSAXDocumentBuilder::setDocumentLocator(const Reference
< XLocator
>& aLocator
)
351 throw (RuntimeException
, SAXException
)
353 // set the document locator...
354 m_aLocator
= aLocator
;