Quantum GIS API Documentation
1.8
|
00001 /*************************************************************************** 00002 qgsexpression.cpp 00003 ------------------- 00004 begin : August 2011 00005 copyright : (C) 2011 Martin Dobias 00006 email : wonder.sk at gmail dot com 00007 *************************************************************************** 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 ***************************************************************************/ 00015 00016 #include "qgsexpression.h" 00017 00018 #include <QtDebug> 00019 #include <QDomDocument> 00020 #include <QSettings> 00021 00022 #include <math.h> 00023 #include <limits> 00024 00025 #include "qgsdistancearea.h" 00026 #include "qgsfeature.h" 00027 #include "qgsgeometry.h" 00028 #include "qgslogger.h" 00029 00030 // from parser 00031 extern QgsExpression::Node* parseExpression( const QString& str, QString& parserErrorMsg ); 00032 00033 00035 // three-value logic 00036 00037 enum TVL 00038 { 00039 False, 00040 True, 00041 Unknown 00042 }; 00043 00044 static TVL AND[3][3] = 00045 { 00046 // false true unknown 00047 { False, False, False }, // false 00048 { False, True, Unknown }, // true 00049 { False, Unknown, Unknown } // unknown 00050 }; 00051 00052 static TVL OR[3][3] = 00053 { 00054 { False, True, Unknown }, // false 00055 { True, True, True }, // true 00056 { Unknown, True, Unknown } // unknown 00057 }; 00058 00059 static TVL NOT[3] = { True, False, Unknown }; 00060 00061 static QVariant tvl2variant( TVL v ) 00062 { 00063 switch ( v ) 00064 { 00065 case False: return 0; 00066 case True: return 1; 00067 case Unknown: 00068 default: 00069 return QVariant(); 00070 } 00071 } 00072 00073 #define TVL_True QVariant(1) 00074 #define TVL_False QVariant(0) 00075 #define TVL_Unknown QVariant() 00076 00078 // QVariant checks and conversions 00079 00080 inline bool isIntSafe( const QVariant& v ) 00081 { 00082 if ( v.type() == QVariant::Int ) return true; 00083 if ( v.type() == QVariant::Double ) return false; 00084 if ( v.type() == QVariant::String ) { bool ok; v.toString().toInt( &ok ); return ok; } 00085 return false; 00086 } 00087 inline bool isDoubleSafe( const QVariant& v ) 00088 { 00089 if ( v.type() == QVariant::Double || v.type() == QVariant::Int ) return true; 00090 if ( v.type() == QVariant::String ) { bool ok; v.toString().toDouble( &ok ); return ok; } 00091 return false; 00092 } 00093 00094 inline bool isNull( const QVariant& v ) { return v.isNull(); } 00095 00097 // evaluation error macros 00098 00099 #define ENSURE_NO_EVAL_ERROR { if (parent->hasEvalError()) return QVariant(); } 00100 #define SET_EVAL_ERROR(x) { parent->setEvalErrorString(x); return QVariant(); } 00101 00103 // operators 00104 00105 const char* QgsExpression::BinaryOperatorText[] = 00106 { 00107 "OR", "AND", 00108 "=", "<>", "<=", ">=", "<", ">", "~", "LIKE", "NOT LIKE", "ILIKE", "NOT ILIKE", "IS", "IS NOT", 00109 "+", "-", "*", "/", "%", "^", 00110 "||" 00111 }; 00112 00113 const char* QgsExpression::BinaryOgcOperatorText[] = 00114 { 00115 "Or", "And", 00116 "PropertyIsEqualTo", "PropertyIsNotEqualTo", 00117 "PropertyIsGreaterThanOrEqualTo", "PropertyIsLessThanOrEqualTo", 00118 "PropertyIsLessThan", "PropertyIsGreaterThan", 00119 "", "PropertyIsLike", "", "", "", 00120 "Add", "Sub", "Mul", "Div", "", "", 00121 "" 00122 }; 00123 00124 const char* QgsExpression::UnaryOperatorText[] = 00125 { 00126 "NOT", "-" 00127 }; 00128 00129 const char* QgsExpression::UnaryOgcOperatorText[] = 00130 { 00131 "Not", "" 00132 }; 00133 00135 // functions 00136 00137 // implicit conversion to string 00138 static QString getStringValue( const QVariant& value, QgsExpression* ) 00139 { 00140 return value.toString(); 00141 } 00142 00143 static double getDoubleValue( const QVariant& value, QgsExpression* parent ) 00144 { 00145 bool ok; 00146 double x = value.toDouble( &ok ); 00147 if ( !ok ) 00148 { 00149 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to double" ).arg( value.toString() ) ); 00150 return 0; 00151 } 00152 return x; 00153 } 00154 00155 static int getIntValue( const QVariant& value, QgsExpression* parent ) 00156 { 00157 bool ok; 00158 qint64 x = value.toLongLong( &ok ); 00159 if ( ok && x >= std::numeric_limits<int>::min() && x <= std::numeric_limits<int>::max() ) 00160 { 00161 return x; 00162 } 00163 else 00164 { 00165 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to int" ).arg( value.toString() ) ); 00166 return 0; 00167 } 00168 } 00169 00170 00171 // this handles also NULL values 00172 static TVL getTVLValue( const QVariant& value, QgsExpression* parent ) 00173 { 00174 // we need to convert to TVL 00175 if ( value.isNull() ) 00176 return Unknown; 00177 00178 if ( value.type() == QVariant::Int ) 00179 return value.toInt() != 0 ? True : False; 00180 00181 bool ok; 00182 double x = value.toDouble( &ok ); 00183 if ( !ok ) 00184 { 00185 parent->setEvalErrorString( QObject::tr( "Cannot convert '%1' to boolean" ).arg( value.toString() ) ); 00186 return Unknown; 00187 } 00188 return x != 0 ? True : False; 00189 } 00190 00192 00193 static QVariant fcnSqrt( const QVariantList& values, QgsFeature* /*f*/, QgsExpression* parent ) 00194 { 00195 double x = getDoubleValue( values.at( 0 ), parent ); 00196 return QVariant( sqrt( x ) ); 00197 } 00198 static QVariant fcnSin( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00199 { 00200 double x = getDoubleValue( values.at( 0 ), parent ); 00201 return QVariant( sin( x ) ); 00202 } 00203 static QVariant fcnCos( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00204 { 00205 double x = getDoubleValue( values.at( 0 ), parent ); 00206 return QVariant( cos( x ) ); 00207 } 00208 static QVariant fcnTan( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00209 { 00210 double x = getDoubleValue( values.at( 0 ), parent ); 00211 return QVariant( tan( x ) ); 00212 } 00213 static QVariant fcnAsin( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00214 { 00215 double x = getDoubleValue( values.at( 0 ), parent ); 00216 return QVariant( asin( x ) ); 00217 } 00218 static QVariant fcnAcos( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00219 { 00220 double x = getDoubleValue( values.at( 0 ), parent ); 00221 return QVariant( acos( x ) ); 00222 } 00223 static QVariant fcnAtan( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00224 { 00225 double x = getDoubleValue( values.at( 0 ), parent ); 00226 return QVariant( atan( x ) ); 00227 } 00228 static QVariant fcnAtan2( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00229 { 00230 double y = getDoubleValue( values.at( 0 ), parent ); 00231 double x = getDoubleValue( values.at( 1 ), parent ); 00232 return QVariant( atan2( y, x ) ); 00233 } 00234 static QVariant fcnExp( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00235 { 00236 double x = getDoubleValue( values.at( 0 ), parent ); 00237 return QVariant( exp( x ) ); 00238 } 00239 static QVariant fcnLn( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00240 { 00241 double x = getDoubleValue( values.at( 0 ), parent ); 00242 if ( x <= 0 ) 00243 return QVariant(); 00244 return QVariant( log( x ) ); 00245 } 00246 static QVariant fcnLog10( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00247 { 00248 double x = getDoubleValue( values.at( 0 ), parent ); 00249 if ( x <= 0 ) 00250 return QVariant(); 00251 return QVariant( log10( x ) ); 00252 } 00253 static QVariant fcnLog( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00254 { 00255 double b = getDoubleValue( values.at( 0 ), parent ); 00256 double x = getDoubleValue( values.at( 1 ), parent ); 00257 if ( x <= 0 || b <= 0 ) 00258 return QVariant(); 00259 return QVariant( log( x ) / log( b ) ); 00260 } 00261 static QVariant fcnToInt( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00262 { 00263 return QVariant( getIntValue( values.at( 0 ), parent ) ); 00264 } 00265 static QVariant fcnToReal( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00266 { 00267 return QVariant( getDoubleValue( values.at( 0 ), parent ) ); 00268 } 00269 static QVariant fcnToString( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00270 { 00271 return QVariant( getStringValue( values.at( 0 ), parent ) ); 00272 } 00273 static QVariant fcnLower( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00274 { 00275 QString str = getStringValue( values.at( 0 ), parent ); 00276 return QVariant( str.toLower() ); 00277 } 00278 static QVariant fcnUpper( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00279 { 00280 QString str = getStringValue( values.at( 0 ), parent ); 00281 return QVariant( str.toUpper() ); 00282 } 00283 static QVariant fcnLength( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00284 { 00285 QString str = getStringValue( values.at( 0 ), parent ); 00286 return QVariant( str.length() ); 00287 } 00288 static QVariant fcnReplace( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00289 { 00290 QString str = getStringValue( values.at( 0 ), parent ); 00291 QString before = getStringValue( values.at( 1 ), parent ); 00292 QString after = getStringValue( values.at( 2 ), parent ); 00293 return QVariant( str.replace( before, after ) ); 00294 } 00295 static QVariant fcnRegexpReplace( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00296 { 00297 QString str = getStringValue( values.at( 0 ), parent ); 00298 QString regexp = getStringValue( values.at( 1 ), parent ); 00299 QString after = getStringValue( values.at( 2 ), parent ); 00300 00301 QRegExp re( regexp ); 00302 if ( !re.isValid() ) 00303 { 00304 parent->setEvalErrorString( QObject::tr( "Invalid regular expression '%1': %2" ).arg( regexp ).arg( re.errorString() ) ); 00305 return QVariant(); 00306 } 00307 return QVariant( str.replace( re, after ) ); 00308 } 00309 static QVariant fcnSubstr( const QVariantList& values, QgsFeature* , QgsExpression* parent ) 00310 { 00311 QString str = getStringValue( values.at( 0 ), parent ); 00312 int from = getIntValue( values.at( 1 ), parent ); 00313 int len = getIntValue( values.at( 2 ), parent ); 00314 return QVariant( str.mid( from -1, len ) ); 00315 } 00316 00317 static QVariant fcnRowNumber( const QVariantList& , QgsFeature* , QgsExpression* parent ) 00318 { 00319 return QVariant( parent->currentRowNumber() ); 00320 } 00321 00322 static QVariant fcnFeatureId( const QVariantList& , QgsFeature* f, QgsExpression* ) 00323 { 00324 // TODO: handling of 64-bit feature ids? 00325 return f ? QVariant(( int )f->id() ) : QVariant(); 00326 } 00327 00328 #define ENSURE_GEOM_TYPE(f, g, geomtype) if (!f) return QVariant(); \ 00329 QgsGeometry* g = f->geometry(); \ 00330 if (!g || g->type() != geomtype) return QVariant(); 00331 00332 00333 static QVariant fcnX( const QVariantList& , QgsFeature* f, QgsExpression* ) 00334 { 00335 ENSURE_GEOM_TYPE( f, g, QGis::Point ); 00336 if ( g->isMultipart() ) 00337 { 00338 return g->asMultiPoint()[ 0 ].x(); 00339 } 00340 else 00341 { 00342 return g->asPoint().x(); 00343 } 00344 } 00345 static QVariant fcnY( const QVariantList& , QgsFeature* f, QgsExpression* ) 00346 { 00347 ENSURE_GEOM_TYPE( f, g, QGis::Point ); 00348 if ( g->isMultipart() ) 00349 { 00350 return g->asMultiPoint()[ 0 ].y(); 00351 } 00352 else 00353 { 00354 return g->asPoint().y(); 00355 } 00356 } 00357 00358 static QVariant pointAt( const QVariantList& values, QgsFeature* f, QgsExpression* parent ) // helper function 00359 { 00360 int idx = getIntValue( values.at( 0 ), parent ); 00361 ENSURE_GEOM_TYPE( f, g, QGis::Line ); 00362 QgsPolyline polyline = g->asPolyline(); 00363 if ( idx < 0 ) 00364 idx += polyline.count(); 00365 00366 if ( idx < 0 || idx >= polyline.count() ) 00367 { 00368 parent->setEvalErrorString( QObject::tr( "Index is out of range" ) ); 00369 return QVariant(); 00370 } 00371 return QVariant( QPointF( polyline[idx].x(), polyline[idx].y() ) ); 00372 } 00373 00374 static QVariant fcnXat( const QVariantList& values, QgsFeature* f, QgsExpression* parent ) 00375 { 00376 QVariant v = pointAt( values, f, parent ); 00377 if ( v.type() == QVariant::PointF ) 00378 return QVariant( v.toPointF().x() ); 00379 else 00380 return QVariant(); 00381 } 00382 static QVariant fcnYat( const QVariantList& values, QgsFeature* f, QgsExpression* parent ) 00383 { 00384 QVariant v = pointAt( values, f, parent ); 00385 if ( v.type() == QVariant::PointF ) 00386 return QVariant( v.toPointF().y() ); 00387 else 00388 return QVariant(); 00389 } 00390 00391 static QVariant fcnGeomArea( const QVariantList& , QgsFeature* f, QgsExpression* parent ) 00392 { 00393 ENSURE_GEOM_TYPE( f, g, QGis::Polygon ); 00394 QgsDistanceArea* calc = parent->geomCalculator(); 00395 return QVariant( calc->measure( f->geometry() ) ); 00396 } 00397 static QVariant fcnGeomLength( const QVariantList& , QgsFeature* f, QgsExpression* parent ) 00398 { 00399 ENSURE_GEOM_TYPE( f, g, QGis::Line ); 00400 QgsDistanceArea* calc = parent->geomCalculator(); 00401 return QVariant( calc->measure( f->geometry() ) ); 00402 } 00403 static QVariant fcnGeomPerimeter( const QVariantList& , QgsFeature* f, QgsExpression* parent ) 00404 { 00405 ENSURE_GEOM_TYPE( f, g, QGis::Polygon ); 00406 QgsDistanceArea* calc = parent->geomCalculator(); 00407 return QVariant( calc->measurePerimeter( f->geometry() ) ); 00408 } 00409 00410 QList<QgsExpression::FunctionDef> QgsExpression::gmBuiltinFunctions; 00411 00412 const QList<QgsExpression::FunctionDef> &QgsExpression::BuiltinFunctions() 00413 { 00414 if ( gmBuiltinFunctions.isEmpty() ) 00415 { 00416 // math 00417 gmBuiltinFunctions 00418 << FunctionDef( "sqrt", 1, fcnSqrt, QObject::tr( "Math" ) ) 00419 << FunctionDef( "sin", 1, fcnSin, QObject::tr( "Math" ) ) 00420 << FunctionDef( "cos", 1, fcnCos, QObject::tr( "Math" ) ) 00421 << FunctionDef( "tan", 1, fcnTan, QObject::tr( "Math" ) ) 00422 << FunctionDef( "asin", 1, fcnAsin, QObject::tr( "Math" ) ) 00423 << FunctionDef( "acos", 1, fcnAcos, QObject::tr( "Math" ) ) 00424 << FunctionDef( "atan", 1, fcnAtan, QObject::tr( "Math" ) ) 00425 << FunctionDef( "atan2", 2, fcnAtan2, QObject::tr( "Math" ) ) 00426 << FunctionDef( "exp", 1, fcnExp, QObject::tr( "Math" ) ) 00427 << FunctionDef( "ln", 1, fcnLn, QObject::tr( "Math" ) ) 00428 << FunctionDef( "log10", 1, fcnLog10, QObject::tr( "Math" ) ) 00429 << FunctionDef( "log", 2, fcnLog, QObject::tr( "Math" ) ) 00430 // casts 00431 << FunctionDef( "toint", 1, fcnToInt, QObject::tr( "Conversions" ) ) 00432 << FunctionDef( "toreal", 1, fcnToReal, QObject::tr( "Conversions" ) ) 00433 << FunctionDef( "tostring", 1, fcnToString, QObject::tr( "Conversions" ) ) 00434 // string manipulation 00435 << FunctionDef( "lower", 1, fcnLower, QObject::tr( "String" ) ) 00436 << FunctionDef( "upper", 1, fcnUpper, QObject::tr( "String" ) ) 00437 << FunctionDef( "length", 1, fcnLength, QObject::tr( "String" ) ) 00438 << FunctionDef( "replace", 3, fcnReplace, QObject::tr( "String" ) ) 00439 << FunctionDef( "regexp_replace", 3, fcnRegexpReplace, QObject::tr( "String" ) ) 00440 << FunctionDef( "substr", 3, fcnSubstr, QObject::tr( "String" ) ) 00441 // geometry accessors 00442 << FunctionDef( "xat", 1, fcnXat, QObject::tr( "Geometry" ), "", true ) 00443 << FunctionDef( "yat", 1, fcnYat, QObject::tr( "Geometry" ), "", true ) 00444 << FunctionDef( "$area", 0, fcnGeomArea, QObject::tr( "Geometry" ), "", true ) 00445 << FunctionDef( "$length", 0, fcnGeomLength, QObject::tr( "Geometry" ), "", true ) 00446 << FunctionDef( "$perimeter", 0, fcnGeomPerimeter, QObject::tr( "Geometry" ), "", true ) 00447 << FunctionDef( "$x", 0, fcnX, QObject::tr( "Geometry" ), "", true ) 00448 << FunctionDef( "$y", 0, fcnY, QObject::tr( "Geometry" ), "" , true ) 00449 // special columns 00450 << FunctionDef( "$rownum", 0, fcnRowNumber, QObject::tr( "Record" ) ) 00451 << FunctionDef( "$id", 0, fcnFeatureId, QObject::tr( "Record" ) ) 00452 ; 00453 } 00454 00455 return gmBuiltinFunctions; 00456 } 00457 00458 00459 bool QgsExpression::isFunctionName( QString name ) 00460 { 00461 return functionIndex( name ) != -1; 00462 } 00463 00464 int QgsExpression::functionIndex( QString name ) 00465 { 00466 int count = functionCount(); 00467 for ( int i = 0; i < count; i++ ) 00468 { 00469 if ( QString::compare( name, BuiltinFunctions()[i].mName, Qt::CaseInsensitive ) == 0 ) 00470 return i; 00471 } 00472 return -1; 00473 } 00474 00475 int QgsExpression::functionCount() 00476 { 00477 return BuiltinFunctions().size(); 00478 } 00479 00480 00481 QgsExpression::QgsExpression( const QString& expr ) 00482 : mExpression( expr ), mRowNumber( 0 ), mCalc( NULL ) 00483 { 00484 mRootNode = ::parseExpression( mExpression, mParserErrorString ); 00485 00486 if ( mParserErrorString.isNull() ) 00487 { 00488 Q_ASSERT( mRootNode != NULL ); 00489 } 00490 } 00491 00492 QgsExpression::~QgsExpression() 00493 { 00494 delete mRootNode; 00495 delete mCalc; 00496 } 00497 00498 QStringList QgsExpression::referencedColumns() 00499 { 00500 if ( !mRootNode ) 00501 return QStringList(); 00502 QStringList columns = mRootNode->referencedColumns(); 00503 00504 // filter out duplicates 00505 for ( int i = 0; i < columns.count(); i++ ) 00506 { 00507 QString col = columns.at( i ); 00508 for ( int j = i + 1; j < columns.count(); j++ ) 00509 { 00510 if ( QString::compare( col, columns[j], Qt::CaseInsensitive ) == 0 ) 00511 { 00512 // this column is repeated: remove it! 00513 columns.removeAt( j-- ); 00514 } 00515 } 00516 } 00517 00518 return columns; 00519 } 00520 00521 bool QgsExpression::needsGeometry() 00522 { 00523 if ( !mRootNode ) 00524 return false; 00525 return mRootNode->needsGeometry(); 00526 } 00527 00528 void QgsExpression::initGeomCalculator() 00529 { 00530 mCalc = new QgsDistanceArea; 00531 mCalc->setProjectionsEnabled( false ); 00532 QSettings settings; 00533 QString ellipsoid = settings.value( "/qgis/measure/ellipsoid", "WGS84" ).toString(); 00534 mCalc->setEllipsoid( ellipsoid ); 00535 } 00536 00537 bool QgsExpression::prepare( const QgsFieldMap& fields ) 00538 { 00539 mEvalErrorString = QString(); 00540 if ( !mRootNode ) 00541 { 00542 mEvalErrorString = QObject::tr( "No root node! Parsing failed?" ); 00543 return false; 00544 } 00545 00546 return mRootNode->prepare( this, fields ); 00547 } 00548 00549 QVariant QgsExpression::evaluate( QgsFeature* f ) 00550 { 00551 mEvalErrorString = QString(); 00552 if ( !mRootNode ) 00553 { 00554 mEvalErrorString = QObject::tr( "No root node! Parsing failed?" ); 00555 return QVariant(); 00556 } 00557 00558 return mRootNode->eval( this, f ); 00559 } 00560 00561 QVariant QgsExpression::evaluate( QgsFeature* f, const QgsFieldMap& fields ) 00562 { 00563 // first prepare 00564 bool res = prepare( fields ); 00565 if ( !res ) 00566 return QVariant(); 00567 00568 // then evaluate 00569 return evaluate( f ); 00570 } 00571 00572 QString QgsExpression::dump() const 00573 { 00574 if ( !mRootNode ) 00575 return QObject::tr( "(no root)" ); 00576 00577 return mRootNode->dump(); 00578 } 00579 00580 void QgsExpression::toOgcFilter( QDomDocument &doc, QDomElement &element ) const 00581 { 00582 if ( !mRootNode ) 00583 return; 00584 00585 mRootNode->toOgcFilter( doc, element ); 00586 } 00587 00588 QgsExpression* QgsExpression::createFromOgcFilter( QDomElement &element ) 00589 { 00590 if ( element.isNull() || !element.hasChildNodes() ) 00591 return NULL; 00592 00593 QgsExpression *expr = new QgsExpression(); 00594 00595 QDomElement childElem = element.firstChildElement(); 00596 while ( !childElem.isNull() ) 00597 { 00598 QString errorMsg; 00599 QgsExpression::Node *node = QgsExpression::Node::createFromOgcFilter( childElem, errorMsg ); 00600 if ( !node ) 00601 { 00602 // invalid expression, parser error 00603 expr->mParserErrorString = errorMsg; 00604 return expr; 00605 } 00606 00607 // use the concat binary operator to append to the root node 00608 if ( !expr->mRootNode ) 00609 { 00610 expr->mRootNode = node; 00611 } 00612 else 00613 { 00614 expr->mRootNode = new QgsExpression::NodeBinaryOperator( boConcat, expr->mRootNode, node ); 00615 } 00616 00617 childElem = childElem.nextSiblingElement(); 00618 } 00619 00620 return expr; 00621 } 00622 00623 void QgsExpression::acceptVisitor( QgsExpression::Visitor& v ) 00624 { 00625 if ( mRootNode ) 00626 mRootNode->accept( v ); 00627 } 00628 00629 00630 QgsExpression::Node* QgsExpression::Node::createFromOgcFilter( QDomElement &element, QString &errorMessage ) 00631 { 00632 if ( element.isNull() ) 00633 return NULL; 00634 00635 // check for unary operators 00636 int unaryOpCount = sizeof( UnaryOgcOperatorText ) / sizeof( UnaryOgcOperatorText[0] ); 00637 for ( int i = 0; i < unaryOpCount; i++ ) 00638 { 00639 QString ogcOperatorName = UnaryOgcOperatorText[ i ]; 00640 if ( ogcOperatorName.isEmpty() ) 00641 continue; 00642 00643 if ( element.localName() == ogcOperatorName ) 00644 { 00645 QgsExpression::Node *node = QgsExpression::NodeUnaryOperator::createFromOgcFilter( element, errorMessage ); 00646 if ( node ) 00647 return node; 00648 00649 return NULL; 00650 } 00651 } 00652 00653 // check for binary operators 00654 int binaryOpCount = sizeof( BinaryOgcOperatorText ) / sizeof( BinaryOgcOperatorText[0] ); 00655 for ( int i = 0; i < binaryOpCount; i++ ) 00656 { 00657 QString ogcOperatorName = BinaryOgcOperatorText[ i ]; 00658 if ( ogcOperatorName.isEmpty() ) 00659 continue; 00660 00661 if ( element.localName() == ogcOperatorName ) 00662 { 00663 QgsExpression::Node *node = QgsExpression::NodeBinaryOperator::createFromOgcFilter( element, errorMessage ); 00664 if ( node ) 00665 return node; 00666 00667 return NULL; 00668 } 00669 } 00670 00671 // check for other OGC operators, convert them to expressions 00672 00673 if ( element.localName() == "PropertyIsNull" ) 00674 { 00675 return QgsExpression::NodeBinaryOperator::createFromOgcFilter( element, errorMessage ); 00676 } 00677 else if ( element.localName() == "Literal" ) 00678 { 00679 return QgsExpression::NodeLiteral::createFromOgcFilter( element, errorMessage ); 00680 } 00681 else if ( element.localName() == "Function" ) 00682 { 00683 return QgsExpression::NodeFunction::createFromOgcFilter( element, errorMessage ); 00684 } 00685 else if ( element.localName() == "PropertyName" ) 00686 { 00687 return QgsExpression::NodeColumnRef::createFromOgcFilter( element, errorMessage ); 00688 } 00689 else if ( element.localName() == "PropertyIsBetween" ) 00690 { 00691 // <ogc:PropertyIsBetween> encode a Range check 00692 QgsExpression::Node *operand = 0, *lowerBound = 0, *upperBound = 0; 00693 00694 QDomElement operandElem = element.firstChildElement( "LowerBoundary" ); 00695 if ( !operandElem.isNull() ) 00696 lowerBound = createFromOgcFilter( operandElem, errorMessage ); 00697 00698 operandElem = element.firstChildElement( "UpperBoundary" ); 00699 if ( !operandElem.isNull() ) 00700 upperBound = createFromOgcFilter( operandElem, errorMessage ); 00701 00702 // <ogc:expression> 00703 operandElem = element.firstChildElement(); 00704 while ( !operandElem.isNull() ) 00705 { 00706 if ( operandElem.localName() != "LowerBoundary" && 00707 operandElem.localName() != "UpperBoundary" ) 00708 { 00709 operand = createFromOgcFilter( operandElem, errorMessage ); 00710 break; 00711 } 00712 00713 operandElem = operandElem.nextSiblingElement(); 00714 } 00715 00716 if ( !operand || !lowerBound || !upperBound ) 00717 { 00718 if ( operand ) 00719 delete operand; 00720 00721 if ( lowerBound ) 00722 delete lowerBound; 00723 00724 if ( upperBound ) 00725 delete upperBound; 00726 00727 errorMessage = "missing some required sub-elements in ogc:PropertyIsBetween"; 00728 return NULL; 00729 } 00730 00731 QgsExpression::Node *geOperator = new QgsExpression::NodeBinaryOperator( boGE, operand, lowerBound ); 00732 QgsExpression::Node *leOperator = new QgsExpression::NodeBinaryOperator( boLE, operand, upperBound ); 00733 return new QgsExpression::NodeBinaryOperator( boAnd, geOperator, leOperator ); 00734 } 00735 00736 errorMessage += QString( "unable to convert '%1' element to a valid expression: it is not supported yet or it has invalid arguments" ).arg( element.tagName() ); 00737 return NULL; 00738 } 00739 00741 // nodes 00742 00743 QString QgsExpression::NodeList::dump() const 00744 { 00745 QString msg; bool first = true; 00746 foreach( Node* n, mList ) 00747 { 00748 if ( !first ) msg += ", "; else first = false; 00749 msg += n->dump(); 00750 } 00751 return msg; 00752 } 00753 00754 void QgsExpression::NodeList::toOgcFilter( QDomDocument &doc, QDomElement &element ) const 00755 { 00756 foreach( Node* n, mList ) 00757 { 00758 n->toOgcFilter( doc, element ); 00759 } 00760 } 00761 00762 // 00763 00764 QVariant QgsExpression::NodeUnaryOperator::eval( QgsExpression* parent, QgsFeature* f ) 00765 { 00766 QVariant val = mOperand->eval( parent, f ); 00767 ENSURE_NO_EVAL_ERROR; 00768 00769 switch ( mOp ) 00770 { 00771 case uoNot: 00772 { 00773 TVL tvl = getTVLValue( val, parent ); 00774 ENSURE_NO_EVAL_ERROR; 00775 return tvl2variant( NOT[tvl] ); 00776 } 00777 00778 case uoMinus: 00779 if ( isIntSafe( val ) ) 00780 return QVariant( - getIntValue( val, parent ) ); 00781 else if ( isDoubleSafe( val ) ) 00782 return QVariant( - getDoubleValue( val, parent ) ); 00783 else 00784 SET_EVAL_ERROR( QObject::tr( "Unary minus only for numeric values." ) ); 00785 break; 00786 default: 00787 Q_ASSERT( 0 && "unknown unary operation" ); 00788 } 00789 return QVariant(); 00790 } 00791 00792 bool QgsExpression::NodeUnaryOperator::prepare( QgsExpression* parent, const QgsFieldMap& fields ) 00793 { 00794 return mOperand->prepare( parent, fields ); 00795 } 00796 00797 QString QgsExpression::NodeUnaryOperator::dump() const 00798 { 00799 return QString( "%1 %2" ).arg( UnaryOperatorText[mOp] ).arg( mOperand->dump() ); 00800 } 00801 00802 void QgsExpression::NodeUnaryOperator::toOgcFilter( QDomDocument &doc, QDomElement &element ) const 00803 { 00804 QDomElement uoElem; 00805 switch ( mOp ) 00806 { 00807 case uoMinus: 00808 uoElem = doc.createElement( "ogc:Literal" ); 00809 uoElem.appendChild( doc.createTextNode( "-" ) ); 00810 break; 00811 case uoNot: 00812 uoElem = doc.createElement( "ogc:Not" ); 00813 break; 00814 00815 default: 00816 element.appendChild( doc.createComment( QString( "Unary operator %1 not implemented yet" ).arg( UnaryOperatorText[mOp] ) ) ); 00817 return; 00818 } 00819 mOperand->toOgcFilter( doc, uoElem ); 00820 element.appendChild( uoElem ); 00821 } 00822 00823 QgsExpression::Node* QgsExpression::NodeUnaryOperator::createFromOgcFilter( QDomElement &element, QString &errorMessage ) 00824 { 00825 if ( element.isNull() ) 00826 return NULL; 00827 00828 int unaryOpCount = sizeof( UnaryOgcOperatorText ) / sizeof( UnaryOgcOperatorText[0] ); 00829 for ( int i = 0; i < unaryOpCount; i++ ) 00830 { 00831 QString ogcOperatorName = UnaryOgcOperatorText[ i ]; 00832 if ( ogcOperatorName.isEmpty() ) 00833 continue; 00834 00835 if ( element.localName() != ogcOperatorName ) 00836 continue; 00837 00838 QDomElement operandElem = element.firstChildElement(); 00839 QgsExpression::Node* operand = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage ); 00840 if ( !operand ) 00841 { 00842 if ( errorMessage.isEmpty() ) 00843 errorMessage = QString( "invalid operand for '%1' unary operator" ).arg( ogcOperatorName ); 00844 return NULL; 00845 } 00846 00847 return new QgsExpression::NodeUnaryOperator(( UnaryOperator ) i, operand ); 00848 } 00849 00850 errorMessage = QString( "%1 unary operator not supported." ).arg( element.tagName() ); 00851 return NULL; 00852 } 00853 00854 // 00855 00856 QVariant QgsExpression::NodeBinaryOperator::eval( QgsExpression* parent, QgsFeature* f ) 00857 { 00858 QVariant vL = mOpLeft->eval( parent, f ); 00859 ENSURE_NO_EVAL_ERROR; 00860 QVariant vR = mOpRight->eval( parent, f ); 00861 ENSURE_NO_EVAL_ERROR; 00862 00863 switch ( mOp ) 00864 { 00865 case boPlus: 00866 case boMinus: 00867 case boMul: 00868 case boDiv: 00869 case boMod: 00870 if ( isNull( vL ) || isNull( vR ) ) 00871 return QVariant(); 00872 else if ( isIntSafe( vL ) && isIntSafe( vR ) ) 00873 { 00874 // both are integers - let's use integer arithmetics 00875 int iL = getIntValue( vL, parent ); ENSURE_NO_EVAL_ERROR; 00876 int iR = getIntValue( vR, parent ); ENSURE_NO_EVAL_ERROR; 00877 if ( mOp == boDiv && iR == 0 ) return QVariant(); // silently handle division by zero and return NULL 00878 return QVariant( computeInt( iL, iR ) ); 00879 } 00880 else 00881 { 00882 // general floating point arithmetic 00883 double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR; 00884 double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR; 00885 if ( mOp == boDiv && fR == 0 ) 00886 return QVariant(); // silently handle division by zero and return NULL 00887 return QVariant( computeDouble( fL, fR ) ); 00888 } 00889 00890 case boPow: 00891 if ( isNull( vL ) || isNull( vR ) ) 00892 return QVariant(); 00893 else 00894 { 00895 double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR; 00896 double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR; 00897 return QVariant( pow( fL, fR ) ); 00898 } 00899 00900 case boAnd: 00901 { 00902 TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent ); 00903 ENSURE_NO_EVAL_ERROR; 00904 return tvl2variant( AND[tvlL][tvlR] ); 00905 } 00906 00907 case boOr: 00908 { 00909 TVL tvlL = getTVLValue( vL, parent ), tvlR = getTVLValue( vR, parent ); 00910 ENSURE_NO_EVAL_ERROR; 00911 return tvl2variant( OR[tvlL][tvlR] ); 00912 } 00913 00914 case boEQ: 00915 case boNE: 00916 case boLT: 00917 case boGT: 00918 case boLE: 00919 case boGE: 00920 if ( isNull( vL ) || isNull( vR ) ) 00921 { 00922 return TVL_Unknown; 00923 } 00924 else if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) ) 00925 { 00926 // do numeric comparison if both operators can be converted to numbers 00927 double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR; 00928 double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR; 00929 return compare( fL - fR ) ? TVL_True : TVL_False; 00930 } 00931 else 00932 { 00933 // do string comparison otherwise 00934 QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR; 00935 QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR; 00936 int diff = QString::compare( sL, sR ); 00937 return compare( diff ) ? TVL_True : TVL_False; 00938 } 00939 00940 case boIs: 00941 case boIsNot: 00942 if ( isNull( vL ) && isNull( vR ) ) // both operators null 00943 return ( mOp == boIs ? TVL_True : TVL_False ); 00944 else if ( isNull( vL ) || isNull( vR ) ) // one operator null 00945 return ( mOp == boIs ? TVL_False : TVL_True ); 00946 else // both operators non-null 00947 { 00948 bool equal = false; 00949 if ( isDoubleSafe( vL ) && isDoubleSafe( vR ) ) 00950 { 00951 double fL = getDoubleValue( vL, parent ); ENSURE_NO_EVAL_ERROR; 00952 double fR = getDoubleValue( vR, parent ); ENSURE_NO_EVAL_ERROR; 00953 equal = fL == fR; 00954 } 00955 else 00956 { 00957 QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR; 00958 QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR; 00959 equal = QString::compare( sL, sR ) == 0; 00960 } 00961 if ( equal ) 00962 return mOp == boIs ? TVL_True : TVL_False; 00963 else 00964 return mOp == boIs ? TVL_False : TVL_True; 00965 } 00966 00967 case boRegexp: 00968 case boLike: 00969 case boNotLike: 00970 case boILike: 00971 case boNotILike: 00972 if ( isNull( vL ) || isNull( vR ) ) 00973 return TVL_Unknown; 00974 else 00975 { 00976 QString str = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR; 00977 QString regexp = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR; 00978 // TODO: cache QRegExp in case that regexp is a literal string (i.e. it will stay constant) 00979 bool matches; 00980 if ( mOp == boLike || mOp == boILike || mOp == boNotLike || mOp == boNotILike ) // change from LIKE syntax to regexp 00981 { 00982 // XXX escape % and _ ??? 00983 regexp.replace( "%", ".*" ); 00984 regexp.replace( "_", "." ); 00985 matches = QRegExp( regexp, mOp == boLike || mOp == boNotLike ? Qt::CaseSensitive : Qt::CaseInsensitive ).exactMatch( str ); 00986 } 00987 else 00988 { 00989 matches = QRegExp( regexp ).indexIn( str ) != -1; 00990 } 00991 00992 if ( mOp == boNotLike || mOp == boNotILike ) 00993 { 00994 matches = !matches; 00995 } 00996 00997 return matches ? TVL_True : TVL_False; 00998 } 00999 01000 case boConcat: 01001 if ( isNull( vL ) || isNull( vR ) ) 01002 return QVariant(); 01003 else 01004 { 01005 QString sL = getStringValue( vL, parent ); ENSURE_NO_EVAL_ERROR; 01006 QString sR = getStringValue( vR, parent ); ENSURE_NO_EVAL_ERROR; 01007 return QVariant( sL + sR ); 01008 } 01009 01010 default: break; 01011 } 01012 Q_ASSERT( false ); 01013 return QVariant(); 01014 } 01015 01016 bool QgsExpression::NodeBinaryOperator::compare( double diff ) 01017 { 01018 switch ( mOp ) 01019 { 01020 case boEQ: return diff == 0; 01021 case boNE: return diff != 0; 01022 case boLT: return diff < 0; 01023 case boGT: return diff > 0; 01024 case boLE: return diff <= 0; 01025 case boGE: return diff >= 0; 01026 default: Q_ASSERT( false ); return false; 01027 } 01028 } 01029 01030 int QgsExpression::NodeBinaryOperator::computeInt( int x, int y ) 01031 { 01032 switch ( mOp ) 01033 { 01034 case boPlus: return x+y; 01035 case boMinus: return x-y; 01036 case boMul: return x*y; 01037 case boDiv: return x/y; 01038 case boMod: return x%y; 01039 default: Q_ASSERT( false ); return 0; 01040 } 01041 } 01042 01043 double QgsExpression::NodeBinaryOperator::computeDouble( double x, double y ) 01044 { 01045 switch ( mOp ) 01046 { 01047 case boPlus: return x+y; 01048 case boMinus: return x-y; 01049 case boMul: return x*y; 01050 case boDiv: return x/y; 01051 case boMod: return fmod( x,y ); 01052 default: Q_ASSERT( false ); return 0; 01053 } 01054 } 01055 01056 01057 bool QgsExpression::NodeBinaryOperator::prepare( QgsExpression* parent, const QgsFieldMap& fields ) 01058 { 01059 bool resL = mOpLeft->prepare( parent, fields ); 01060 bool resR = mOpRight->prepare( parent, fields ); 01061 return resL && resR; 01062 } 01063 01064 QString QgsExpression::NodeBinaryOperator::dump() const 01065 { 01066 return QString( "%1 %2 %3" ).arg( mOpLeft->dump() ).arg( BinaryOperatorText[mOp] ).arg( mOpRight->dump() ); 01067 } 01068 01069 void QgsExpression::NodeBinaryOperator::toOgcFilter( QDomDocument &doc, QDomElement &element ) const 01070 { 01071 if ( mOp == boConcat ) 01072 { 01073 // the concat binary operator must only convert its operands 01074 mOpLeft->toOgcFilter( doc, element ); 01075 mOpRight->toOgcFilter( doc, element ); 01076 return; 01077 } 01078 01079 if ( mOp == boIs || mOp == boIsNot ) 01080 { 01081 // check if one of the operands is NULL 01082 QgsExpression::NodeLiteral *opLeftLiteral = dynamic_cast<QgsExpression::NodeLiteral *>( mOpLeft ); 01083 QgsExpression::NodeLiteral *opRightLiteral = dynamic_cast<QgsExpression::NodeLiteral *>( mOpRight ); 01084 01085 if ( opLeftLiteral && opLeftLiteral->value().isNull() && 01086 opRightLiteral && opRightLiteral->value().isNull() ) 01087 { 01088 // why could anybody find useful to use NULL IS NULL??? 01089 // BTW avoid issues by converting it to 1 = 1 01090 QDomElement eqElem = doc.createElement( "ogc:PropertyIsEqual" ); 01091 01092 QDomElement literalElem = doc.createElement( "ogc:Literal" ); 01093 literalElem.appendChild( doc.createTextNode( "1" ) ); 01094 eqElem.appendChild( literalElem ); 01095 01096 literalElem = doc.createElement( "ogc:Literal" ); 01097 literalElem.appendChild( doc.createTextNode( "1" ) ); 01098 eqElem.appendChild( literalElem ); 01099 01100 element.appendChild( eqElem ); 01101 } 01102 else if (( opLeftLiteral && opLeftLiteral->value().isNull() ) || 01103 ( opRightLiteral && opRightLiteral->value().isNull() ) ) 01104 { 01105 // at least one operand is NULL, use <ogc:PropertyIsNull> element 01106 QDomElement isNullElem = doc.createElement( "ogc:PropertyIsNull" ); 01107 QgsExpression::Node *operand = opLeftLiteral->value().isNull() ? mOpRight : mOpLeft; 01108 operand->toOgcFilter( doc, isNullElem ); 01109 01110 if ( mOp == boIsNot ) 01111 { 01112 // append to <ogc:Not> element if IS NOT operator was required 01113 QDomElement notOpElem = doc.createElement( "ogc:Not" ); 01114 notOpElem.appendChild( isNullElem ); 01115 element.appendChild( notOpElem ); 01116 } 01117 else 01118 { 01119 element.appendChild( isNullElem ); 01120 } 01121 } 01122 else 01123 { 01124 // both operands are not null, use <ogc:PropertyIsEqual> element 01125 QDomElement eqElem = doc.createElement( "ogc:PropertyIsEqual" ); 01126 mOpLeft->toOgcFilter( doc, eqElem ); 01127 mOpRight->toOgcFilter( doc, eqElem ); 01128 element.appendChild( eqElem ); 01129 } 01130 return; 01131 } 01132 01133 if ( mOp == boILike ) 01134 { 01135 // XXX why ogc:PropertyIsLikeType extends ogc:ComparisonOpsType 01136 // which has no matchCase attribute? Shouldn't it be better if 01137 // would extend BinaryComparisonOpType which has that attribute 01138 // and doesn't require to have a ogc:PropertyName as first parameter? 01139 QgsExpression ilikeExpr( QString( "upper( %1 ) LIKE upper( %2 )" ).arg( mOpLeft->dump() ).arg( mOpRight->dump() ) ); 01140 ilikeExpr.toOgcFilter( doc, element ); 01141 return; 01142 } 01143 01144 QString opText = BinaryOgcOperatorText[mOp]; 01145 if ( opText.isEmpty() ) 01146 { 01147 // not implemented binary operators 01148 // TODO: regex, % (mod), ^ (pow) are not supported yet 01149 element.appendChild( doc.createComment( QString( "Binary operator %1 not implemented yet" ).arg( BinaryOperatorText[mOp] ) ) ); 01150 return; 01151 } 01152 01153 QDomElement boElem = doc.createElement( "ogc:" + opText ); 01154 if ( mOp == boLike ) 01155 { 01156 // setup wildcards to <ogc:PropertyIsLike> 01157 boElem.setAttribute( "wildCard", "%" ); 01158 boElem.setAttribute( "singleChar", "?" ); 01159 boElem.setAttribute( "escapeChar", "!" ); 01160 } 01161 01162 mOpLeft->toOgcFilter( doc, boElem ); 01163 mOpRight->toOgcFilter( doc, boElem ); 01164 element.appendChild( boElem ); 01165 } 01166 01167 QgsExpression::Node* QgsExpression::NodeBinaryOperator::createFromOgcFilter( QDomElement &element, QString &errorMessage ) 01168 { 01169 if ( element.isNull() ) 01170 return NULL; 01171 01172 QgsExpression::Node* opLeft = 0; 01173 QgsExpression::Node* opRight = 0; 01174 01175 // convert ogc:PropertyIsNull to IS operator with NULL right operand 01176 if ( element.localName() == "PropertyIsNull" ) 01177 { 01178 QDomElement operandElem = element.firstChildElement(); 01179 opLeft = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage ); 01180 if ( !opLeft ) 01181 return NULL; 01182 01183 opRight = new QgsExpression::NodeLiteral( QVariant() ); 01184 return new QgsExpression::NodeBinaryOperator( boIs, opLeft, opRight ); 01185 } 01186 01187 // the other binary operators 01188 int binaryOpCount = sizeof( BinaryOgcOperatorText ) / sizeof( BinaryOgcOperatorText[0] ); 01189 for ( int i = 0; i < binaryOpCount; i++ ) 01190 { 01191 QString ogcOperatorName = BinaryOgcOperatorText[ i ]; 01192 if ( ogcOperatorName.isEmpty() ) 01193 continue; 01194 01195 if ( element.localName() != ogcOperatorName ) 01196 continue; 01197 01198 QDomElement operandElem = element.firstChildElement(); 01199 opLeft = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage ); 01200 if ( !opLeft ) 01201 { 01202 if ( errorMessage.isEmpty() ) 01203 errorMessage = QString( "invalid left operand for '%1' binary operator" ).arg( ogcOperatorName ); 01204 break; 01205 } 01206 01207 operandElem = operandElem.nextSiblingElement(); 01208 opRight = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage ); 01209 if ( !opRight ) 01210 { 01211 if ( errorMessage.isEmpty() ) 01212 errorMessage = QString( "invalid right operand for '%1' binary operator" ).arg( ogcOperatorName ); 01213 break; 01214 } 01215 01216 return new QgsExpression::NodeBinaryOperator(( BinaryOperator ) i, opLeft, opRight ); 01217 } 01218 01219 if ( !opLeft && !opRight ) 01220 { 01221 errorMessage = QString( "'%1' binary operator not supported." ).arg( element.tagName() ); 01222 return NULL; 01223 } 01224 01225 if ( opLeft ) 01226 delete opLeft; 01227 01228 if ( opRight ) 01229 delete opRight; 01230 01231 return NULL; 01232 } 01233 01234 // 01235 01236 QVariant QgsExpression::NodeInOperator::eval( QgsExpression* parent, QgsFeature* f ) 01237 { 01238 if ( mList->count() == 0 ) 01239 return mNotIn ? TVL_True : TVL_False; 01240 QVariant v1 = mNode->eval( parent, f ); 01241 ENSURE_NO_EVAL_ERROR; 01242 if ( isNull( v1 ) ) 01243 return TVL_Unknown; 01244 01245 bool listHasNull = false; 01246 01247 foreach( Node* n, mList->list() ) 01248 { 01249 QVariant v2 = n->eval( parent, f ); 01250 ENSURE_NO_EVAL_ERROR; 01251 if ( isNull( v2 ) ) 01252 listHasNull = true; 01253 else 01254 { 01255 bool equal = false; 01256 // check whether they are equal 01257 if ( isDoubleSafe( v1 ) && isDoubleSafe( v2 ) ) 01258 { 01259 double f1 = getDoubleValue( v1, parent ); ENSURE_NO_EVAL_ERROR; 01260 double f2 = getDoubleValue( v2, parent ); ENSURE_NO_EVAL_ERROR; 01261 equal = f1 == f2; 01262 } 01263 else 01264 { 01265 QString s1 = getStringValue( v1, parent ); ENSURE_NO_EVAL_ERROR; 01266 QString s2 = getStringValue( v2, parent ); ENSURE_NO_EVAL_ERROR; 01267 equal = QString::compare( s1, s2 ) == 0; 01268 } 01269 01270 if ( equal ) // we know the result 01271 return mNotIn ? TVL_False : TVL_True; 01272 } 01273 } 01274 01275 // item not found 01276 if ( listHasNull ) 01277 return TVL_Unknown; 01278 else 01279 return mNotIn ? TVL_True : TVL_False; 01280 } 01281 01282 bool QgsExpression::NodeInOperator::prepare( QgsExpression* parent, const QgsFieldMap& fields ) 01283 { 01284 bool res = mNode->prepare( parent, fields ); 01285 foreach( Node* n, mList->list() ) 01286 { 01287 res = res && n->prepare( parent, fields ); 01288 } 01289 return res; 01290 } 01291 01292 QString QgsExpression::NodeInOperator::dump() const 01293 { 01294 return QString( "%1 IN (%2)" ).arg( mNode->dump() ).arg( mList->dump() ); 01295 } 01296 01297 void QgsExpression::NodeInOperator::toOgcFilter( QDomDocument &doc, QDomElement &element ) const 01298 { 01299 // XXX use a function instead of multiple comparations? 01300 01301 QDomElement *parent = &element; 01302 01303 QDomElement orElem; 01304 if ( mList->list().size() > 1 ) 01305 { 01306 orElem = doc.createElement( "ogc:Or" ); 01307 element.appendChild( orElem ); 01308 01309 parent = &orElem; 01310 } 01311 01312 foreach( Node* n, mList->list() ) 01313 { 01314 QDomElement eqElem = doc.createElement( "ogc:PropertyIsEqualTo" ); 01315 mNode->toOgcFilter( doc, eqElem ); 01316 n->toOgcFilter( doc, eqElem ); 01317 01318 parent->appendChild( eqElem ); 01319 } 01320 } 01321 01322 // 01323 01324 QVariant QgsExpression::NodeFunction::eval( QgsExpression* parent, QgsFeature* f ) 01325 { 01326 const FunctionDef& fd = BuiltinFunctions()[mFnIndex]; 01327 01328 // evaluate arguments 01329 QVariantList argValues; 01330 if ( mArgs ) 01331 { 01332 foreach( Node* n, mArgs->list() ) 01333 { 01334 QVariant v = n->eval( parent, f ); 01335 ENSURE_NO_EVAL_ERROR; 01336 if ( isNull( v ) ) 01337 return QVariant(); // all "normal" functions return NULL when any parameter is NULL 01338 argValues.append( v ); 01339 } 01340 } 01341 01342 // run the function 01343 QVariant res = fd.mFcn( argValues, f, parent ); 01344 ENSURE_NO_EVAL_ERROR; 01345 01346 // everything went fine 01347 return res; 01348 } 01349 01350 bool QgsExpression::NodeFunction::prepare( QgsExpression* parent, const QgsFieldMap& fields ) 01351 { 01352 bool res = true; 01353 if ( mArgs ) 01354 { 01355 foreach( Node* n, mArgs->list() ) 01356 { 01357 res = res && n->prepare( parent, fields ); 01358 } 01359 } 01360 return res; 01361 } 01362 01363 QString QgsExpression::NodeFunction::dump() const 01364 { 01365 const FunctionDef& fd = BuiltinFunctions()[mFnIndex]; 01366 if ( fd.mParams == 0 ) 01367 return fd.mName; // special column 01368 else 01369 return QString( "%1(%2)" ).arg( fd.mName ).arg( mArgs ? mArgs->dump() : QString() ); // function 01370 } 01371 01372 void QgsExpression::NodeFunction::toOgcFilter( QDomDocument &doc, QDomElement &element ) const 01373 { 01374 const FunctionDef& fd = BuiltinFunctions()[mFnIndex]; 01375 if ( fd.mParams == 0 ) 01376 return; // TODO: special column 01377 01378 QDomElement funcElem = doc.createElement( "ogc:Function" ); 01379 funcElem.setAttribute( "name", fd.mName ); 01380 mArgs->toOgcFilter( doc, funcElem ); 01381 element.appendChild( funcElem ); 01382 } 01383 01384 QgsExpression::Node* QgsExpression::NodeFunction::createFromOgcFilter( QDomElement &element, QString &errorMessage ) 01385 { 01386 if ( element.isNull() ) 01387 return NULL; 01388 01389 if ( element.localName() != "Function" ) 01390 { 01391 errorMessage = QString( "ogc:Function expected, got %1" ).arg( element.tagName() ); 01392 return NULL; 01393 } 01394 01395 for ( int i = 0; i < BuiltinFunctions().size(); i++ ) 01396 { 01397 QgsExpression::FunctionDef funcDef = BuiltinFunctions()[i]; 01398 01399 if ( element.attribute( "name" ) != funcDef.mName ) 01400 continue; 01401 01402 QgsExpression::NodeList *args = new QgsExpression::NodeList(); 01403 01404 QDomElement operandElem = element.firstChildElement(); 01405 while ( !operandElem.isNull() ) 01406 { 01407 QgsExpression::Node* op = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage ); 01408 if ( !op ) 01409 { 01410 delete args; 01411 return NULL; 01412 } 01413 args->append( op ); 01414 01415 operandElem = operandElem.nextSiblingElement(); 01416 } 01417 01418 return new QgsExpression::NodeFunction( i, args ); 01419 } 01420 01421 return NULL; 01422 } 01423 01424 // 01425 01426 QVariant QgsExpression::NodeLiteral::eval( QgsExpression* , QgsFeature* ) 01427 { 01428 return mValue; 01429 } 01430 01431 bool QgsExpression::NodeLiteral::prepare( QgsExpression* /*parent*/, const QgsFieldMap& /*fields*/ ) 01432 { 01433 return true; 01434 } 01435 01436 01437 QString QgsExpression::NodeLiteral::dump() const 01438 { 01439 if ( mValue.isNull() ) 01440 return "NULL"; 01441 01442 switch ( mValue.type() ) 01443 { 01444 case QVariant::Int: return QString::number( mValue.toInt() ); 01445 case QVariant::Double: return QString::number( mValue.toDouble() ); 01446 case QVariant::String: return QString( "'%1'" ).arg( mValue.toString() ); 01447 default: return QObject::tr( "[unsupported type;%1; value:%2]" ).arg( mValue.typeName() ).arg( mValue.toString() ); 01448 } 01449 } 01450 01451 void QgsExpression::NodeLiteral::toOgcFilter( QDomDocument &doc, QDomElement &element ) const 01452 { 01453 QString value; 01454 if ( !mValue.isNull() ) 01455 { 01456 switch ( mValue.type() ) 01457 { 01458 case QVariant::Int: 01459 value = QString::number( mValue.toInt() ); 01460 break; 01461 case QVariant::Double: 01462 value = QString::number( mValue.toDouble() ); 01463 break; 01464 case QVariant::String: 01465 value = mValue.toString(); 01466 break; 01467 default: 01468 break; 01469 } 01470 } 01471 QDomElement litElem = doc.createElement( "ogc:Literal" ); 01472 litElem.appendChild( doc.createTextNode( value ) ); 01473 element.appendChild( litElem ); 01474 } 01475 01476 QgsExpression::Node* QgsExpression::NodeLiteral::createFromOgcFilter( QDomElement &element, QString &errorMessage ) 01477 { 01478 if ( element.isNull() ) 01479 return NULL; 01480 01481 if ( element.localName() != "Literal" ) 01482 { 01483 errorMessage = QString( "ogc:Literal expected, got %1" ).arg( element.tagName() ); 01484 return NULL; 01485 } 01486 01487 QgsExpression::Node *root = 0; 01488 01489 // the literal content can have more children (e.g. CDATA section, text, ...) 01490 QDomNode childNode = element.firstChild(); 01491 while ( !childNode.isNull() ) 01492 { 01493 QgsExpression::Node* operand = 0; 01494 01495 if ( childNode.nodeType() == QDomNode::ElementNode ) 01496 { 01497 // found a element node (e.g. PropertyName), convert it 01498 QDomElement operandElem = childNode.toElement(); 01499 operand = QgsExpression::Node::createFromOgcFilter( operandElem, errorMessage ); 01500 if ( !operand ) 01501 { 01502 if ( root ) 01503 delete root; 01504 01505 errorMessage = QString( "'%1' is an invalid or not supported content for ogc:Literal" ).arg( operandElem.tagName() ); 01506 return NULL; 01507 } 01508 } 01509 else 01510 { 01511 // probably a text/CDATA node, convert its content to string 01512 operand = new QgsExpression::NodeLiteral( childNode.nodeValue() ); 01513 } 01514 01515 if ( !operand ) 01516 continue; 01517 01518 // use the concat operator to merge the ogc:Literal children 01519 if ( !root ) 01520 { 01521 root = operand; 01522 } 01523 else 01524 { 01525 root = new QgsExpression::NodeBinaryOperator( boConcat, root, operand ); 01526 } 01527 01528 childNode = childNode.nextSibling(); 01529 } 01530 01531 if ( root ) 01532 return root; 01533 01534 return NULL; 01535 } 01536 01537 // 01538 01539 QVariant QgsExpression::NodeColumnRef::eval( QgsExpression* /*parent*/, QgsFeature* f ) 01540 { 01541 return f->attributeMap()[mIndex]; 01542 } 01543 01544 bool QgsExpression::NodeColumnRef::prepare( QgsExpression* parent, const QgsFieldMap& fields ) 01545 { 01546 foreach( int i, fields.keys() ) 01547 { 01548 if ( QString::compare( fields[i].name(), mName, Qt::CaseInsensitive ) == 0 ) 01549 { 01550 mIndex = i; 01551 return true; 01552 } 01553 } 01554 parent->mEvalErrorString = QObject::tr( "Column '%1'' not found" ).arg( mName ); 01555 mIndex = -1; 01556 return false; 01557 } 01558 01559 QString QgsExpression::NodeColumnRef::dump() const 01560 { 01561 return mName; 01562 } 01563 01564 void QgsExpression::NodeColumnRef::toOgcFilter( QDomDocument &doc, QDomElement &element ) const 01565 { 01566 QDomElement propElem = doc.createElement( "ogc:PropertyName" ); 01567 propElem.appendChild( doc.createTextNode( mName ) ); 01568 element.appendChild( propElem ); 01569 } 01570 01571 QgsExpression::Node* QgsExpression::NodeColumnRef::createFromOgcFilter( QDomElement &element, QString &errorMessage ) 01572 { 01573 if ( element.isNull() ) 01574 return NULL; 01575 01576 if ( element.localName() != "PropertyName" ) 01577 { 01578 errorMessage = QString( "ogc:PropertyName expected, got %1" ).arg( element.tagName() ); 01579 return NULL; 01580 } 01581 01582 return new QgsExpression::NodeColumnRef( element.firstChild().nodeValue() ); 01583 } 01584 01585 // 01586 01587 QVariant QgsExpression::NodeCondition::eval( QgsExpression* parent, QgsFeature* f ) 01588 { 01589 foreach( WhenThen* cond, mConditions ) 01590 { 01591 QVariant vWhen = cond->mWhenExp->eval( parent, f ); 01592 TVL tvl = getTVLValue( vWhen, parent ); 01593 ENSURE_NO_EVAL_ERROR; 01594 if ( tvl == True ) 01595 { 01596 QVariant vRes = cond->mThenExp->eval( parent, f ); 01597 ENSURE_NO_EVAL_ERROR; 01598 return vRes; 01599 } 01600 } 01601 01602 if ( mElseExp ) 01603 { 01604 QVariant vElse = mElseExp->eval( parent, f ); 01605 ENSURE_NO_EVAL_ERROR; 01606 return vElse; 01607 } 01608 01609 // return NULL if no condition is matching 01610 return QVariant(); 01611 } 01612 01613 bool QgsExpression::NodeCondition::prepare( QgsExpression* parent, const QgsFieldMap& fields ) 01614 { 01615 bool res; 01616 foreach( WhenThen* cond, mConditions ) 01617 { 01618 res = cond->mWhenExp->prepare( parent, fields ) 01619 & cond->mThenExp->prepare( parent, fields ); 01620 if ( !res ) return false; 01621 } 01622 01623 if ( mElseExp ) 01624 return mElseExp->prepare( parent, fields ); 01625 01626 return true; 01627 } 01628 01629 QString QgsExpression::NodeCondition::dump() const 01630 { 01631 QString msg = "CONDITION:\n"; 01632 foreach( WhenThen* cond, mConditions ) 01633 { 01634 msg += QString( "- WHEN %1 THEN %2\n" ).arg( cond->mWhenExp->dump() ).arg( cond->mThenExp->dump() ); 01635 } 01636 if ( mElseExp ) 01637 msg += QString( "- ELSE %1" ).arg( mElseExp->dump() ); 01638 return msg; 01639 } 01640 01641 void QgsExpression::NodeCondition::toOgcFilter( QDomDocument &doc, QDomElement &element ) const 01642 { 01643 // TODO: if(cond) ... [else if (cond2) ...]* [else ...] 01644 element.appendChild( doc.createComment( "CASE operator not implemented yet" ) ); 01645 } 01646 01647 QStringList QgsExpression::NodeCondition::referencedColumns() const 01648 { 01649 QStringList lst; 01650 foreach( WhenThen* cond, mConditions ) 01651 { 01652 lst += cond->mWhenExp->referencedColumns() + cond->mThenExp->referencedColumns(); 01653 } 01654 01655 if ( mElseExp ) 01656 lst += mElseExp->referencedColumns(); 01657 01658 return lst; 01659 } 01660 01661 bool QgsExpression::NodeCondition::needsGeometry() const 01662 { 01663 foreach( WhenThen* cond, mConditions ) 01664 { 01665 if ( cond->mWhenExp->needsGeometry() || 01666 cond->mThenExp->needsGeometry() ) 01667 return true; 01668 } 01669 01670 if ( mElseExp && mElseExp->needsGeometry() ) 01671 return true; 01672 01673 return false; 01674 }