diff options
Diffstat (limited to 'unoxml/source/xpath')
-rw-r--r-- | unoxml/source/xpath/nodelist.cxx | 72 | ||||
-rw-r--r-- | unoxml/source/xpath/nodelist.hxx | 70 | ||||
-rw-r--r-- | unoxml/source/xpath/xpathapi.cxx | 398 | ||||
-rw-r--r-- | unoxml/source/xpath/xpathapi.hxx | 107 | ||||
-rw-r--r-- | unoxml/source/xpath/xpathobject.cxx | 181 | ||||
-rw-r--r-- | unoxml/source/xpath/xpathobject.hxx | 109 |
6 files changed, 937 insertions, 0 deletions
diff --git a/unoxml/source/xpath/nodelist.cxx b/unoxml/source/xpath/nodelist.cxx new file mode 100644 index 000000000..1b306aabc --- /dev/null +++ b/unoxml/source/xpath/nodelist.cxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "nodelist.hxx" + +#include "../dom/document.hxx" + +using namespace css::uno; +using namespace css::xml::dom; + +namespace XPath +{ + CNodeList::CNodeList( + ::rtl::Reference<DOM::CDocument> const& pDocument, + ::osl::Mutex & rMutex, + std::shared_ptr<xmlXPathObject> const& rxpathObj) + : m_pDocument(pDocument) + , m_rMutex(rMutex) + , m_pNodeSet(nullptr) + { + if (rxpathObj != nullptr && rxpathObj->type == XPATH_NODESET) + { + m_pNodeSet = rxpathObj->nodesetval; + m_pXPathObj = rxpathObj; + } + } + + /** + The number of nodes in the list. + */ + sal_Int32 SAL_CALL CNodeList::getLength() + { + ::osl::MutexGuard const g(m_rMutex); + + sal_Int32 value = 0; + if (m_pNodeSet != nullptr) + value = xmlXPathNodeSetGetLength(m_pNodeSet); + return value; + } + + /** + Returns the indexth item in the collection. + */ + Reference< XNode > SAL_CALL CNodeList::item(sal_Int32 index) + { + ::osl::MutexGuard const g(m_rMutex); + + if (nullptr == m_pNodeSet) { + return nullptr; + } + xmlNodePtr const pNode = xmlXPathNodeSetItem(m_pNodeSet, index); + return m_pDocument->GetCNode(pNode); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unoxml/source/xpath/nodelist.hxx b/unoxml/source/xpath/nodelist.hxx new file mode 100644 index 000000000..689510dea --- /dev/null +++ b/unoxml/source/xpath/nodelist.hxx @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/types.h> +#include <rtl/ref.hxx> + +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/xml/dom/XNode.hpp> +#include <com/sun/star/xml/dom/XNodeList.hpp> + +#include <libxml/xpath.h> + +#include "../dom/document.hxx" + +#include <memory> + +namespace DOM { + class CDocument; +} + +namespace XPath +{ + + class CNodeList : public cppu::WeakImplHelper< css::xml::dom::XNodeList > + { + private: + /// #i115995# keep document alive + ::rtl::Reference< DOM::CDocument > const m_pDocument; + ::osl::Mutex & m_rMutex; + /// retain the result set in case the CXPathObject is released + std::shared_ptr<xmlXPathObject> m_pXPathObj; + xmlNodeSetPtr m_pNodeSet; + + public: + CNodeList( + ::rtl::Reference<DOM::CDocument> const& pDocument, + ::osl::Mutex & rMutex, + std::shared_ptr<xmlXPathObject> const& rxpathObj); + /** + The number of nodes in the list. + */ + virtual sal_Int32 SAL_CALL getLength() override; + /** + Returns the indexth item in the collection. + */ + virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL item(sal_Int32 index) override; + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unoxml/source/xpath/xpathapi.cxx b/unoxml/source/xpath/xpathapi.cxx new file mode 100644 index 000000000..f1968c208 --- /dev/null +++ b/unoxml/source/xpath/xpathapi.cxx @@ -0,0 +1,398 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "xpathapi.hxx" + +#include <stdarg.h> +#include <string.h> + +#include <libxml/tree.h> +#include <libxml/xmlerror.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> + +#include <com/sun/star/xml/xpath/XPathException.hpp> + +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> + +#include "xpathobject.hxx" + +#include <node.hxx> +#include "../dom/document.hxx" + +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> + +using namespace css::io; +using namespace css::uno; +using namespace css::xml::dom; +using namespace css::xml::xpath; + +namespace XPath +{ + // ctor + CXPathAPI::CXPathAPI(const Reference< XComponentContext >& rxContext) + : m_xContext(rxContext) + { + } + + Sequence< OUString > SAL_CALL CXPathAPI::getSupportedServiceNames() + { + return { "com.sun.star.xml.xpath.XPathAPI" }; + } + + OUString SAL_CALL CXPathAPI::getImplementationName() + { + return "com.sun.star.comp.xml.xpath.XPathAPI"; + } + + sal_Bool SAL_CALL CXPathAPI::supportsService(const OUString& aServiceName) + { + return cppu::supportsService(this, aServiceName); + } + + void SAL_CALL CXPathAPI::registerNS( + const OUString& aPrefix, + const OUString& aURI) + { + std::scoped_lock const g(m_Mutex); + + m_nsmap.emplace(aPrefix, aURI); + } + + void SAL_CALL CXPathAPI::unregisterNS( + const OUString& aPrefix, + const OUString& aURI) + { + std::scoped_lock const g(m_Mutex); + + if ((m_nsmap.find(aPrefix))->second == aURI) { + m_nsmap.erase(aPrefix); + } + } + + // register all namespaces stored in the namespace list for this object + // with the current xpath evaluation context + static void lcl_registerNamespaces( + xmlXPathContextPtr ctx, + const nsmap_t& nsmap) + { + OString oprefix, ouri; + for (const auto& rEntry : nsmap) + { + oprefix = OUStringToOString(rEntry.first, RTL_TEXTENCODING_UTF8); + ouri = OUStringToOString(rEntry.second, RTL_TEXTENCODING_UTF8); + xmlChar const *p = reinterpret_cast<xmlChar const *>(oprefix.getStr()); + xmlChar const *u = reinterpret_cast<xmlChar const *>(ouri.getStr()); + (void)xmlXPathRegisterNs(ctx, p, u); + } + } + + // get all ns decls on a node (and parent nodes, if any) + static void lcl_collectNamespaces( + nsmap_t & rNamespaces, Reference< XNode > const& xNamespaceNode) + { + DOM::CNode *const pCNode(comphelper::getFromUnoTunnel<DOM::CNode>(xNamespaceNode)); + if (!pCNode) { throw RuntimeException(); } + + ::osl::MutexGuard const g(pCNode->GetOwnerDocument().GetMutex()); + + xmlNodePtr pNode = pCNode->GetNodePtr(); + while (pNode != nullptr) { + xmlNsPtr curDef = pNode->nsDef; + while (curDef != nullptr) { + const xmlChar* pHref = curDef->href; + OUString aURI(reinterpret_cast<char const *>(pHref), strlen(reinterpret_cast<char const *>(pHref)), RTL_TEXTENCODING_UTF8); + const xmlChar* pPre = curDef->prefix; + OUString aPrefix(reinterpret_cast<char const *>(pPre), strlen(reinterpret_cast<char const *>(pPre)), RTL_TEXTENCODING_UTF8); + // we could already have this prefix from a child node + rNamespaces.emplace(aPrefix, aURI); + curDef = curDef->next; + } + pNode = pNode->parent; + } + } + + static void lcl_collectRegisterNamespaces( + CXPathAPI & rAPI, Reference< XNode > const& xNamespaceNode) + { + nsmap_t namespaces; + lcl_collectNamespaces(namespaces, xNamespaceNode); + for (const auto& rEntry : namespaces) + { + rAPI.registerNS(rEntry.first, rEntry.second); + } + } + + // register function and variable lookup functions with the current + // xpath evaluation context + static void lcl_registerExtensions( + xmlXPathContextPtr ctx, + const extensions_t& extensions) + { + for (const auto& rExtensionRef : extensions) + { + Libxml2ExtensionHandle aHandle = rExtensionRef->getLibxml2ExtensionHandle(); + if ( aHandle.functionLookupFunction != 0 ) + { + xmlXPathRegisterFuncLookup(ctx, + 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, + reinterpret_cast<xmlXPathVariableLookupFunc>( + sal::static_int_cast<sal_IntPtr>(aHandle.variableLookupFunction)), + reinterpret_cast<void*>( + sal::static_int_cast<sal_IntPtr>(aHandle.variableData))); + } + } + } + + /** + * Use an XPath string to select a nodelist. + */ + Reference< XNodeList > SAL_CALL CXPathAPI::selectNodeList( + const Reference< XNode >& contextNode, + const OUString& expr) + { + Reference< XXPathObject > xobj = eval(contextNode, expr); + return xobj->getNodeList(); + } + + /** + * same as selectNodeList but registers all name space declarations found on namespaceNode + */ + Reference< XNodeList > SAL_CALL CXPathAPI::selectNodeListNS( + const Reference< XNode >& contextNode, + const OUString& expr, + const Reference< XNode >& namespaceNode) + { + lcl_collectRegisterNamespaces(*this, namespaceNode); + return selectNodeList(contextNode, expr); + } + + /** + * Same as selectNodeList but returns the first node (if any) + */ + Reference< XNode > SAL_CALL CXPathAPI::selectSingleNode( + const Reference< XNode >& contextNode, + const OUString& expr) + { + Reference< XNodeList > aList = selectNodeList(contextNode, expr); + Reference< XNode > aNode = aList->item(0); + return aNode; + } + + /** + * Same as selectSingleNode but registers all namespaces declared on + * namespaceNode + */ + Reference< XNode > SAL_CALL CXPathAPI::selectSingleNodeNS( + const Reference< XNode >& contextNode, + const OUString& expr, + const Reference< XNode >& namespaceNode ) + { + lcl_collectRegisterNamespaces(*this, namespaceNode); + return selectSingleNode(contextNode, expr); + } + + static OUString make_error_message(xmlErrorPtr pError) + { + OUStringBuffer buf; + if (pError) { + if (pError->message) { + buf.appendAscii(pError->message); + } + int line = pError->line; + if (line) { + buf.append("Line: "); + buf.append(static_cast<sal_Int32>(line)); + buf.append("\n"); + } + int column = pError->int2; + if (column) { + buf.append("Column: "); + buf.append(static_cast<sal_Int32>(column)); + buf.append("\n"); + } + } else { + buf.append("no error argument!"); + } + OUString msg = buf.makeStringAndClear(); + return msg; + } + + extern "C" { + +#if defined __GNUC__ + __attribute__ ((format (printf, 2, 3))) +#endif + static void generic_error_func(void *, const char *format, ...) + { + char str[1000]; + va_list args; + + va_start(args, format); +#ifdef _WIN32 +#define vsnprintf _vsnprintf +#endif + vsnprintf(str, sizeof(str), format, args); + va_end(args); + + SAL_WARN("unoxml", "libxml2 error: " << str); + } + + static void structured_error_func(void *, xmlErrorPtr error) + { + SAL_WARN("unoxml", "libxml2 error: " << make_error_message(error)); + } + + } // extern "C" + + /** + * evaluates an XPath string. relative XPath expressions are evaluated relative to + * the context Node + */ + Reference< XXPathObject > SAL_CALL CXPathAPI::eval( + Reference< XNode > const& xContextNode, + const OUString& expr) + { + if (!xContextNode.is()) { throw RuntimeException(); } + + nsmap_t nsmap; + extensions_t extensions; + + { + std::scoped_lock const g(m_Mutex); + nsmap = m_nsmap; + extensions = m_extensions; + } + + // get the node and document + ::rtl::Reference<DOM::CDocument> const pCDoc( + dynamic_cast<DOM::CDocument*>( comphelper::getFromUnoTunnel<DOM::CNode>( + xContextNode->getOwnerDocument()))); + if (!pCDoc.is()) { throw RuntimeException(); } + + DOM::CNode *const pCNode = comphelper::getFromUnoTunnel<DOM::CNode>(xContextNode); + if (!pCNode) { throw RuntimeException(); } + + ::osl::MutexGuard const g(pCDoc->GetMutex()); // lock the document! + + xmlNodePtr const pNode = pCNode->GetNodePtr(); + if (!pNode) { throw RuntimeException(); } + 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 */ + std::shared_ptr<xmlXPathContext> const xpathCtx( + xmlXPathNewContext(pDoc), xmlXPathFreeContext); + if (xpathCtx == nullptr) { throw XPathException(); } + + // set context node + xpathCtx->node = pNode; + // error handling + xpathCtx->error = structured_error_func; + xmlSetGenericErrorFunc(nullptr, generic_error_func); + + // register namespaces and extension + lcl_registerNamespaces(xpathCtx.get(), nsmap); + lcl_registerExtensions(xpathCtx.get(), extensions); + + /* run the query */ + OString o1 = OUStringToOString(expr, RTL_TEXTENCODING_UTF8); + xmlChar const *pStr = reinterpret_cast<xmlChar const *>(o1.getStr()); + std::shared_ptr<xmlXPathObject> const xpathObj( + xmlXPathEval(pStr, xpathCtx.get()), xmlXPathFreeObject); + xmlSetGenericErrorFunc(nullptr, nullptr); + if (nullptr == xpathObj) { + // OSL_ENSURE(xpathCtx->lastError == NULL, xpathCtx->lastError->message); + throw XPathException(); + } + Reference<XXPathObject> const xObj( + new CXPathObject(pCDoc, pCDoc->GetMutex(), xpathObj)); + return xObj; + } + + /** + * 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) + { + lcl_collectRegisterNamespaces(*this, namespaceNode); + return eval(contextNode, expr); + } + + /** + * 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) + { + std::scoped_lock const g(m_Mutex); + + // get extension from service manager + Reference< XXPathExtension > const xExtension( + m_xContext->getServiceManager()->createInstanceWithContext(aName, m_xContext), UNO_QUERY_THROW); + m_extensions.push_back(xExtension); + } + + /** + * registers the given extension instance to be used by XPath evaluations performed through this + * XPathAPI instance + */ + void SAL_CALL CXPathAPI::registerExtensionInstance( + Reference< XXPathExtension> const& xExtension) + { + if (!xExtension.is()) { + throw RuntimeException(); + } + std::scoped_lock const g(m_Mutex); + m_extensions.push_back( xExtension ); + } +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +unoxml_CXPathAPI_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new XPath::CXPathAPI(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unoxml/source/xpath/xpathapi.hxx b/unoxml/source/xpath/xpathapi.hxx new file mode 100644 index 000000000..bb37922c8 --- /dev/null +++ b/unoxml/source/xpath/xpathapi.hxx @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <map> +#include <mutex> +#include <vector> + +#include <sal/types.h> + +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/Sequence.h> + +#include <com/sun/star/xml/xpath/XXPathAPI.hpp> +#include <com/sun/star/xml/dom/XNode.hpp> +#include <com/sun/star/xml/dom/XNodeList.hpp> +#include <com/sun/star/xml/xpath/XXPathObject.hpp> +#include <com/sun/star/xml/xpath/XXPathExtension.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +namespace XPath +{ + typedef std::map<OUString, OUString> nsmap_t; + typedef std::vector< css::uno::Reference<css::xml::xpath::XXPathExtension> > extensions_t; + + typedef ::cppu::WeakImplHelper + < css::xml::xpath::XXPathAPI + , css::lang::XServiceInfo + > CXPathAPI_Base; + + class CXPathAPI + : public CXPathAPI_Base + { + + private: + std::mutex m_Mutex; + nsmap_t m_nsmap; + const css::uno::Reference< css::uno::XComponentContext > m_xContext; + extensions_t m_extensions; + + public: + // ctor + explicit CXPathAPI( const css::uno::Reference< css::uno::XComponentContext >& ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override; + + + // --- XXPathAPI --- + + virtual void SAL_CALL registerNS(const OUString& aPrefix, const OUString& aURI) override; + + virtual void SAL_CALL unregisterNS(const OUString& aPrefix, const OUString& aURI) override; + + /** + Use an XPath string to select a nodelist. + */ + virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL selectNodeList(const css::uno::Reference< css::xml::dom::XNode >& contextNode, const OUString& str) override; + + /** + Use an XPath string to select a nodelist. + */ + virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL selectNodeListNS(const css::uno::Reference< css::xml::dom::XNode >& contextNode, const OUString& str, const css::uno::Reference< css::xml::dom::XNode >& namespaceNode) override; + + /** + Use an XPath string to select a single node. + */ + virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL selectSingleNode(const css::uno::Reference< css::xml::dom::XNode >& contextNode, const OUString& str) override; + + /** + Use an XPath string to select a single node. + */ + virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL selectSingleNodeNS(const css::uno::Reference< css::xml::dom::XNode >& contextNode, const OUString& str, const css::uno::Reference< css::xml::dom::XNode >& namespaceNode) override; + + virtual css::uno::Reference< css::xml::xpath::XXPathObject > SAL_CALL eval(const css::uno::Reference< css::xml::dom::XNode >& contextNode, const OUString& str) override; + + virtual css::uno::Reference< css::xml::xpath::XXPathObject > SAL_CALL evalNS(const css::uno::Reference< css::xml::dom::XNode >& contextNode, const OUString& str, const css::uno::Reference< css::xml::dom::XNode >& namespaceNode) override; + + virtual void SAL_CALL registerExtension(const OUString& aName) override; + virtual void SAL_CALL registerExtensionInstance(const css::uno::Reference< css::xml::xpath::XXPathExtension>& aExtension) override; + + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unoxml/source/xpath/xpathobject.cxx b/unoxml/source/xpath/xpathobject.cxx new file mode 100644 index 000000000..1184129a0 --- /dev/null +++ b/unoxml/source/xpath/xpathobject.cxx @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "xpathobject.hxx" + +#include <string.h> + +#include "../dom/document.hxx" +#include "nodelist.hxx" + +using namespace css::uno; +using namespace css::xml::dom; +using namespace css::xml::xpath; + +namespace XPath +{ + static XPathObjectType lcl_GetType(xmlXPathObjectPtr const pXPathObj) + { + switch (pXPathObj->type) + { + case XPATH_UNDEFINED: + return XPathObjectType_XPATH_UNDEFINED; + case XPATH_NODESET: + return XPathObjectType_XPATH_NODESET; + case XPATH_BOOLEAN: + return XPathObjectType_XPATH_BOOLEAN; + case XPATH_NUMBER: + return XPathObjectType_XPATH_NUMBER; + case XPATH_STRING: + return XPathObjectType_XPATH_STRING; +#if LIBXML_VERSION < 21000 || defined(LIBXML_XPTR_LOCS_ENABLED) + case XPATH_POINT: + return XPathObjectType_XPATH_POINT; + case XPATH_RANGE: + return XPathObjectType_XPATH_RANGE; + case XPATH_LOCATIONSET: + return XPathObjectType_XPATH_LOCATIONSET; +#endif + case XPATH_USERS: + return XPathObjectType_XPATH_USERS; + case XPATH_XSLT_TREE: + return XPathObjectType_XPATH_XSLT_TREE; + default: + return XPathObjectType_XPATH_UNDEFINED; + } + } + + CXPathObject::CXPathObject( + ::rtl::Reference<DOM::CDocument> const& pDocument, + ::osl::Mutex & rMutex, + std::shared_ptr<xmlXPathObject> const& pXPathObj) + : m_pDocument(pDocument) + , m_rMutex(rMutex) + , m_pXPathObj(pXPathObj) + , m_XPathObjectType(lcl_GetType(pXPathObj.get())) + { + } + + /** + get object type + */ + XPathObjectType CXPathObject::getObjectType() + { + return m_XPathObjectType; + } + + /** + get the nodes from a nodelist type object + */ + Reference< XNodeList > SAL_CALL + CXPathObject::getNodeList() + { + ::osl::MutexGuard const g(m_rMutex); + + Reference< XNodeList > const xRet( + new CNodeList(m_pDocument, m_rMutex, m_pXPathObj)); + return xRet; + } + + /** + get value of a boolean object + */ + sal_Bool SAL_CALL CXPathObject::getBoolean() + { + ::osl::MutexGuard const g(m_rMutex); + + return xmlXPathCastToBoolean(m_pXPathObj.get()) != 0; + } + + /** + get number as byte + */ + sal_Int8 SAL_CALL CXPathObject::getByte() + { + ::osl::MutexGuard const g(m_rMutex); + + return static_cast<sal_Int8>(xmlXPathCastToNumber(m_pXPathObj.get())); + } + + /** + get number as short + */ + sal_Int16 SAL_CALL CXPathObject::getShort() + { + ::osl::MutexGuard const g(m_rMutex); + + return static_cast<sal_Int16>(xmlXPathCastToNumber(m_pXPathObj.get())); + } + + /** + get number as long + */ + sal_Int32 SAL_CALL CXPathObject::getLong() + { + ::osl::MutexGuard const g(m_rMutex); + + return static_cast<sal_Int32>(xmlXPathCastToNumber(m_pXPathObj.get())); + } + + /** + get number as hyper + */ + sal_Int64 SAL_CALL CXPathObject::getHyper() + { + ::osl::MutexGuard const g(m_rMutex); + + return static_cast<sal_Int64>(xmlXPathCastToNumber(m_pXPathObj.get())); + } + + /** + get number as float + */ + float SAL_CALL CXPathObject::getFloat() + { + ::osl::MutexGuard const g(m_rMutex); + + return static_cast<float>(xmlXPathCastToNumber(m_pXPathObj.get())); + } + + /** + get number as double + */ + double SAL_CALL CXPathObject::getDouble() + { + ::osl::MutexGuard const g(m_rMutex); + + return xmlXPathCastToNumber(m_pXPathObj.get()); + } + + /** + get string value + */ + OUString SAL_CALL CXPathObject::getString() + { + ::osl::MutexGuard const g(m_rMutex); + + std::shared_ptr<xmlChar const> str( + xmlXPathCastToString(m_pXPathObj.get()), xmlFree); + char const*const pS(reinterpret_cast<char const*>(str.get())); + return OUString(pS, strlen(pS), RTL_TEXTENCODING_UTF8); + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/unoxml/source/xpath/xpathobject.hxx b/unoxml/source/xpath/xpathobject.hxx new file mode 100644 index 000000000..41a8e45a0 --- /dev/null +++ b/unoxml/source/xpath/xpathobject.hxx @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <memory> + +#include <libxml/xpath.h> + +#include <sal/types.h> +#include <rtl/ref.hxx> + +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/xml/dom/XNodeList.hpp> +#include <com/sun/star/xml/xpath/XXPathObject.hpp> + +#include "../dom/document.hxx" + +namespace DOM { + class CDocument; +} + +namespace XPath +{ + class CXPathObject : public cppu::WeakImplHelper< css::xml::xpath::XXPathObject > + { + private: + ::rtl::Reference< DOM::CDocument > const m_pDocument; + ::osl::Mutex & m_rMutex; + std::shared_ptr<xmlXPathObject> const m_pXPathObj; + css::xml::xpath::XPathObjectType const m_XPathObjectType; + + public: + CXPathObject( ::rtl::Reference<DOM::CDocument> const& pDocument, + ::osl::Mutex & rMutex, + std::shared_ptr<xmlXPathObject> const& pXPathObj); + + /** + get object type + */ + virtual css::xml::xpath::XPathObjectType SAL_CALL getObjectType() override; + + /** + get the nodes from a nodelist type object + */ + virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getNodeList() override; + + /** + get value of a boolean object + */ + virtual sal_Bool SAL_CALL getBoolean() override; + + /** + get number as byte + */ + virtual sal_Int8 SAL_CALL getByte() override; + + /** + get number as short + */ + virtual sal_Int16 SAL_CALL getShort() override; + + /** + get number as long + */ + virtual sal_Int32 SAL_CALL getLong() override; + + /** + get number as hyper + */ + virtual sal_Int64 SAL_CALL getHyper() override; + + /** + get number as float + */ + virtual float SAL_CALL getFloat() override; + + /** + get number as double + */ + virtual double SAL_CALL getDouble() override; + + /** + get string value + */ + virtual OUString SAL_CALL getString() override; + + }; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |