Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include "computedexpression.hxx"
22 : #include "unohelper.hxx"
23 : #include "evaluationcontext.hxx"
24 : #include "NameContainer.hxx"
25 :
26 : #include <com/sun/star/container/XNameContainer.hpp>
27 : #include <com/sun/star/uno/Sequence.hxx>
28 : #include <com/sun/star/xml/dom/NodeType.hpp>
29 : #include <com/sun/star/xml/dom/XNode.hpp>
30 : #include <com/sun/star/xml/xpath/XPathAPI.hpp>
31 : #include <com/sun/star/xml/xpath/XXPathObject.hpp>
32 : #include <com/sun/star/xml/xpath/XPathExtension.hpp>
33 : #include <com/sun/star/beans/NamedValue.hpp>
34 : #include <com/sun/star/lang/XInitialization.hpp>
35 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
36 : #include <com/sun/star/util/SearchAlgorithms.hpp>
37 :
38 : #include <osl/diagnose.h>
39 :
40 : #include <unotools/textsearch.hxx>
41 : #include <comphelper/processfactory.hxx>
42 :
43 : using com::sun::star::beans::NamedValue;
44 : using namespace com::sun::star::uno;
45 : using com::sun::star::lang::XInitialization;
46 : using com::sun::star::lang::XMultiServiceFactory;
47 : using com::sun::star::xml::dom::XNode;
48 : using com::sun::star::container::XNameContainer;
49 : using com::sun::star::xml::xpath::XPathAPI;
50 : using com::sun::star::xml::xpath::XXPathAPI;
51 : using com::sun::star::xml::xpath::XPathExtension;
52 : using com::sun::star::xml::xpath::XXPathExtension;
53 : using com::sun::star::xml::xpath::XXPathObject;
54 : using com::sun::star::xml::xpath::XPathObjectType_XPATH_UNDEFINED;
55 : using com::sun::star::util::SearchOptions;
56 : using com::sun::star::util::SearchAlgorithms_REGEXP;
57 :
58 :
59 : namespace xforms
60 : {
61 :
62 0 : ComputedExpression::ComputedExpression()
63 : : msExpression(),
64 : mbIsEmpty( true ),
65 : mbIsSimple( true ),
66 0 : mxResult()
67 : {
68 0 : }
69 :
70 0 : ComputedExpression::~ComputedExpression()
71 : {
72 0 : }
73 :
74 :
75 :
76 0 : void ComputedExpression::setExpression( const OUString& rExpression )
77 : {
78 : // set new expression, and clear pre-computed results
79 0 : msExpression = rExpression;
80 0 : mbIsEmpty = _checkExpression( " *" );
81 0 : mbIsSimple = false;
82 0 : mxResult.clear();
83 0 : }
84 :
85 :
86 0 : bool ComputedExpression::_checkExpression( const sal_Char* pExpression ) const
87 : {
88 : assert(pExpression && "no expression?");
89 :
90 : // call RegExp engine
91 0 : SearchOptions aSearchOptions;
92 0 : aSearchOptions.algorithmType = SearchAlgorithms_REGEXP;
93 0 : aSearchOptions.searchString = OUString( pExpression, strlen(pExpression), RTL_TEXTENCODING_ASCII_US );
94 0 : utl::TextSearch aTextSearch( aSearchOptions );
95 :
96 0 : sal_Int32 nLength = msExpression.getLength();
97 0 : sal_Int32 nStart = 0;
98 0 : sal_Int32 nEnd = nLength;
99 0 : bool nSearch = aTextSearch.SearchForward( msExpression, &nStart, &nEnd );
100 :
101 : // our expression is static only if 1) we found our regexp, and 2)
102 : // the regexp goes from beginning to end.
103 0 : return ( nLength == 0 || nSearch )
104 0 : && ( nStart == 0 && nEnd == nLength );
105 : }
106 :
107 0 : bool ComputedExpression::isSimpleExpression() const
108 : {
109 : // actual work is done by setExpression
110 0 : return mbIsEmpty || mbIsSimple;
111 : }
112 :
113 :
114 0 : bool ComputedExpression::_evaluate(
115 : const xforms::EvaluationContext& rContext,
116 : const OUString& sExpression )
117 : {
118 : OSL_ENSURE( rContext.mxContextNode.is(), "no context node in context" );
119 :
120 : // obtain value by evaluating XPath expression
121 0 : mxResult.clear();
122 : try
123 : {
124 0 : mxResult = _getXPathAPI(rContext)->eval( rContext.mxContextNode,
125 0 : sExpression );
126 : }
127 0 : catch( const Exception& )
128 : {
129 : ; // ignore exception -> mxResult will be empty
130 : }
131 :
132 0 : return hasValue();
133 : }
134 :
135 0 : bool ComputedExpression::evaluate( const EvaluationContext& rContext )
136 : {
137 : // for simple expression we don't need to re-evaluate (if we have
138 : // an older result); neither for empty expressions
139 0 : if( mbIsEmpty || (mxResult.is() && mbIsSimple) )
140 0 : return true;
141 :
142 0 : return _evaluate( rContext, _getExpressionForEvaluation() );
143 : }
144 :
145 :
146 0 : bool ComputedExpression::hasValue() const
147 : {
148 0 : return mxResult.is() &&
149 0 : mxResult->getObjectType() != XPathObjectType_XPATH_UNDEFINED;
150 : }
151 :
152 0 : void ComputedExpression::clear()
153 : {
154 0 : mxResult.clear();
155 0 : }
156 :
157 :
158 0 : OUString ComputedExpression::getString( const OUString& rDefault ) const
159 : {
160 0 : return mxResult.is() ? mxResult->getString() : rDefault;
161 : }
162 :
163 0 : bool ComputedExpression::getBool( bool bDefault ) const
164 : {
165 0 : return mxResult.is() ? mxResult->getBoolean() : bDefault;
166 : }
167 :
168 :
169 :
170 :
171 0 : Reference<XXPathAPI> ComputedExpression::_getXPathAPI(const xforms::EvaluationContext& aContext)
172 : {
173 : // create XPath API, then register namespaces
174 0 : Reference<XXPathAPI> xXPath( XPathAPI::create( comphelper::getProcessComponentContext() ) );
175 :
176 : // register xforms extension#
177 0 : Reference< XComponentContext > aComponentContext = comphelper::getProcessComponentContext();
178 0 : Reference< XXPathExtension > aExtension = XPathExtension::createWithModel(aComponentContext, aContext.mxModel, aContext.mxContextNode);
179 0 : xXPath->registerExtensionInstance(aExtension);
180 :
181 : // register namespaces
182 0 : if( aContext.mxNamespaces.is() )
183 : {
184 0 : Sequence<OUString> aPrefixes =aContext.mxNamespaces->getElementNames();
185 0 : sal_Int32 nCount = aPrefixes.getLength();
186 0 : const OUString* pPrefixes = aPrefixes.getConstArray();
187 0 : for( sal_Int32 i = 0; i < nCount; i++ )
188 : {
189 0 : const OUString* pNamePrefix = &pPrefixes[i];
190 0 : OUString sNameURL;
191 0 : aContext.mxNamespaces->getByName( *pNamePrefix ) >>= sNameURL;
192 0 : xXPath->registerNS( *pNamePrefix, sNameURL );
193 0 : }
194 : }
195 :
196 : // done, so return xXPath-object
197 0 : return xXPath;
198 : }
199 :
200 :
201 : } // namespace xforms
202 :
203 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|