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