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 <unotools/textsearch.hxx>
39 : #include <comphelper/processfactory.hxx>
40 :
41 : using com::sun::star::beans::NamedValue;
42 : using namespace com::sun::star::uno;
43 : using com::sun::star::lang::XInitialization;
44 : using com::sun::star::lang::XMultiServiceFactory;
45 : using com::sun::star::xml::dom::XNode;
46 : using com::sun::star::container::XNameContainer;
47 : using com::sun::star::xml::xpath::XPathAPI;
48 : using com::sun::star::xml::xpath::XXPathAPI;
49 : using com::sun::star::xml::xpath::XPathExtension;
50 : using com::sun::star::xml::xpath::XXPathExtension;
51 : using com::sun::star::xml::xpath::XXPathObject;
52 : using com::sun::star::xml::xpath::XPathObjectType_XPATH_UNDEFINED;
53 : using com::sun::star::util::SearchOptions;
54 : using com::sun::star::util::SearchAlgorithms_REGEXP;
55 :
56 :
57 : namespace xforms
58 : {
59 :
60 0 : ComputedExpression::ComputedExpression()
61 : : msExpression(),
62 : mbIsEmpty( true ),
63 : mbIsSimple( true ),
64 0 : mxResult()
65 : {
66 0 : }
67 :
68 0 : ComputedExpression::~ComputedExpression()
69 : {
70 0 : }
71 :
72 :
73 0 : OUString ComputedExpression::getExpression() const
74 : {
75 0 : return msExpression;
76 : }
77 :
78 0 : void ComputedExpression::setExpression( const OUString& rExpression )
79 : {
80 : // set new expression, and clear pre-computed results
81 0 : msExpression = rExpression;
82 0 : mbIsEmpty = _checkExpression( " *" );
83 0 : mbIsSimple = false;
84 0 : mxResult.clear();
85 0 : }
86 :
87 :
88 0 : bool ComputedExpression::_checkExpression( const sal_Char* pExpression ) const
89 : {
90 : OSL_ENSURE( pExpression != NULL, "no expression?" );
91 :
92 : // call RegExp engine
93 0 : SearchOptions aSearchOptions;
94 0 : aSearchOptions.algorithmType = SearchAlgorithms_REGEXP;
95 0 : aSearchOptions.searchString = OUString( pExpression, strlen(pExpression), RTL_TEXTENCODING_ASCII_US );
96 0 : utl::TextSearch aTextSearch( aSearchOptions );
97 :
98 0 : sal_Int32 nLength = msExpression.getLength();
99 0 : sal_Int32 nStart = 0;
100 0 : sal_Int32 nEnd = nLength;
101 0 : bool nSearch = aTextSearch.SearchForward( msExpression, &nStart, &nEnd );
102 :
103 : // our expression is static only if 1) we found our regexp, and 2)
104 : // the regexp goes from beginning to end.
105 0 : return ( nLength == 0 || nSearch )
106 0 : && ( nStart == 0 && nEnd == nLength );
107 : }
108 :
109 : /// do we have an actual expression?
110 0 : bool ComputedExpression::isEmptyExpression() const
111 : {
112 0 : return mbIsEmpty;
113 : }
114 :
115 0 : bool ComputedExpression::isSimpleExpression() const
116 : {
117 : // actual work is done by setExpression
118 0 : return mbIsEmpty || mbIsSimple;
119 : }
120 :
121 :
122 0 : const OUString ComputedExpression::_getExpressionForEvaluation() const
123 : {
124 : // the default implementation is to do nothing...
125 0 : return msExpression;
126 : }
127 :
128 0 : bool ComputedExpression::_evaluate(
129 : const xforms::EvaluationContext& rContext,
130 : const OUString& sExpression )
131 : {
132 : OSL_ENSURE( rContext.mxContextNode.is(), "no context node in context" );
133 :
134 : // obtain value by evaluating XPath expression
135 0 : mxResult.clear();
136 : try
137 : {
138 0 : mxResult = _getXPathAPI(rContext)->eval( rContext.mxContextNode,
139 0 : sExpression );
140 : }
141 0 : catch( const Exception& )
142 : {
143 : ; // ignore exception -> mxResult will be empty
144 : }
145 :
146 0 : return hasValue();
147 : }
148 :
149 0 : bool ComputedExpression::evaluate( const EvaluationContext& rContext )
150 : {
151 : // for simple expression we don't need to re-evaluate (if we have
152 : // an older result); neither for empty expressions
153 0 : if( mbIsEmpty || (mxResult.is() && mbIsSimple) )
154 0 : return true;
155 :
156 0 : return _evaluate( rContext, _getExpressionForEvaluation() );
157 : }
158 :
159 :
160 0 : bool ComputedExpression::hasValue() const
161 : {
162 0 : return mxResult.is() &&
163 0 : mxResult->getObjectType() != XPathObjectType_XPATH_UNDEFINED;
164 : }
165 :
166 0 : void ComputedExpression::clear()
167 : {
168 0 : mxResult.clear();
169 0 : }
170 :
171 0 : Reference<XXPathObject> ComputedExpression::getXPath() const
172 : {
173 0 : return mxResult;
174 : }
175 :
176 0 : OUString ComputedExpression::getString( const OUString& rDefault ) const
177 : {
178 0 : return mxResult.is() ? mxResult->getString() : rDefault;
179 : }
180 :
181 0 : bool ComputedExpression::getBool( bool bDefault ) const
182 : {
183 0 : return mxResult.is() ? mxResult->getBoolean() : bDefault;
184 : }
185 :
186 :
187 :
188 :
189 0 : Reference<XXPathAPI> ComputedExpression::_getXPathAPI(const xforms::EvaluationContext& aContext)
190 : {
191 : // create XPath API, then register namespaces
192 0 : Reference<XXPathAPI> xXPath( XPathAPI::create( comphelper::getProcessComponentContext() ) );
193 :
194 : // register xforms extension#
195 0 : Reference< XComponentContext > aComponentContext = comphelper::getProcessComponentContext();
196 0 : Reference< XXPathExtension > aExtension = XPathExtension::createWithModel(aComponentContext, aContext.mxModel, aContext.mxContextNode);
197 0 : xXPath->registerExtensionInstance(aExtension);
198 :
199 : // register namespaces
200 0 : if( aContext.mxNamespaces.is() )
201 : {
202 0 : Sequence<OUString> aPrefixes =aContext.mxNamespaces->getElementNames();
203 0 : sal_Int32 nCount = aPrefixes.getLength();
204 0 : const OUString* pPrefixes = aPrefixes.getConstArray();
205 0 : for( sal_Int32 i = 0; i < nCount; i++ )
206 : {
207 0 : const OUString* pNamePrefix = &pPrefixes[i];
208 0 : OUString sNameURL;
209 0 : aContext.mxNamespaces->getByName( *pNamePrefix ) >>= sNameURL;
210 0 : xXPath->registerNS( *pNamePrefix, sNameURL );
211 0 : }
212 : }
213 :
214 : // done, so return xXPath-object
215 0 : return xXPath;
216 : }
217 :
218 :
219 : } // namespace xforms
220 :
221 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|