xref: /AOO41X/main/unoxml/source/dom/saxbuilder.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 #if defined(_MSC_VER) && (_MSC_VER > 1310)
28 #pragma warning(disable : 4701)
29 #endif
30 
31 #include "saxbuilder.hxx"
32 
33 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
34 
35 
36 namespace DOM
37 {
38     Reference< XInterface > CSAXDocumentBuilder::_getInstance(const Reference< XMultiServiceFactory >& rSMgr)
39     {
40         return static_cast< XSAXDocumentBuilder* >(new CSAXDocumentBuilder(rSMgr));
41     }
42 
43     const char* CSAXDocumentBuilder::aImplementationName = "com.sun.star.comp.xml.dom.SAXDocumentBuilder";
44     const char* CSAXDocumentBuilder::aSupportedServiceNames[] = {
45         "com.sun.star.xml.dom.SAXDocumentBuilder",
46         NULL
47     };
48 
49     CSAXDocumentBuilder::CSAXDocumentBuilder(const Reference< XMultiServiceFactory >& mgr)
50         : m_aServiceManager(mgr)
51         , m_aState( SAXDocumentBuilderState_READY)
52     {}
53 
54     OUString CSAXDocumentBuilder::_getImplementationName()
55     {
56 	    return OUString::createFromAscii(aImplementationName);
57     }
58     Sequence<OUString> CSAXDocumentBuilder::_getSupportedServiceNames()
59     {
60 	    Sequence<OUString> aSequence;
61 	    for (int i=0; aSupportedServiceNames[i]!=NULL; i++) {
62 		    aSequence.realloc(i+1);
63 		    aSequence[i]=(OUString::createFromAscii(aSupportedServiceNames[i]));
64 	    }
65 	    return aSequence;
66     }
67 
68     Sequence< OUString > SAL_CALL CSAXDocumentBuilder::getSupportedServiceNames()
69         throw (RuntimeException)
70     {
71         return CSAXDocumentBuilder::_getSupportedServiceNames();
72     }
73 
74     OUString SAL_CALL CSAXDocumentBuilder::getImplementationName()
75         throw (RuntimeException)
76     {
77         return CSAXDocumentBuilder::_getImplementationName();
78     }
79 
80     sal_Bool SAL_CALL CSAXDocumentBuilder::supportsService(const OUString& aServiceName)
81         throw (RuntimeException)
82     {
83         Sequence< OUString > supported = CSAXDocumentBuilder::_getSupportedServiceNames();
84         for (sal_Int32 i=0; i<supported.getLength(); i++)
85         {
86             if (supported[i] == aServiceName) return sal_True;
87         }
88         return sal_False;
89     }
90 
91 
92     SAXDocumentBuilderState SAL_CALL CSAXDocumentBuilder::getState()
93         throw (RuntimeException)
94     {
95         ::osl::MutexGuard g(m_Mutex);
96 
97         return m_aState;
98     }
99 
100     void SAL_CALL CSAXDocumentBuilder::reset()
101         throw (RuntimeException)
102     {
103         ::osl::MutexGuard g(m_Mutex);
104 
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;
110     }
111 
112     Reference< XDocument > SAL_CALL CSAXDocumentBuilder::getDocument()
113         throw (RuntimeException)
114     {
115         ::osl::MutexGuard g(m_Mutex);
116 
117         if (m_aState != SAXDocumentBuilderState_DOCUMENT_FINISHED)
118             throw RuntimeException();
119 
120         return m_aDocument;
121     }
122 
123     Reference< XDocumentFragment > SAL_CALL CSAXDocumentBuilder::getDocumentFragment()
124          throw (RuntimeException)
125     {
126         ::osl::MutexGuard g(m_Mutex);
127 
128         if (m_aState != SAXDocumentBuilderState_FRAGMENT_FINISHED)
129             throw RuntimeException();
130         return m_aFragment;
131     }
132 
133     void SAL_CALL CSAXDocumentBuilder::startDocumentFragment(const Reference< XDocument >& ownerDoc)
134         throw (RuntimeException)
135     {
136         ::osl::MutexGuard g(m_Mutex);
137 
138         // start a new document fragment and push it onto the stack
139         // we have to be in a clean state to do this
140         if (!m_aState == SAXDocumentBuilderState_READY)
141             throw RuntimeException();
142 
143         m_aDocument = ownerDoc;
144         Reference< XDocumentFragment > aFragment = m_aDocument->createDocumentFragment();
145         m_aNodeStack.push(Reference< XNode >(aFragment, UNO_QUERY));
146         m_aFragment = aFragment;
147         m_aState = SAXDocumentBuilderState_BUILDING_FRAGMENT;
148     }
149 
150     void SAL_CALL CSAXDocumentBuilder::endDocumentFragment()
151         throw (RuntimeException)
152     {
153         ::osl::MutexGuard g(m_Mutex);
154 
155         // there should only be the document left on the node stack
156         if (m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
157             throw RuntimeException();
158 
159         Reference< XNode > aNode = m_aNodeStack.top();
160         if ( aNode->getNodeType() != NodeType_DOCUMENT_FRAGMENT_NODE)
161             throw RuntimeException();
162         m_aNodeStack.pop();
163         m_aState = SAXDocumentBuilderState_FRAGMENT_FINISHED;
164     }
165 
166     // document handler
167 
168     void SAL_CALL  CSAXDocumentBuilder::startDocument() throw (RuntimeException, SAXException)
169     {
170         ::osl::MutexGuard g(m_Mutex);
171 
172         // start a new document and push it onto the stack
173         // we have to be in a clean state to do this
174         if (!m_aState == SAXDocumentBuilderState_READY)
175             throw SAXException();
176 
177         Reference< XDocumentBuilder > aBuilder(m_aServiceManager->createInstance(
178                 OUString::createFromAscii("com.sun.star.xml.dom.DocumentBuilder")), UNO_QUERY_THROW);
179         Reference< XDocument > aDocument = aBuilder->newDocument();
180         m_aNodeStack.push(Reference< XNode >(aDocument, UNO_QUERY));
181         m_aDocument = aDocument;
182         m_aState = SAXDocumentBuilderState_BUILDING_DOCUMENT;
183     }
184 
185     void SAL_CALL CSAXDocumentBuilder::endDocument() throw (RuntimeException, SAXException)
186     {
187         ::osl::MutexGuard g(m_Mutex);
188 
189         // there should only be the document left on the node stack
190         if (!m_aState == SAXDocumentBuilderState_BUILDING_DOCUMENT)
191             throw SAXException();
192 
193         Reference< XNode > aNode = m_aNodeStack.top();
194         if ( aNode->getNodeType() != NodeType_DOCUMENT_NODE)
195             throw SAXException();
196         m_aNodeStack.pop();
197         m_aState = SAXDocumentBuilderState_DOCUMENT_FINISHED;
198     }
199 
200     void SAL_CALL CSAXDocumentBuilder::startElement(const OUString& aName, const Reference< XAttributeList>& attribs)
201         throw (RuntimeException, SAXException)
202     {
203         ::osl::MutexGuard g(m_Mutex);
204 
205         if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
206              m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
207         {
208             throw SAXException();
209         }
210 
211         // start with mappings in effect for last level
212         NSMap aNSMap;
213         if (!m_aNSStack.empty())
214             aNSMap = NSMap(m_aNSStack.top());
215 
216         // handle xmlns: attributes and add to mappings
217         OUString attr_qname;
218         OUString attr_value;
219         OUString newprefix;
220         AttrMap aAttrMap;
221         sal_Int32 idx=-1;
222         sal_Int16 nAttributes = attribs->getLength();
223         for (sal_Int16 i=0; i<nAttributes; i++)
224         {
225             attr_qname = attribs->getNameByIndex(i);
226             attr_value = attribs->getValueByIndex(i);
227             // new prefix mapping
228             if (attr_qname.indexOf(OUString::createFromAscii("xmlns:")) == 0)
229             {
230                 newprefix = attr_qname.copy(attr_qname.indexOf(':')+1);
231                 aNSMap.insert(NSMap::value_type(newprefix, attr_value));
232             }
233             else if (attr_qname == OUString::createFromAscii("xmlns"))
234             {
235                 // new default prefix
236                 aNSMap.insert(NSMap::value_type(OUString(), attr_value));
237             }
238             else
239             {
240                 aAttrMap.insert(AttrMap::value_type(attr_qname, attr_value));
241             }
242         }
243 
244         // does the element have a prefix?
245         OUString aPrefix;
246         OUString aURI;
247         Reference< XElement > aElement;
248         idx = aName.indexOf(':');
249         if (idx != -1)
250         {
251             aPrefix = aName.copy(0, idx);
252         }
253         else
254             aPrefix = OUString();
255 
256         NSMap::const_iterator result = aNSMap.find(aPrefix);
257         if ( result != aNSMap.end())
258         {
259             // found a URI for prefix
260             // qualified name
261             aElement = m_aDocument->createElementNS( result->second, aName);
262         }
263         else
264         {
265             // no URI for prefix
266             aElement = m_aDocument->createElement(aName);
267         }
268         aElement = Reference< XElement > (
269             m_aNodeStack.top()->appendChild(Reference< XNode >(aElement, UNO_QUERY)),
270             UNO_QUERY);
271         m_aNodeStack.push(Reference< XNode >(aElement, UNO_QUERY));
272 
273         // set non xmlns attributes
274         aPrefix = OUString();
275         aURI = OUString();
276         AttrMap::const_iterator a = aAttrMap.begin();
277         while (a != aAttrMap.end())
278         {
279             attr_qname = a->first;
280             attr_value = a->second;
281             idx = attr_qname.indexOf(':');
282             if(idx != -1)
283             {
284                 aPrefix = attr_qname.copy(0, idx);
285             }
286             else
287                 aPrefix = OUString();
288 
289             result = aNSMap.find(aPrefix);
290             if (result != aNSMap.end())
291             {
292                 // set attribute with namespace
293                 aElement->setAttributeNS(result->second, attr_qname, attr_value);
294             } else {
295                 // set attribute without namespace
296                 aElement->setAttribute(attr_qname, attr_value);
297            }
298             a++;
299         }
300         m_aNSStack.push(aNSMap);
301     }
302 
303     void SAL_CALL CSAXDocumentBuilder::endElement(const OUString& aName)
304         throw (RuntimeException, SAXException)
305     {
306         ::osl::MutexGuard g(m_Mutex);
307 
308         // pop the current element from the stack
309         if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
310              m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
311             throw SAXException();
312 
313         Reference< XNode > aNode(m_aNodeStack.top());
314         if (aNode->getNodeType() != NodeType_ELEMENT_NODE)
315             throw SAXException();
316 
317         Reference< XElement > aElement(aNode, UNO_QUERY);
318         OUString aRefName;
319         OUString aPrefix = aElement->getPrefix();
320         if (aPrefix.getLength() > 0)
321             aRefName = aPrefix + OUString::createFromAscii(":") + aElement->getTagName();
322         else
323             aRefName = aElement->getTagName();
324         if (aRefName != aName) // consistency check
325             throw SAXException();
326 
327         // pop it
328         m_aNodeStack.pop();
329         m_aNSStack.pop();
330     }
331 
332     void SAL_CALL CSAXDocumentBuilder::characters(const OUString& aChars)
333         throw (RuntimeException, SAXException)
334     {
335         ::osl::MutexGuard g(m_Mutex);
336 
337         //  append text node to the current top element
338          if (m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
339              m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
340             throw SAXException();
341 
342          Reference< XText > aText = m_aDocument->createTextNode(aChars);
343          m_aNodeStack.top()->appendChild(Reference< XNode >(aText, UNO_QUERY));
344     }
345 
346     void SAL_CALL CSAXDocumentBuilder::ignorableWhitespace(const OUString& )
347         throw (RuntimeException, SAXException)
348     {
349         ::osl::MutexGuard g(m_Mutex);
350 
351         //  ignore ignorable whitespace
352         if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
353              m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
354             throw SAXException();
355     }
356 
357     void SAL_CALL CSAXDocumentBuilder::processingInstruction(const OUString& aTarget, const OUString& aData)
358         throw (RuntimeException, SAXException)
359     {
360         ::osl::MutexGuard g(m_Mutex);
361 
362         //  append PI node to the current top
363         if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
364              m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
365             throw SAXException();
366 
367         Reference< XProcessingInstruction > aInstruction = m_aDocument->createProcessingInstruction(
368                 aTarget, aData);
369         m_aNodeStack.top()->appendChild(Reference< XNode >(aInstruction, UNO_QUERY));
370     }
371 
372     void SAL_CALL CSAXDocumentBuilder::setDocumentLocator(const Reference< XLocator >& aLocator)
373         throw (RuntimeException, SAXException)
374     {
375         ::osl::MutexGuard g(m_Mutex);
376 
377         // set the document locator...
378         m_aLocator = aLocator;
379     }
380 }
381