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 :
74 0 : void ComputedExpression::setExpression( const OUString& rExpression )
75 : {
76 : // set new expression, and clear pre-computed results
77 0 : msExpression = rExpression;
78 0 : mbIsEmpty = _checkExpression( " *" );
79 0 : mbIsSimple = false;
80 0 : mxResult.clear();
81 0 : }
82 :
83 :
84 0 : bool ComputedExpression::_checkExpression( const sal_Char* pExpression ) const
85 : {
86 : assert(pExpression && "no expression?");
87 :
88 : // call RegExp engine
89 0 : SearchOptions aSearchOptions;
90 0 : aSearchOptions.algorithmType = SearchAlgorithms_REGEXP;
91 0 : aSearchOptions.searchString = OUString( pExpression, strlen(pExpression), RTL_TEXTENCODING_ASCII_US );
92 0 : utl::TextSearch aTextSearch( aSearchOptions );
93 :
94 0 : sal_Int32 nLength = msExpression.getLength();
95 0 : sal_Int32 nStart = 0;
96 0 : sal_Int32 nEnd = nLength;
97 0 : bool nSearch = aTextSearch.SearchForward( msExpression, &nStart, &nEnd );
98 :
99 : // our expression is static only if 1) we found our regexp, and 2)
100 : // the regexp goes from beginning to end.
101 0 : return ( nLength == 0 || nSearch )
102 0 : && ( nStart == 0 && nEnd == nLength );
103 : }
104 :
105 0 : bool ComputedExpression::isSimpleExpression() const
106 : {
107 : // actual work is done by setExpression
108 0 : return mbIsEmpty || mbIsSimple;
109 : }
110 :
111 :
112 0 : bool ComputedExpression::_evaluate(
113 : const xforms::EvaluationContext& rContext,
114 : const OUString& sExpression )
115 : {
116 : OSL_ENSURE( rContext.mxContextNode.is(), "no context node in context" );
117 :
118 : // obtain value by evaluating XPath expression
119 0 : mxResult.clear();
120 : try
121 : {
122 0 : mxResult = _getXPathAPI(rContext)->eval( rContext.mxContextNode,
123 0 : sExpression );
124 : }
125 0 : catch( const Exception& )
126 : {
127 : ; // ignore exception -> mxResult will be empty
128 : }
129 :
130 0 : return hasValue();
131 : }
132 :
133 0 : bool ComputedExpression::evaluate( const EvaluationContext& rContext )
134 : {
135 : // for simple expression we don't need to re-evaluate (if we have
136 : // an older result); neither for empty expressions
137 0 : if( mbIsEmpty || (mxResult.is() && mbIsSimple) )
138 0 : return true;
139 :
140 0 : return _evaluate( rContext, _getExpressionForEvaluation() );
141 : }
142 :
143 :
144 0 : bool ComputedExpression::hasValue() const
145 : {
146 0 : return mxResult.is() &&
147 0 : mxResult->getObjectType() != XPathObjectType_XPATH_UNDEFINED;
148 : }
149 :
150 0 : void ComputedExpression::clear()
151 : {
152 0 : mxResult.clear();
153 0 : }
154 :
155 :
156 0 : OUString ComputedExpression::getString( const OUString& rDefault ) const
157 : {
158 0 : return mxResult.is() ? mxResult->getString() : rDefault;
159 : }
160 :
161 0 : bool ComputedExpression::getBool( bool bDefault ) const
162 : {
163 0 : return mxResult.is() ? mxResult->getBoolean() : bDefault;
164 : }
165 :
166 :
167 :
168 :
169 0 : Reference<XXPathAPI> ComputedExpression::_getXPathAPI(const xforms::EvaluationContext& aContext)
170 : {
171 : // create XPath API, then register namespaces
172 0 : Reference<XXPathAPI> xXPath( XPathAPI::create( comphelper::getProcessComponentContext() ) );
173 :
174 : // register xforms extension#
175 0 : Reference< XComponentContext > aComponentContext = comphelper::getProcessComponentContext();
176 0 : Reference< XXPathExtension > aExtension = XPathExtension::createWithModel(aComponentContext, aContext.mxModel, aContext.mxContextNode);
177 0 : xXPath->registerExtensionInstance(aExtension);
178 :
179 : // register namespaces
180 0 : if( aContext.mxNamespaces.is() )
181 : {
182 0 : Sequence<OUString> aPrefixes =aContext.mxNamespaces->getElementNames();
183 0 : sal_Int32 nCount = aPrefixes.getLength();
184 0 : const OUString* pPrefixes = aPrefixes.getConstArray();
185 0 : for( sal_Int32 i = 0; i < nCount; i++ )
186 : {
187 0 : const OUString* pNamePrefix = &pPrefixes[i];
188 0 : OUString sNameURL;
189 0 : aContext.mxNamespaces->getByName( *pNamePrefix ) >>= sNameURL;
190 0 : xXPath->registerNS( *pNamePrefix, sNameURL );
191 0 : }
192 : }
193 :
194 : // done, so return xXPath-object
195 0 : return xXPath;
196 : }
197 :
198 :
199 : } // namespace xforms
200 :
201 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|