xref: /trunk/main/unoxml/source/xpath/xpathapi.cxx (revision b862c97c)
1e9cbe144SAndrew Rist /**************************************************************
2e9cbe144SAndrew Rist  *
3e9cbe144SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4e9cbe144SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5e9cbe144SAndrew Rist  * distributed with this work for additional information
6e9cbe144SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7e9cbe144SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8e9cbe144SAndrew Rist  * "License"); you may not use this file except in compliance
9e9cbe144SAndrew Rist  * with the License.  You may obtain a copy of the License at
10e9cbe144SAndrew Rist  *
11e9cbe144SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12e9cbe144SAndrew Rist  *
13e9cbe144SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14e9cbe144SAndrew Rist  * software distributed under the License is distributed on an
15e9cbe144SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16e9cbe144SAndrew Rist  * KIND, either express or implied.  See the License for the
17e9cbe144SAndrew Rist  * specific language governing permissions and limitations
18e9cbe144SAndrew Rist  * under the License.
19e9cbe144SAndrew Rist  *
20e9cbe144SAndrew Rist  *************************************************************/
21e9cbe144SAndrew Rist 
22e9cbe144SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir #include <xpathapi.hxx>
25cdf0e10cSrcweir 
26cdf0e10cSrcweir #include <stdarg.h>
27cdf0e10cSrcweir #include <string.h>
28cdf0e10cSrcweir 
29cdf0e10cSrcweir #include <libxml/tree.h>
30cdf0e10cSrcweir #include <libxml/xmlerror.h>
31cdf0e10cSrcweir #include <libxml/xpath.h>
32cdf0e10cSrcweir #include <libxml/xpathInternals.h>
33cdf0e10cSrcweir 
34cdf0e10cSrcweir #include <rtl/ustrbuf.hxx>
35cdf0e10cSrcweir 
36cdf0e10cSrcweir #include <nodelist.hxx>
37cdf0e10cSrcweir #include <xpathobject.hxx>
38cdf0e10cSrcweir 
39cdf0e10cSrcweir #include "../dom/node.hxx"
40cdf0e10cSrcweir #include "../dom/document.hxx"
41cdf0e10cSrcweir 
42cdf0e10cSrcweir 
43cdf0e10cSrcweir using ::com::sun::star::lang::XMultiServiceFactory;
44cdf0e10cSrcweir 
45cdf0e10cSrcweir 
46cdf0e10cSrcweir namespace XPath
47cdf0e10cSrcweir {
48cdf0e10cSrcweir 	// factory
_getInstance(const Reference<XMultiServiceFactory> & rSMgr)49cdf0e10cSrcweir     Reference< XInterface > CXPathAPI::_getInstance(const Reference< XMultiServiceFactory >& rSMgr)
50cdf0e10cSrcweir     {
51cdf0e10cSrcweir         return Reference< XInterface >(static_cast<XXPathAPI*>(new CXPathAPI(rSMgr)));
52cdf0e10cSrcweir     }
53cdf0e10cSrcweir 
54cdf0e10cSrcweir 	// ctor
CXPathAPI(const Reference<XMultiServiceFactory> & rSMgr)55cdf0e10cSrcweir     CXPathAPI::CXPathAPI(const Reference< XMultiServiceFactory >& rSMgr)
56cdf0e10cSrcweir         : m_aFactory(rSMgr)
57cdf0e10cSrcweir     {
58cdf0e10cSrcweir     }
59cdf0e10cSrcweir 
60cdf0e10cSrcweir     const char* CXPathAPI::aImplementationName = "com.sun.star.comp.xml.xpath.XPathAPI";
61cdf0e10cSrcweir     const char* CXPathAPI::aSupportedServiceNames[] = {
62cdf0e10cSrcweir         "com.sun.star.xml.xpath.XPathAPI",
63cdf0e10cSrcweir         NULL
64cdf0e10cSrcweir     };
65cdf0e10cSrcweir 
_getImplementationName()66cdf0e10cSrcweir     OUString CXPathAPI::_getImplementationName()
67cdf0e10cSrcweir     {
68cdf0e10cSrcweir 	    return OUString::createFromAscii(aImplementationName);
69cdf0e10cSrcweir     }
70cdf0e10cSrcweir 
_getSupportedServiceNames()71cdf0e10cSrcweir     Sequence<OUString> CXPathAPI::_getSupportedServiceNames()
72cdf0e10cSrcweir     {
73cdf0e10cSrcweir 	    Sequence<OUString> aSequence;
74cdf0e10cSrcweir 	    for (int i=0; aSupportedServiceNames[i]!=NULL; i++) {
75cdf0e10cSrcweir 		    aSequence.realloc(i+1);
76cdf0e10cSrcweir 		    aSequence[i]=(OUString::createFromAscii(aSupportedServiceNames[i]));
77cdf0e10cSrcweir 	    }
78cdf0e10cSrcweir 	    return aSequence;
79cdf0e10cSrcweir     }
80cdf0e10cSrcweir 
getSupportedServiceNames()81cdf0e10cSrcweir     Sequence< OUString > SAL_CALL CXPathAPI::getSupportedServiceNames()
82cdf0e10cSrcweir         throw (RuntimeException)
83cdf0e10cSrcweir     {
84cdf0e10cSrcweir         return CXPathAPI::_getSupportedServiceNames();
85cdf0e10cSrcweir     }
86cdf0e10cSrcweir 
getImplementationName()87cdf0e10cSrcweir     OUString SAL_CALL CXPathAPI::getImplementationName()
88cdf0e10cSrcweir         throw (RuntimeException)
89cdf0e10cSrcweir     {
90cdf0e10cSrcweir         return CXPathAPI::_getImplementationName();
91cdf0e10cSrcweir     }
92cdf0e10cSrcweir 
supportsService(const OUString & aServiceName)93cdf0e10cSrcweir     sal_Bool SAL_CALL CXPathAPI::supportsService(const OUString& aServiceName)
94cdf0e10cSrcweir         throw (RuntimeException)
95cdf0e10cSrcweir     {
96cdf0e10cSrcweir         Sequence< OUString > supported = CXPathAPI::_getSupportedServiceNames();
97cdf0e10cSrcweir         for (sal_Int32 i=0; i<supported.getLength(); i++)
98cdf0e10cSrcweir         {
99cdf0e10cSrcweir             if (supported[i] == aServiceName) return sal_True;
100cdf0e10cSrcweir         }
101cdf0e10cSrcweir         return sal_False;
102cdf0e10cSrcweir     }
103cdf0e10cSrcweir 
104cdf0e10cSrcweir     // -------------------------------------------------------------------
105cdf0e10cSrcweir 
registerNS(const OUString & aPrefix,const OUString & aURI)106cdf0e10cSrcweir     void SAL_CALL CXPathAPI::registerNS(
107cdf0e10cSrcweir 			const OUString& aPrefix,
108cdf0e10cSrcweir 			const OUString& aURI)
109cdf0e10cSrcweir         throw (RuntimeException)
110cdf0e10cSrcweir     {
111cdf0e10cSrcweir         ::osl::MutexGuard const g(m_Mutex);
112cdf0e10cSrcweir 
113cdf0e10cSrcweir         m_nsmap.insert(nsmap_t::value_type(aPrefix, aURI));
114cdf0e10cSrcweir     }
115cdf0e10cSrcweir 
unregisterNS(const OUString & aPrefix,const OUString & aURI)116cdf0e10cSrcweir     void SAL_CALL CXPathAPI::unregisterNS(
117cdf0e10cSrcweir 			const OUString& aPrefix,
118cdf0e10cSrcweir 			const OUString& aURI)
119cdf0e10cSrcweir         throw (RuntimeException)
120cdf0e10cSrcweir     {
121cdf0e10cSrcweir         ::osl::MutexGuard const g(m_Mutex);
122cdf0e10cSrcweir 
123cdf0e10cSrcweir         if ((m_nsmap.find(aPrefix))->second.equals(aURI)) {
124cdf0e10cSrcweir             m_nsmap.erase(aPrefix);
125cdf0e10cSrcweir         }
126cdf0e10cSrcweir     }
127cdf0e10cSrcweir 
128cdf0e10cSrcweir 	// register all namespaces stored in the namespace list for this object
129cdf0e10cSrcweir 	// with the current xpath evaluation context
lcl_registerNamespaces(xmlXPathContextPtr ctx,const nsmap_t & nsmap)130cdf0e10cSrcweir     static void lcl_registerNamespaces(
131cdf0e10cSrcweir 			xmlXPathContextPtr ctx,
132cdf0e10cSrcweir 			const nsmap_t& nsmap)
133cdf0e10cSrcweir     {
134cdf0e10cSrcweir         nsmap_t::const_iterator i = nsmap.begin();
135cdf0e10cSrcweir         OString oprefix, ouri;
136cdf0e10cSrcweir         xmlChar *p, *u;
137cdf0e10cSrcweir         while (i != nsmap.end())
138cdf0e10cSrcweir         {
139cdf0e10cSrcweir             oprefix = OUStringToOString(i->first,  RTL_TEXTENCODING_UTF8);
140cdf0e10cSrcweir             ouri    = OUStringToOString(i->second, RTL_TEXTENCODING_UTF8);
141cdf0e10cSrcweir             p = (xmlChar*)oprefix.getStr();
142cdf0e10cSrcweir             u = (xmlChar*)ouri.getStr();
143cdf0e10cSrcweir             xmlXPathRegisterNs(ctx, p, u);
144cdf0e10cSrcweir             i++;
145cdf0e10cSrcweir         }
146cdf0e10cSrcweir     }
147cdf0e10cSrcweir 
148cdf0e10cSrcweir     // get all ns decls on a node (and parent nodes, if any)
lcl_collectNamespaces(nsmap_t & rNamespaces,Reference<XNode> const & xNamespaceNode)149cdf0e10cSrcweir     static void lcl_collectNamespaces(
150cdf0e10cSrcweir             nsmap_t & rNamespaces, Reference< XNode > const& xNamespaceNode)
151cdf0e10cSrcweir     {
152cdf0e10cSrcweir         DOM::CNode *const pCNode(DOM::CNode::GetImplementation(xNamespaceNode));
153cdf0e10cSrcweir         if (!pCNode) { throw RuntimeException(); }
154cdf0e10cSrcweir 
155cdf0e10cSrcweir         ::osl::MutexGuard const g(pCNode->GetOwnerDocument().GetMutex());
156cdf0e10cSrcweir 
157cdf0e10cSrcweir         xmlNodePtr pNode = pCNode->GetNodePtr();
158cdf0e10cSrcweir 		while (pNode != 0) {
159cdf0e10cSrcweir 			xmlNsPtr curDef = pNode->nsDef;
160cdf0e10cSrcweir 			while (curDef != 0) {
161cdf0e10cSrcweir 				const xmlChar* xHref = curDef->href;
162cdf0e10cSrcweir 				OUString aURI((sal_Char*)xHref, strlen((char*)xHref), RTL_TEXTENCODING_UTF8);
163cdf0e10cSrcweir 				const xmlChar* xPre = curDef->prefix;
164cdf0e10cSrcweir 				OUString aPrefix((sal_Char*)xPre, strlen((char*)xPre), RTL_TEXTENCODING_UTF8);
165cdf0e10cSrcweir                 // we could already have this prefix from a child node
166cdf0e10cSrcweir                 if (rNamespaces.find(aPrefix) == rNamespaces.end())
167cdf0e10cSrcweir                 {
168cdf0e10cSrcweir                     rNamespaces.insert(::std::make_pair(aPrefix, aURI));
169cdf0e10cSrcweir                 }
170cdf0e10cSrcweir 				curDef = curDef->next;
171cdf0e10cSrcweir 			}
172cdf0e10cSrcweir 			pNode = pNode->parent;
173cdf0e10cSrcweir 		}
174cdf0e10cSrcweir 	}
175cdf0e10cSrcweir 
lcl_collectRegisterNamespaces(CXPathAPI & rAPI,Reference<XNode> const & xNamespaceNode)176cdf0e10cSrcweir     static void lcl_collectRegisterNamespaces(
177cdf0e10cSrcweir             CXPathAPI & rAPI, Reference< XNode > const& xNamespaceNode)
178cdf0e10cSrcweir     {
179cdf0e10cSrcweir         nsmap_t namespaces;
180cdf0e10cSrcweir         lcl_collectNamespaces(namespaces, xNamespaceNode);
181cdf0e10cSrcweir         for (nsmap_t::const_iterator iter = namespaces.begin();
182cdf0e10cSrcweir                 iter != namespaces.end(); ++iter)
183cdf0e10cSrcweir         {
184cdf0e10cSrcweir             rAPI.registerNS(iter->first, iter->second);
185cdf0e10cSrcweir         }
186cdf0e10cSrcweir     }
187cdf0e10cSrcweir 
188cdf0e10cSrcweir 	// register function and variable lookup functions with the current
189cdf0e10cSrcweir 	// xpath evaluation context
lcl_registerExtensions(xmlXPathContextPtr ctx,const extensions_t & extensions)190cdf0e10cSrcweir     static void lcl_registerExtensions(
191cdf0e10cSrcweir 			xmlXPathContextPtr ctx,
192cdf0e10cSrcweir 			const extensions_t& extensions)
193cdf0e10cSrcweir     {
194cdf0e10cSrcweir         extensions_t::const_iterator i = extensions.begin();
195cdf0e10cSrcweir         while (i != extensions.end())
196cdf0e10cSrcweir         {
197cdf0e10cSrcweir             Libxml2ExtensionHandle aHandle = (*i)->getLibxml2ExtensionHandle();
198cdf0e10cSrcweir 			if ( aHandle.functionLookupFunction != 0 )
199cdf0e10cSrcweir 			{
200cdf0e10cSrcweir                 xmlXPathRegisterFuncLookup(ctx,
201cdf0e10cSrcweir                     reinterpret_cast<xmlXPathFuncLookupFunc>(
202cdf0e10cSrcweir 						sal::static_int_cast<sal_IntPtr>(aHandle.functionLookupFunction)),
203cdf0e10cSrcweir                     reinterpret_cast<void*>(
204cdf0e10cSrcweir 						sal::static_int_cast<sal_IntPtr>(aHandle.functionData)));
205cdf0e10cSrcweir 			}
206cdf0e10cSrcweir 			if ( aHandle.variableLookupFunction != 0 )
207cdf0e10cSrcweir 			{
208cdf0e10cSrcweir                 xmlXPathRegisterVariableLookup(ctx,
209cdf0e10cSrcweir                     reinterpret_cast<xmlXPathVariableLookupFunc>(
210cdf0e10cSrcweir 						sal::static_int_cast<sal_IntPtr>(aHandle.variableLookupFunction)),
211cdf0e10cSrcweir                     reinterpret_cast<void*>(
212cdf0e10cSrcweir 						sal::static_int_cast<sal_IntPtr>(aHandle.variableData)));
213cdf0e10cSrcweir 			}
214cdf0e10cSrcweir             i++;
215cdf0e10cSrcweir         }
216cdf0e10cSrcweir     }
217cdf0e10cSrcweir 
218cdf0e10cSrcweir     /**
219cdf0e10cSrcweir      * Use an XPath string to select a nodelist.
220cdf0e10cSrcweir      */
selectNodeList(const Reference<XNode> & contextNode,const OUString & expr)221cdf0e10cSrcweir     Reference< XNodeList > SAL_CALL CXPathAPI::selectNodeList(
222cdf0e10cSrcweir             const Reference< XNode >& contextNode,
223cdf0e10cSrcweir             const OUString& expr)
224cdf0e10cSrcweir         throw (RuntimeException, XPathException)
225cdf0e10cSrcweir     {
226cdf0e10cSrcweir 		Reference< XXPathObject > xobj = eval(contextNode, expr);
227cdf0e10cSrcweir 		return xobj->getNodeList();
228cdf0e10cSrcweir     }
229cdf0e10cSrcweir 
230cdf0e10cSrcweir     /**
231cdf0e10cSrcweir      * same as selectNodeList but registers all name space decalratiosn found on namespaceNode
232cdf0e10cSrcweir      */
selectNodeListNS(const Reference<XNode> & contextNode,const OUString & expr,const Reference<XNode> & namespaceNode)233cdf0e10cSrcweir     Reference< XNodeList > SAL_CALL CXPathAPI::selectNodeListNS(
234cdf0e10cSrcweir             const Reference< XNode >&  contextNode,
235cdf0e10cSrcweir             const OUString& expr,
236cdf0e10cSrcweir             const Reference< XNode >&  namespaceNode)
237cdf0e10cSrcweir         throw (RuntimeException, XPathException)
238cdf0e10cSrcweir     {
239cdf0e10cSrcweir         lcl_collectRegisterNamespaces(*this, namespaceNode);
240cdf0e10cSrcweir         return selectNodeList(contextNode, expr);
241cdf0e10cSrcweir     }
242cdf0e10cSrcweir 
243cdf0e10cSrcweir     /**
244cdf0e10cSrcweir      * Same as selectNodeList but returns the first node (if any)
245cdf0e10cSrcweir      */
selectSingleNode(const Reference<XNode> & contextNode,const OUString & expr)246cdf0e10cSrcweir     Reference< XNode > SAL_CALL CXPathAPI::selectSingleNode(
247cdf0e10cSrcweir             const Reference< XNode >& contextNode,
248cdf0e10cSrcweir             const OUString& expr)
249cdf0e10cSrcweir         throw (RuntimeException, XPathException)
250cdf0e10cSrcweir     {
251cdf0e10cSrcweir         Reference< XNodeList > aList = selectNodeList(contextNode, expr);
252cdf0e10cSrcweir         Reference< XNode > aNode = aList->item(0);
253cdf0e10cSrcweir         return aNode;
254cdf0e10cSrcweir     }
255cdf0e10cSrcweir 
256cdf0e10cSrcweir     /**
257cdf0e10cSrcweir 	 * Same as selectSingleNode but registers all namespaces declared on
258cdf0e10cSrcweir      * namespaceNode
259cdf0e10cSrcweir      */
selectSingleNodeNS(const Reference<XNode> & contextNode,const OUString & expr,const Reference<XNode> & namespaceNode)260cdf0e10cSrcweir     Reference< XNode > SAL_CALL CXPathAPI::selectSingleNodeNS(
261cdf0e10cSrcweir             const Reference< XNode >& contextNode,
262cdf0e10cSrcweir             const OUString& expr,
263cdf0e10cSrcweir             const Reference< XNode >&  namespaceNode )
264cdf0e10cSrcweir         throw (RuntimeException, XPathException)
265cdf0e10cSrcweir     {
266cdf0e10cSrcweir         lcl_collectRegisterNamespaces(*this, namespaceNode);
267cdf0e10cSrcweir         return selectSingleNode(contextNode, expr);
268cdf0e10cSrcweir     }
269cdf0e10cSrcweir 
make_error_message(xmlErrorPtr pError)270cdf0e10cSrcweir     static OUString make_error_message(xmlErrorPtr pError)
271cdf0e10cSrcweir     {
272cdf0e10cSrcweir         ::rtl::OUStringBuffer buf;
273cdf0e10cSrcweir         if (pError->message) {
274cdf0e10cSrcweir             buf.appendAscii(pError->message);
275cdf0e10cSrcweir         }
276cdf0e10cSrcweir         int line = pError->line;
277cdf0e10cSrcweir         if (line) {
278cdf0e10cSrcweir             buf.appendAscii("Line: ");
279cdf0e10cSrcweir             buf.append(static_cast<sal_Int32>(line));
280cdf0e10cSrcweir             buf.appendAscii("\n");
281cdf0e10cSrcweir         }
282cdf0e10cSrcweir         int column = pError->int2;
283cdf0e10cSrcweir         if (column) {
284cdf0e10cSrcweir             buf.appendAscii("Column: ");
285cdf0e10cSrcweir             buf.append(static_cast<sal_Int32>(column));
286cdf0e10cSrcweir             buf.appendAscii("\n");
287cdf0e10cSrcweir         }
288cdf0e10cSrcweir         OUString msg = buf.makeStringAndClear();
289cdf0e10cSrcweir         return msg;
290cdf0e10cSrcweir     }
291cdf0e10cSrcweir 
292cdf0e10cSrcweir     extern "C" {
293cdf0e10cSrcweir 
generic_error_func(void * userData,const char * format,...)294cdf0e10cSrcweir         static void generic_error_func(void *userData, const char *format, ...)
295cdf0e10cSrcweir         {
296cdf0e10cSrcweir             (void) userData;
297cdf0e10cSrcweir             char str[1000];
298cdf0e10cSrcweir             va_list args;
299cdf0e10cSrcweir 
300cdf0e10cSrcweir             va_start(args, format);
301cdf0e10cSrcweir #ifdef _WIN32
302cdf0e10cSrcweir #define vsnprintf _vsnprintf
303cdf0e10cSrcweir #endif
304cdf0e10cSrcweir             vsnprintf(str, sizeof(str), format, args);
305cdf0e10cSrcweir             va_end(args);
306cdf0e10cSrcweir 
307cdf0e10cSrcweir             ::rtl::OUStringBuffer buf(
308cdf0e10cSrcweir                 OUString::createFromAscii("libxml2 error:\n"));
309cdf0e10cSrcweir             buf.appendAscii(str);
310cdf0e10cSrcweir             OString msg = OUStringToOString(buf.makeStringAndClear(),
311cdf0e10cSrcweir                 RTL_TEXTENCODING_ASCII_US);
312cdf0e10cSrcweir             OSL_ENSURE(sal_False, msg.getStr());
313cdf0e10cSrcweir         }
314cdf0e10cSrcweir 
structured_error_func(void * userData,xmlErrorPtr error)315cdf0e10cSrcweir         static void structured_error_func(void * userData, xmlErrorPtr error)
316cdf0e10cSrcweir         {
317cdf0e10cSrcweir             (void) userData;
318cdf0e10cSrcweir             ::rtl::OUStringBuffer buf(
319cdf0e10cSrcweir                 OUString::createFromAscii("libxml2 error:\n"));
320cdf0e10cSrcweir             if (error) {
321cdf0e10cSrcweir                 buf.append(make_error_message(error));
322cdf0e10cSrcweir             } else {
323cdf0e10cSrcweir                 buf.append(OUString::createFromAscii("no error argument!"));
324cdf0e10cSrcweir             }
325cdf0e10cSrcweir             OString msg = OUStringToOString(buf.makeStringAndClear(),
326cdf0e10cSrcweir                 RTL_TEXTENCODING_ASCII_US);
327cdf0e10cSrcweir             OSL_ENSURE(sal_False, msg.getStr());
328cdf0e10cSrcweir         }
329cdf0e10cSrcweir 
330cdf0e10cSrcweir     } // extern "C"
331cdf0e10cSrcweir 
332cdf0e10cSrcweir 	/**
333cdf0e10cSrcweir 	 * evaluates an XPath string. relative XPath expressions are evaluated relative to
334cdf0e10cSrcweir 	 * the context Node
335cdf0e10cSrcweir 	 */
eval(Reference<XNode> const & xContextNode,const OUString & expr)336cdf0e10cSrcweir     Reference< XXPathObject > SAL_CALL CXPathAPI::eval(
337cdf0e10cSrcweir             Reference< XNode > const& xContextNode,
338cdf0e10cSrcweir 			const OUString& expr)
339cdf0e10cSrcweir         throw (RuntimeException, XPathException)
340cdf0e10cSrcweir     {
341cdf0e10cSrcweir         if (!xContextNode.is()) { throw RuntimeException(); }
342cdf0e10cSrcweir 
343cdf0e10cSrcweir         nsmap_t nsmap;
344cdf0e10cSrcweir         extensions_t extensions;
345cdf0e10cSrcweir 
346cdf0e10cSrcweir         {
347cdf0e10cSrcweir             ::osl::MutexGuard const g(m_Mutex);
348cdf0e10cSrcweir             nsmap = m_nsmap;
349cdf0e10cSrcweir             extensions = m_extensions;
350cdf0e10cSrcweir         }
351cdf0e10cSrcweir 
352cdf0e10cSrcweir         // get the node and document
353cdf0e10cSrcweir         ::rtl::Reference<DOM::CDocument> const pCDoc(
354cdf0e10cSrcweir                 dynamic_cast<DOM::CDocument*>( DOM::CNode::GetImplementation(
355cdf0e10cSrcweir                         xContextNode->getOwnerDocument())));
356cdf0e10cSrcweir         if (!pCDoc.is()) { throw RuntimeException(); }
357cdf0e10cSrcweir 
358cdf0e10cSrcweir         DOM::CNode *const pCNode = DOM::CNode::GetImplementation(xContextNode);
359cdf0e10cSrcweir         if (!pCNode) { throw RuntimeException(); }
360cdf0e10cSrcweir 
361cdf0e10cSrcweir         ::osl::MutexGuard const g(pCDoc->GetMutex()); // lock the document!
362cdf0e10cSrcweir 
363cdf0e10cSrcweir         xmlNodePtr const pNode = pCNode->GetNodePtr();
364cdf0e10cSrcweir         if (!pNode) { throw RuntimeException(); }
365cdf0e10cSrcweir         xmlDocPtr pDoc = pNode->doc;
366cdf0e10cSrcweir 
367cdf0e10cSrcweir         /* NB: workaround for #i87252#:
368cdf0e10cSrcweir            libxml < 2.6.17 considers it an error if the context
369cdf0e10cSrcweir            node is the empty document (i.e. its xpathCtx->doc has no
370cdf0e10cSrcweir            children). libxml 2.6.17 does not consider it an error.
371cdf0e10cSrcweir            Unfortunately, old libxml prints an error message to stderr,
372cdf0e10cSrcweir            which (afaik) cannot be turned off in this case, so we handle it.
373cdf0e10cSrcweir         */
374cdf0e10cSrcweir         if (!pDoc->children) {
375cdf0e10cSrcweir             throw XPathException();
376cdf0e10cSrcweir         }
377cdf0e10cSrcweir 
378cdf0e10cSrcweir         /* Create xpath evaluation context */
379cdf0e10cSrcweir         ::boost::shared_ptr<xmlXPathContext> const xpathCtx(
380cdf0e10cSrcweir                 xmlXPathNewContext(pDoc), xmlXPathFreeContext);
381*b862c97cSHerbert Dürr         if( !bool(xpathCtx)) { throw XPathException(); }
382cdf0e10cSrcweir 
383cdf0e10cSrcweir         // set context node
384cdf0e10cSrcweir         xpathCtx->node = pNode;
385cdf0e10cSrcweir         // error handling
386cdf0e10cSrcweir         xpathCtx->error = structured_error_func;
387cdf0e10cSrcweir         xmlSetGenericErrorFunc(NULL, generic_error_func);
388cdf0e10cSrcweir 
389cdf0e10cSrcweir 		// register namespaces and extension
390cdf0e10cSrcweir         lcl_registerNamespaces(xpathCtx.get(), nsmap);
391cdf0e10cSrcweir         lcl_registerExtensions(xpathCtx.get(), extensions);
392cdf0e10cSrcweir 
393cdf0e10cSrcweir 		/* run the query */
394cdf0e10cSrcweir         OString o1 = OUStringToOString(expr, RTL_TEXTENCODING_UTF8);
395cdf0e10cSrcweir         xmlChar *xStr = (xmlChar*)o1.getStr();
396cdf0e10cSrcweir         ::boost::shared_ptr<xmlXPathObject> const xpathObj(
397cdf0e10cSrcweir                 xmlXPathEval(xStr, xpathCtx.get()), xmlXPathFreeObject);
398cdf0e10cSrcweir         if (0 == xpathObj) {
399cdf0e10cSrcweir             // OSL_ENSURE(xpathCtx->lastError == NULL, xpathCtx->lastError->message);
400cdf0e10cSrcweir             throw XPathException();
401cdf0e10cSrcweir         }
402cdf0e10cSrcweir         Reference<XXPathObject> const xObj(
403cdf0e10cSrcweir                 new CXPathObject(pCDoc, pCDoc->GetMutex(), xpathObj));
404cdf0e10cSrcweir         return xObj;
405cdf0e10cSrcweir     }
406cdf0e10cSrcweir 
407cdf0e10cSrcweir 	/**
408cdf0e10cSrcweir 	 * same as eval but registers all namespace declarations found on namespaceNode
409cdf0e10cSrcweir 	 */
evalNS(const Reference<XNode> & contextNode,const OUString & expr,const Reference<XNode> & namespaceNode)410cdf0e10cSrcweir     Reference< XXPathObject > SAL_CALL CXPathAPI::evalNS(
411cdf0e10cSrcweir 			const Reference< XNode >& contextNode,
412cdf0e10cSrcweir 			const OUString& expr,
413cdf0e10cSrcweir 			const Reference< XNode >& namespaceNode)
414cdf0e10cSrcweir         throw (RuntimeException, XPathException)
415cdf0e10cSrcweir     {
416cdf0e10cSrcweir         lcl_collectRegisterNamespaces(*this, namespaceNode);
417cdf0e10cSrcweir         return eval(contextNode, expr);
418cdf0e10cSrcweir     }
419cdf0e10cSrcweir 
420cdf0e10cSrcweir 	/**
421cdf0e10cSrcweir 	 * uses the service manager to create an instance of the service denoted by aName.
422cdf0e10cSrcweir 	 * If the returned object implements the XXPathExtension interface, it is added to the list
423cdf0e10cSrcweir 	 * of extensions that are used when evaluating XPath strings with this XPathAPI instance
424cdf0e10cSrcweir 	 */
registerExtension(const OUString & aName)425cdf0e10cSrcweir     void SAL_CALL CXPathAPI::registerExtension(
426cdf0e10cSrcweir 			const OUString& aName)
427cdf0e10cSrcweir         throw (RuntimeException)
428cdf0e10cSrcweir     {
429cdf0e10cSrcweir         ::osl::MutexGuard const g(m_Mutex);
430cdf0e10cSrcweir 
431cdf0e10cSrcweir         // get extension from service manager
432cdf0e10cSrcweir         Reference< XXPathExtension > const xExtension(
433cdf0e10cSrcweir                 m_aFactory->createInstance(aName), UNO_QUERY_THROW);
434cdf0e10cSrcweir         m_extensions.push_back(xExtension);
435cdf0e10cSrcweir     }
436cdf0e10cSrcweir 
437cdf0e10cSrcweir 	/**
438cdf0e10cSrcweir 	 * registers the given extension instance to be used by XPath evaluations performed through this
439cdf0e10cSrcweir 	 * XPathAPI instance
440cdf0e10cSrcweir 	 */
registerExtensionInstance(Reference<XXPathExtension> const & xExtension)441cdf0e10cSrcweir     void SAL_CALL CXPathAPI::registerExtensionInstance(
442cdf0e10cSrcweir             Reference< XXPathExtension> const& xExtension)
443cdf0e10cSrcweir         throw (RuntimeException)
444cdf0e10cSrcweir     {
445cdf0e10cSrcweir         if (!xExtension.is()) {
446cdf0e10cSrcweir             throw RuntimeException();
447cdf0e10cSrcweir         }
448cdf0e10cSrcweir         ::osl::MutexGuard const g(m_Mutex);
449cdf0e10cSrcweir         m_extensions.push_back( xExtension );
450cdf0e10cSrcweir     }
451cdf0e10cSrcweir }
452