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