diff options
author | Rüdiger Timm <rt@openoffice.org> | 2008-06-06 11:07:43 +0000 |
---|---|---|
committer | Rüdiger Timm <rt@openoffice.org> | 2008-06-06 11:07:43 +0000 |
commit | 7d76d92bc014e8aeb166a8dce74e16e27731a4ef (patch) | |
tree | 3a003bfcb3405a02eaaad62476402961fd61f618 /unoxml/source | |
parent | fa29cea453568a10d95cce5a4f69962fe6e0c231 (diff) |
INTEGRATION: CWS xmlfix2 (1.5.18); FILE MERGED
2008/05/15 17:26:52 mst 1.5.18.5: RESYNC: (1.5-1.6); FILE MERGED
2008/04/23 13:43:49 mst 1.5.18.4: - unoxml/source/xpath/xpathapi.cxx:
+ fix build with gcc 4.3: include string.h
2008/04/09 16:30:28 mst 1.5.18.3: fix issue #i87252#
- unoxml/source/xpath/xpathapi.cxx:
+ prevent libxml from printing error messages to stderr when evaluating
XPath expressions
2008/03/31 14:20:35 mst 1.5.18.2: #i81678#: interface change: XXPathAPI
- unoxml/source/xpath/xpathapi{.hxx,.cxx}:
+ adapt to changes in css.xml.xpath.XXPathAPI
2007/11/14 14:28:38 lo 1.5.18.1: parser improvements
Diffstat (limited to 'unoxml/source')
-rw-r--r-- | unoxml/source/xpath/xpathapi.cxx | 286 |
1 files changed, 201 insertions, 85 deletions
diff --git a/unoxml/source/xpath/xpathapi.cxx b/unoxml/source/xpath/xpathapi.cxx index 10cc5aad0f63..c8fb5f990090 100644 --- a/unoxml/source/xpath/xpathapi.cxx +++ b/unoxml/source/xpath/xpathapi.cxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: xpathapi.cxx,v $ - * $Revision: 1.6 $ + * $Revision: 1.7 $ * * This file is part of OpenOffice.org. * @@ -33,19 +33,25 @@ #include "xpathobject.hxx" #include "../dom/node.hxx" +#include <rtl/ustrbuf.hxx> + +#include <libxml/xmlerror.h> #include <libxml/xpath.h> #include <libxml/xpathInternals.h> +#include <stdarg.h> +#include <string.h> + + namespace XPath { - + // factory Reference< XInterface > CXPathAPI::_getInstance(const Reference< XMultiServiceFactory >& rSMgr) { - // XXX - // return static_cast< XXPathAPI* >(new CXPathAPI()); return Reference< XInterface >(static_cast<XXPathAPI*>(new CXPathAPI(rSMgr))); } + // ctor CXPathAPI::CXPathAPI(const Reference< XMultiServiceFactory >& rSMgr) : m_aFactory(rSMgr) { @@ -61,6 +67,7 @@ namespace XPath { return OUString::createFromAscii(aImplementationName); } + Sequence<OUString> CXPathAPI::_getSupportedServiceNames() { Sequence<OUString> aSequence; @@ -96,21 +103,28 @@ namespace XPath // ------------------------------------------------------------------- - void SAL_CALL CXPathAPI::registerNS(const OUString& aPrefix, const OUString& aURI) + void SAL_CALL CXPathAPI::registerNS( + const OUString& aPrefix, + const OUString& aURI) throw (RuntimeException) { m_nsmap.insert(nsmap_t::value_type(aPrefix, aURI)); } - void SAL_CALL CXPathAPI::unregisterNS(const OUString& aPrefix, const OUString& aURI) + void SAL_CALL CXPathAPI::unregisterNS( + const OUString& aPrefix, + const OUString& aURI) throw (RuntimeException) { if ((m_nsmap.find(aPrefix))->second.equals(aURI)) m_nsmap.erase(aPrefix); - } - static void _registerNamespaces(xmlXPathContextPtr ctx, const nsmap_t& nsmap) + // register all namespaces stored in the namespace list for this object + // with the current xpath evaluation context + static void _registerNamespaces( + xmlXPathContextPtr ctx, + const nsmap_t& nsmap) { nsmap_t::const_iterator i = nsmap.begin(); OString oprefix, ouri; @@ -126,104 +140,176 @@ namespace XPath } } - static void _registerExtensions(xmlXPathContextPtr ctx, const extensions_t& extensions) + // get all ns decls on a node (and parent nodes, if any) and register them + static void _collectNamespaces( + CXPathAPI* pAPI, + const Reference< XNode >& namespaceNode) + { + // get namespace decls from node... + xmlNodePtr pNode = DOM::CNode::getNodePtr(namespaceNode); + while (pNode != 0) { + xmlNsPtr curDef = pNode->nsDef; + while (curDef != 0) { + const xmlChar* xHref = curDef->href; + OUString aURI((sal_Char*)xHref, strlen((char*)xHref), RTL_TEXTENCODING_UTF8); + const xmlChar* xPre = curDef->prefix; + OUString aPrefix((sal_Char*)xPre, strlen((char*)xPre), RTL_TEXTENCODING_UTF8); + pAPI->registerNS(aPrefix, aURI); + curDef = curDef->next; + } + pNode = pNode->parent; + } + } + + // register function and variable lookup functions with the current + // xpath evaluation context + static void _registerExtensions( + xmlXPathContextPtr ctx, + const extensions_t& extensions) { extensions_t::const_iterator i = extensions.begin(); while (i != extensions.end()) { Libxml2ExtensionHandle aHandle = (*i)->getLibxml2ExtensionHandle(); if ( aHandle.functionLookupFunction != 0 ) + { xmlXPathRegisterFuncLookup(ctx, - reinterpret_cast<xmlXPathFuncLookupFunc>(sal::static_int_cast<sal_IntPtr>(aHandle.functionLookupFunction)), - /* (xmlXPathFuncLookupFunc) aHandle.functionLookupFunction, */ - reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(aHandle.functionData))); - /* (void*)(aHandle.functionData));*/ + reinterpret_cast<xmlXPathFuncLookupFunc>( + sal::static_int_cast<sal_IntPtr>(aHandle.functionLookupFunction)), + reinterpret_cast<void*>( + sal::static_int_cast<sal_IntPtr>(aHandle.functionData))); + } if ( aHandle.variableLookupFunction != 0 ) + { xmlXPathRegisterVariableLookup(ctx, - /* (xmlXPathVariableLookupFunc) aHandle.variableLookupFunction, */ - reinterpret_cast<xmlXPathVariableLookupFunc>(sal::static_int_cast<sal_IntPtr>(aHandle.variableLookupFunction)), - /*(void*)(aHandle.variableData));*/ - reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(aHandle.variableData))); + reinterpret_cast<xmlXPathVariableLookupFunc>( + sal::static_int_cast<sal_IntPtr>(aHandle.variableLookupFunction)), + reinterpret_cast<void*>( + sal::static_int_cast<sal_IntPtr>(aHandle.variableData))); + } i++; } } /** - Use an XPath string to select a nodelist. - */ + * Use an XPath string to select a nodelist. + */ Reference< XNodeList > SAL_CALL CXPathAPI::selectNodeList( const Reference< XNode >& contextNode, - const OUString& str) - throw (RuntimeException) + const OUString& expr) + throw (RuntimeException, XPathException) { - - xmlXPathContextPtr xpathCtx; - xmlXPathObjectPtr xpathObj; - - // get the node and document - xmlNodePtr pNode = DOM::CNode::getNodePtr(contextNode); - xmlDocPtr pDoc = pNode->doc; - - /* Create xpath evaluation context */ - xpathCtx = xmlXPathNewContext(pDoc); - if (xpathCtx == NULL)throw RuntimeException(); - xpathCtx->node = pNode; - _registerNamespaces(xpathCtx, m_nsmap); - - OString o1 = OUStringToOString(str, RTL_TEXTENCODING_UTF8); - xmlChar *xStr = (xmlChar*)o1.getStr(); - - /* run the query */ - if ((xpathObj = xmlXPathEval(xStr, xpathCtx)) == NULL) - { - xmlXPathFreeContext(xpathCtx); - throw RuntimeException(); - } - Reference< XNodeList > aList(new CNodeList(xpathObj)); - xmlXPathFreeContext(xpathCtx); - return aList; + Reference< XXPathObject > xobj = eval(contextNode, expr); + return xobj->getNodeList(); } /** - Use an XPath string to select a nodelist. - */ + * same as selectNodeList but registers all name space decalratiosn found on namespaceNode + */ Reference< XNodeList > SAL_CALL CXPathAPI::selectNodeListNS( - const Reference< XNode >& /* contextNode */, - const OUString& /* str */, - const Reference< XNode >& /* namespaceNode */) - throw (RuntimeException) + const Reference< XNode >& contextNode, + const OUString& expr, + const Reference< XNode >& namespaceNode) + throw (RuntimeException, XPathException) { - return Reference< XNodeList>(); + _collectNamespaces(this, namespaceNode); + return selectNodeList(contextNode, expr); } /** - Use an XPath string to select a single node. - */ + * Same as selectNodeList but returns the first node (if any) + */ Reference< XNode > SAL_CALL CXPathAPI::selectSingleNode( const Reference< XNode >& contextNode, - const OUString& str) - throw (RuntimeException) + const OUString& expr) + throw (RuntimeException, XPathException) { - Reference< XNodeList > aList = selectNodeList(contextNode, str); + Reference< XNodeList > aList = selectNodeList(contextNode, expr); Reference< XNode > aNode = aList->item(0); return aNode; } /** - Use an XPath string to select a single node. - */ + * Same as selectSingleNode but registers all namespaces declared on + * namespaceNode + */ Reference< XNode > SAL_CALL CXPathAPI::selectSingleNodeNS( - const Reference< XNode >& /* contextNode */, - const OUString& /* str */, - const Reference< XNode >& /* namespaceNode*/ ) - throw (RuntimeException) + const Reference< XNode >& contextNode, + const OUString& expr, + const Reference< XNode >& namespaceNode ) + throw (RuntimeException, XPathException) { - return Reference< XNode >(); + _collectNamespaces(this, namespaceNode); + return selectSingleNode(contextNode, expr); } + static OUString make_error_message(xmlErrorPtr pError) + { + ::rtl::OUStringBuffer buf; + if (pError->message) { + buf.appendAscii(pError->message); + } + int line = pError->line; + if (line) { + buf.appendAscii("Line: "); + buf.append(static_cast<sal_Int32>(line)); + buf.appendAscii("\n"); + } + int column = pError->int2; + if (column) { + buf.appendAscii("Column: "); + buf.append(static_cast<sal_Int32>(column)); + buf.appendAscii("\n"); + } + OUString msg = buf.makeStringAndClear(); + return msg; + } + + extern "C" { - Reference< XXPathObject > SAL_CALL CXPathAPI::eval(const Reference< XNode >& contextNode, const OUString& str) - throw (RuntimeException) + static void generic_error_func(void *userData, const char *format, ...) + { + (void) userData; + char str[1000]; + va_list args; + + va_start(args, format); + vsnprintf(str, sizeof(str), format, args); + va_end(args); + + ::rtl::OUStringBuffer buf( + OUString::createFromAscii("libxml2 error:\n")); + buf.appendAscii(str); + OString msg = OUStringToOString(buf.makeStringAndClear(), + RTL_TEXTENCODING_ASCII_US); + OSL_ENSURE(sal_False, msg.getStr()); + } + + static void structured_error_func(void * userData, xmlErrorPtr error) + { + (void) userData; + ::rtl::OUStringBuffer buf( + OUString::createFromAscii("libxml2 error:\n")); + if (error) { + buf.append(make_error_message(error)); + } else { + buf.append(OUString::createFromAscii("no error argument!")); + } + OString msg = OUStringToOString(buf.makeStringAndClear(), + RTL_TEXTENCODING_ASCII_US); + OSL_ENSURE(sal_False, msg.getStr()); + } + + } // extern "C" + + /** + * evaluates an XPath string. relative XPath expressions are evaluated relative to + * the context Node + */ + Reference< XXPathObject > SAL_CALL CXPathAPI::eval( + const Reference< XNode >& contextNode, + const OUString& expr) + throw (RuntimeException, XPathException) { xmlXPathContextPtr xpathCtx; xmlXPathObjectPtr xpathObj; @@ -232,53 +318,83 @@ namespace XPath xmlNodePtr pNode = DOM::CNode::getNodePtr(contextNode); xmlDocPtr pDoc = pNode->doc; + /* NB: workaround for #i87252#: + libxml < 2.6.17 considers it an error if the context + node is the empty document (i.e. its xpathCtx->doc has no + children). libxml 2.6.17 does not consider it an error. + Unfortunately, old libxml prints an error message to stderr, + which (afaik) cannot be turned off in this case, so we handle it. + */ + if (!pDoc->children) { + throw XPathException(); + } + /* Create xpath evaluation context */ xpathCtx = xmlXPathNewContext(pDoc); - if (xpathCtx == NULL)throw RuntimeException(); + if (xpathCtx == NULL) throw XPathException(); - // set conext node + // set context node xpathCtx->node = pNode; + // error handling + xpathCtx->error = structured_error_func; + xmlSetGenericErrorFunc(NULL, generic_error_func); + // register namespaces and extension _registerNamespaces(xpathCtx, m_nsmap); _registerExtensions(xpathCtx, m_extensions); - OString o1 = OUStringToOString(str, RTL_TEXTENCODING_UTF8); - xmlChar *xStr = (xmlChar*)o1.getStr(); - - /* run the query */ + OString o1 = OUStringToOString(expr, RTL_TEXTENCODING_UTF8); + xmlChar *xStr = (xmlChar*)o1.getStr(); if ((xpathObj = xmlXPathEval(xStr, xpathCtx)) == NULL) { // OSL_ENSURE(xpathCtx->lastError == NULL, xpathCtx->lastError->message); xmlXPathFreeContext(xpathCtx); - throw RuntimeException(); + throw XPathException(); } xmlXPathFreeContext(xpathCtx); - Reference< XXPathObject > aObj(new CXPathObject(xpathObj)); return aObj; } - Reference< XXPathObject > SAL_CALL CXPathAPI::evalNS(const Reference< XNode >& /* contextNode */, const OUString& /* str */, const Reference< XNode >& /* namespaceNode */) - throw (RuntimeException) + /** + * same as eval but registers all namespace declarations found on namespaceNode + */ + Reference< XXPathObject > SAL_CALL CXPathAPI::evalNS( + const Reference< XNode >& contextNode, + const OUString& expr, + const Reference< XNode >& namespaceNode) + throw (RuntimeException, XPathException) { - return Reference< XXPathObject>(); + _collectNamespaces(this, namespaceNode); + return eval(contextNode, expr); } - void SAL_CALL CXPathAPI::registerExtension(const OUString& aName) throw (RuntimeException) + /** + * uses the service manager to create an instance of the service denoted by aName. + * If the returned object implements the XXPathExtension interface, it is added to the list + * of extensions that are used when evaluating XPath strings with this XPathAPI instance + */ + void SAL_CALL CXPathAPI::registerExtension( + const OUString& aName) + throw (RuntimeException) { // get extension from service manager Reference< XXPathExtension > aExtension(m_aFactory->createInstance(aName), UNO_QUERY_THROW); m_extensions.push_back( aExtension ); } - void SAL_CALL CXPathAPI::registerExtensionInstance(const Reference< XXPathExtension>& aExtension) throw (RuntimeException) + /** + * registers the given extension instance to be used by XPath evaluations performed through this + * XPathAPI instance + */ + void SAL_CALL CXPathAPI::registerExtensionInstance( + const Reference< XXPathExtension>& aExtension) + throw (RuntimeException) { if (aExtension.is()) { m_extensions.push_back( aExtension ); - } - else + } else { throw RuntimeException(); + } } - - } |