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