1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_forms.hxx" 30 31 #include "computedexpression.hxx" 32 #include "unohelper.hxx" 33 #include "evaluationcontext.hxx" 34 #include "NameContainer.hxx" 35 36 #include <com/sun/star/container/XNameContainer.hpp> 37 #include <com/sun/star/uno/Sequence.hxx> 38 #include <com/sun/star/xml/dom/NodeType.hpp> 39 #include <com/sun/star/xml/dom/XNode.hpp> 40 #include <com/sun/star/xml/xpath/XXPathAPI.hpp> 41 #include <com/sun/star/xml/xpath/XXPathObject.hpp> 42 #include <com/sun/star/xml/xpath/XXPathExtension.hpp> 43 #include <com/sun/star/beans/NamedValue.hpp> 44 #include <com/sun/star/lang/XInitialization.hpp> 45 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 46 #include <com/sun/star/util/SearchAlgorithms.hpp> 47 48 #include <unotools/textsearch.hxx> 49 #include <comphelper/processfactory.hxx> 50 51 using rtl::OUString; 52 using com::sun::star::beans::NamedValue; 53 using com::sun::star::uno::Any; 54 using com::sun::star::uno::Reference; 55 using com::sun::star::uno::Sequence; 56 using com::sun::star::lang::XInitialization; 57 using com::sun::star::lang::XMultiServiceFactory; 58 using com::sun::star::xml::dom::XNode; 59 using com::sun::star::container::XNameContainer; 60 using com::sun::star::xml::xpath::XXPathAPI; 61 using com::sun::star::xml::xpath::XXPathExtension; 62 using com::sun::star::xml::xpath::XXPathObject; 63 using com::sun::star::uno::RuntimeException; 64 using com::sun::star::uno::Exception; 65 using com::sun::star::uno::UNO_QUERY_THROW; 66 using com::sun::star::xml::xpath::XPathObjectType_XPATH_UNDEFINED; 67 using com::sun::star::util::SearchOptions; 68 using com::sun::star::util::SearchAlgorithms_REGEXP; 69 70 71 namespace xforms 72 { 73 74 ComputedExpression::ComputedExpression() 75 : msExpression(), 76 mbIsEmpty( true ), 77 mbIsSimple( true ), 78 mxResult() 79 { 80 } 81 82 ComputedExpression::~ComputedExpression() 83 { 84 } 85 86 87 OUString ComputedExpression::getExpression() const 88 { 89 return msExpression; 90 } 91 92 void ComputedExpression::setExpression( const OUString& rExpression ) 93 { 94 // set new expression, and clear pre-computed results 95 msExpression = rExpression; 96 mbIsEmpty = _checkExpression( " *" ); 97 mbIsSimple = false; 98 mxResult.clear(); 99 } 100 101 102 bool ComputedExpression::_checkExpression( const sal_Char* pExpression ) const 103 { 104 OSL_ENSURE( pExpression != NULL, "no expression?" ); 105 106 // call RegExp engine 107 SearchOptions aSearchOptions; 108 aSearchOptions.algorithmType = SearchAlgorithms_REGEXP; 109 aSearchOptions.searchString = String( pExpression, RTL_TEXTENCODING_ASCII_US ); 110 utl::TextSearch aTextSearch( aSearchOptions ); 111 112 xub_StrLen nLength = 113 static_cast<xub_StrLen>( msExpression.getLength() ); 114 xub_StrLen nStart = 0; 115 xub_StrLen nEnd = nLength; 116 int nSearch = aTextSearch.SearchFrwrd( msExpression, &nStart, &nEnd ); 117 118 // our expression is static only if 1) we found our regexp, and 2) 119 // the regexp goes from beginning to end. 120 return ( nLength == 0 || nSearch != 0 ) 121 && ( nStart == 0 && nEnd == nLength ); 122 } 123 124 /// do we have an actual expression? 125 bool ComputedExpression::isEmptyExpression() const 126 { 127 return mbIsEmpty; 128 } 129 130 bool ComputedExpression::isSimpleExpression() const 131 { 132 // actual work is done by setExpression 133 return mbIsEmpty || mbIsSimple; 134 } 135 136 137 const OUString ComputedExpression::_getExpressionForEvaluation() const 138 { 139 // the default implementation is to do nothing... 140 return msExpression; 141 } 142 143 bool ComputedExpression::_evaluate( 144 const xforms::EvaluationContext& rContext, 145 const OUString& sExpression ) 146 { 147 OSL_ENSURE( rContext.mxContextNode.is(), "no context node in context" ); 148 149 // obtain value by evaluating XPath expression 150 mxResult.clear(); 151 try 152 { 153 mxResult = _getXPathAPI(rContext)->eval( rContext.mxContextNode, 154 sExpression ); 155 } 156 catch( const Exception& ) 157 { 158 ; // ignore exception -> mxResult will be empty 159 } 160 161 return hasValue(); 162 } 163 164 bool ComputedExpression::evaluate( const EvaluationContext& rContext ) 165 { 166 // for simple expression we don't need to re-evaluate (if we have 167 // an older result); neither for empty expressions 168 if( mbIsEmpty || (mxResult.is() && mbIsSimple) ) 169 return true; 170 171 return _evaluate( rContext, _getExpressionForEvaluation() ); 172 } 173 174 175 bool ComputedExpression::hasValue() const 176 { 177 return mxResult.is() && 178 mxResult->getObjectType() != XPathObjectType_XPATH_UNDEFINED; 179 } 180 181 void ComputedExpression::clear() 182 { 183 mxResult.clear(); 184 } 185 186 Reference<XXPathObject> ComputedExpression::getXPath() 187 { 188 return mxResult; 189 } 190 191 OUString ComputedExpression::getString( const rtl::OUString& rDefault ) const 192 { 193 return mxResult.is() ? mxResult->getString() : rDefault; 194 } 195 196 bool ComputedExpression::getBool( bool bDefault ) const 197 { 198 return mxResult.is() ? mxResult->getBoolean() : bDefault; 199 } 200 201 202 203 204 Reference<XXPathAPI> ComputedExpression::_getXPathAPI(const xforms::EvaluationContext& aContext) 205 { 206 // create XPath API, then register namespaces 207 Reference<XXPathAPI> xXPath( createInstance( 208 OUSTRING( "com.sun.star.xml.xpath.XPathAPI" ) ), 209 UNO_QUERY_THROW ); 210 OSL_ENSURE( xXPath.is(), "cannot get XPath API" ); 211 212 // register xforms extension# 213 Sequence< Any > aSequence(2); 214 NamedValue aValue; 215 aValue.Name = OUSTRING("Model"); 216 aValue.Value <<= aContext.mxModel; 217 aSequence[0] <<= aValue; 218 aValue.Name = OUSTRING("ContextNode"); 219 aValue.Value <<= aContext.mxContextNode; 220 aSequence[1] <<= aValue; 221 Reference<XMultiServiceFactory> aFactory = comphelper::getProcessServiceFactory(); 222 Reference< XXPathExtension > aExtension( aFactory->createInstanceWithArguments( 223 OUSTRING( "com.sun.star.comp.xml.xpath.XFormsExtension"), aSequence), UNO_QUERY_THROW); 224 xXPath->registerExtensionInstance(aExtension); 225 226 // register namespaces 227 if( aContext.mxNamespaces.is() ) 228 { 229 Sequence<OUString> aPrefixes =aContext.mxNamespaces->getElementNames(); 230 sal_Int32 nCount = aPrefixes.getLength(); 231 const OUString* pPrefixes = aPrefixes.getConstArray(); 232 for( sal_Int32 i = 0; i < nCount; i++ ) 233 { 234 const OUString* pNamePrefix = &pPrefixes[i]; 235 OUString sNameURL; 236 aContext.mxNamespaces->getByName( *pNamePrefix ) >>= sNameURL; 237 xXPath->registerNS( *pNamePrefix, sNameURL ); 238 } 239 } 240 241 // done, so return xXPath-object 242 return xXPath; 243 } 244 245 246 } // namespace xforms 247