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