Skip to content

Commit

Permalink
proper setup of url with computed expression in combination with exit…
Browse files Browse the repository at this point in the history
…ing filters and bbox restrictions
  • Loading branch information
signedav authored and nyalldawson committed Jul 20, 2022
1 parent 93c1e4a commit 70425b4
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 46 deletions.
68 changes: 68 additions & 0 deletions src/core/qgsogcutils.cpp
Expand Up @@ -1952,6 +1952,74 @@ QDomElement QgsOgcUtils::expressionToOgcExpression( const QgsExpression &express
return QDomElement();
}

QDomElement QgsOgcUtils::expressionToOgcExpressionFilter( const QgsExpression &exp, QDomDocument &doc, QString *errorMessage )
{
return expressionToOgcExpressionFilter( exp, doc, GML_2_1_2, FILTER_OGC_1_0,
QStringLiteral( "geometry" ), QString(), false, false, errorMessage );
}


QDomElement QgsOgcUtils::expressionToOgcExpressionFilter( const QgsExpression &expression,
QDomDocument &doc,
GMLVersion gmlVersion,
FilterVersion filterVersion,
const QString &geometryName,
const QString &srsName,
bool honourAxisOrientation,
bool invertAxisOrientation,
QString *errorMessage )
{
QgsExpressionContext context;
context << QgsExpressionContextUtils::globalScope();

QgsExpression exp = expression;

const QgsExpressionNode *node = exp.rootNode();
if ( !node )
return QDomElement();

switch ( node->nodeType() )
{
case QgsExpressionNode::ntFunction:
case QgsExpressionNode::ntLiteral:
case QgsExpressionNode::ntColumnRef:
{
QgsOgcUtilsExprToFilter utils( doc, gmlVersion, filterVersion, geometryName, srsName, honourAxisOrientation, invertAxisOrientation );
const QDomElement exprRootElem = utils.expressionNodeToOgcFilter( node, &exp, &context );

if ( errorMessage )
*errorMessage = utils.errorMessage();

if ( !exprRootElem.isNull() )
{
QDomElement filterElem =
( filterVersion == FILTER_FES_2_0 ) ?
doc.createElementNS( FES_NAMESPACE, QStringLiteral( "fes:Filter" ) ) :
doc.createElementNS( OGC_NAMESPACE, QStringLiteral( "ogc:Filter" ) );
if ( utils.GMLNamespaceUsed() )
{
QDomAttr attr = doc.createAttribute( QStringLiteral( "xmlns:gml" ) );
if ( gmlVersion == GML_3_2_1 )
attr.setValue( GML32_NAMESPACE );
else
attr.setValue( GML_NAMESPACE );
filterElem.setAttributeNode( attr );
}
filterElem.appendChild( exprRootElem );
return filterElem;
}
break;
}
default:
{
if ( errorMessage )
*errorMessage = QObject::tr( "Node type not supported in expression translation: %1" ).arg( node->nodeType() );
}
}
// got an error
return QDomElement();
}

QDomElement QgsOgcUtils::SQLStatementToOgcFilter( const QgsSQLStatement &statement,
QDomDocument &doc,
GMLVersion gmlVersion,
Expand Down
22 changes: 22 additions & 0 deletions src/core/qgsogcutils.h
Expand Up @@ -231,6 +231,28 @@ class CORE_EXPORT QgsOgcUtils
bool invertAxisOrientation,
QString *errorMessage = nullptr );

/**
* Creates an OGC expression XML element.
* \returns valid OGC expression QDomElement on success,
* otherwise null QDomElement
*/
static QDomElement expressionToOgcExpressionFilter( const QgsExpression &exp, QDomDocument &doc, QString *errorMessage = nullptr );

/**
* Creates an OGC expression XML element.
* \returns valid OGC expression QDomElement on success,
* otherwise null QDomElement
*/
static QDomElement expressionToOgcExpressionFilter( const QgsExpression &exp,
QDomDocument &doc,
QgsOgcUtils::GMLVersion gmlVersion,
FilterVersion filterVersion,
const QString &geometryName,
const QString &srsName,
bool honourAxisOrientation,
bool invertAxisOrientation,
QString *errorMessage = nullptr );

#ifndef SIP_RUN

/**
Expand Down
2 changes: 2 additions & 0 deletions src/providers/wfs/qgsbackgroundcachedfeatureiterator.cpp
Expand Up @@ -277,7 +277,9 @@ QgsBackgroundCachedFeatureIterator::QgsBackgroundCachedFeatureIterator(
QString serverExpression;
if ( mRequest.filterType() == QgsFeatureRequest::FilterExpression && mRequest.filterExpression() && mRequest.filterExpression()->isValid() )
{
qDebug() << "WFS DEB expression: " << mRequest.filterExpression()->expression();
serverExpression = mShared->computedExpression( *mRequest.filterExpression() );
qDebug() << "WFS DEB EX" << serverExpression;
}

if ( !shared->clientSideFilterExpression().isEmpty() )
Expand Down
92 changes: 47 additions & 45 deletions src/providers/wfs/qgswfsfeatureiterator.cpp
Expand Up @@ -179,7 +179,9 @@ QUrl QgsWFSFeatureDownloaderImpl::buildURL( qint64 startIndex, long long maxFeat
// In case we must issue a BBOX and we have a filter, we must combine
// both as a single filter, as both BBOX and FILTER aren't supported together
if ( ( !rect.isNull() && !mShared->mWFSFilter.isEmpty() )
|| !mShared->mServerExpression.isEmpty() )
|| ( !mShared->mServerExpression.isEmpty() && !mShared->mWFSFilter.isEmpty() )
|| ( !rect.isNull() && !mShared->mServerExpression.isEmpty() )
)
{
QgsOgcUtils::GMLVersion gmlVersion;
QgsOgcUtils::FilterVersion filterVersion;
Expand All @@ -202,9 +204,9 @@ QUrl QgsWFSFeatureDownloaderImpl::buildURL( qint64 startIndex, long long maxFeat
filterVersion = QgsOgcUtils::FILTER_FES_2_0;
}

QDomDocument doc;
QDomElement andElem = doc.createElement( ( filterVersion == QgsOgcUtils::FILTER_FES_2_0 ) ? "fes:And" : "ogc:And" );
QDomElement filterElem = doc.createElement( "fes:Filter" );
QDomDocument bboxDoc;
QDomDocument filterDoc;
QDomDocument expressionDoc;

QString geometryAttribute( mShared->mGeometryAttribute );
if ( mShared->mLayerPropertiesList.size() > 1 )
Expand All @@ -215,6 +217,28 @@ QUrl QgsWFSFeatureDownloaderImpl::buildURL( qint64 startIndex, long long maxFeat
QDomNode bboxNode;
QDomNode filterNode;
QDomNode expressionNode;

QDomDocument envelopeFilterDoc;

//having a filter
if ( !mShared->mWFSFilter.isEmpty() )
{
( void )filterDoc.setContent( mShared->mWFSFilter, true );
filterNode = filterDoc.firstChildElement().firstChildElement();
filterNode = filterDoc.firstChildElement().removeChild( filterNode );
envelopeFilterDoc = filterDoc;
}

//having an expression
if ( !mShared->mServerExpression.isEmpty() )
{
( void )expressionDoc.setContent( mShared->mServerExpression, true );
expressionNode = expressionDoc.firstChildElement().firstChildElement();
expressionNode = expressionDoc.firstChildElement().removeChild( expressionNode );
envelopeFilterDoc = expressionDoc;
}

//having a bbox
if ( !rect.isNull() )
{
double minx = rect.xMinimum();
Expand All @@ -224,69 +248,43 @@ QUrl QgsWFSFeatureDownloaderImpl::buildURL( qint64 startIndex, long long maxFeat
QString filterBbox( QStringLiteral( "intersects_bbox($geometry, geomFromWKT('LINESTRING(%1 %2,%3 %4)'))" ).
arg( minx ).arg( miny ).arg( maxx ).arg( maxy ) );
QgsExpression bboxExp( filterBbox );
QDomDocument bboxDoc;
QDomElement bboxElem = QgsOgcUtils::expressionToOgcFilter( bboxExp, bboxDoc,
gmlVersion, filterVersion, geometryAttribute, mShared->srsName(),
honourAxisOrientation, mShared->mURI.invertAxisOrientation() );
bboxDoc.appendChild( bboxElem );

bboxNode = bboxElem.firstChildElement();
bboxNode = bboxElem.removeChild( bboxNode );
}
if ( !mShared->mWFSFilter.isEmpty() )
{
QDomDocument filterDoc;
( void )filterDoc.setContent( mShared->mWFSFilter, true );
filterNode = filterDoc.firstChildElement().firstChildElement();
filterNode = filterDoc.firstChildElement().removeChild( filterNode );
envelopeFilterDoc = bboxDoc;
}

if ( !mShared->mServerExpression.isEmpty() )
{
QDomDocument expressionDoc;
( void )expressionDoc.setContent( mShared->mServerExpression, true );
expressionNode = expressionDoc.firstChildElement();
expressionNode = expressionDoc.removeChild( expressionNode );
}
QDomElement andElem = envelopeFilterDoc.createElement( ( filterVersion == QgsOgcUtils::FILTER_FES_2_0 ) ? "fes:And" : "ogc:And" );
if ( !expressionNode.isNull() )
andElem.appendChild( expressionNode );
if ( !bboxNode.isNull() )
andElem.appendChild( bboxNode );
if ( !filterNode.isNull() )
andElem.appendChild( filterNode );

if ( expressionNode.isNull() && bboxNode.isNull() )
{
filterElem.appendChild( filterNode );
}
else if ( expressionNode.isNull() && filterNode.isNull() )
{
filterElem.appendChild( bboxNode );
}
else
{
filterElem.appendChild( andElem );
if ( !expressionNode.isNull() )
andElem.appendChild( expressionNode );
if ( !bboxNode.isNull() )
andElem.appendChild( bboxNode );
if ( !filterNode.isNull() )
andElem.appendChild( filterNode );
}
doc.appendChild( filterElem );

QString str;
QTextStream stream( &str );
filterElem.save( stream, 4 );
envelopeFilterDoc.firstChildElement().appendChild( andElem );

qDebug() << "WFS DEB filter " << mShared->mWFSFilter;
qDebug() << "WFS DEB expres " << mShared->mServerExpression;
QSet<QString> setNamespaceURI;
for ( const QgsOgcUtils::LayerProperties &props : std::as_const( mShared->mLayerPropertiesList ) )
{
if ( !props.mNamespacePrefix.isEmpty() && !props.mNamespaceURI.isEmpty() &&
!setNamespaceURI.contains( props.mNamespaceURI ) )
{
setNamespaceURI.insert( props.mNamespaceURI );
QDomAttr attr = doc.createAttribute( QStringLiteral( "xmlns:" ) + props.mNamespacePrefix );
QDomAttr attr = envelopeFilterDoc.createAttribute( QStringLiteral( "xmlns:" ) + props.mNamespacePrefix );
attr.setValue( props.mNamespaceURI );
doc.firstChildElement().setAttributeNode( attr );
envelopeFilterDoc.firstChildElement().setAttributeNode( attr );
}
}

query.addQueryItem( QStringLiteral( "FILTER" ), sanitizeFilter( doc.toString() ) );
qDebug() << "WFS DEB having the doc:\n" << envelopeFilterDoc.toString();
query.addQueryItem( QStringLiteral( "FILTER" ), sanitizeFilter( envelopeFilterDoc.toString() ) );
}
else if ( !rect.isNull() )
{
Expand Down Expand Up @@ -329,6 +327,10 @@ QUrl QgsWFSFeatureDownloaderImpl::buildURL( qint64 startIndex, long long maxFeat
{
query.addQueryItem( QStringLiteral( "FILTER" ), sanitizeFilter( mShared->mWFSFilter ) );
}
else if ( !mShared->mServerExpression.isEmpty() )
{
query.addQueryItem( QStringLiteral( "FILTER" ), sanitizeFilter( mShared->mServerExpression ) );
}

if ( !mShared->mSortBy.isEmpty() && !forHits )
{
Expand Down
2 changes: 1 addition & 1 deletion src/providers/wfs/qgswfsshareddata.cpp
Expand Up @@ -119,7 +119,7 @@ QString QgsWFSSharedData::computedExpression( const QgsExpression &expression )
if ( expression.isValid() )
{
QDomDocument expressionDoc;
QDomElement expressionElem = QgsOgcUtils::expressionToOgcExpression( expression, expressionDoc, gmlVersion, filterVersion, mGeometryAttribute, srsName(), honourAxisOrientation, mURI.invertAxisOrientation() );
QDomElement expressionElem = QgsOgcUtils::expressionToOgcExpressionFilter( expression, expressionDoc, gmlVersion, filterVersion, mGeometryAttribute, srsName(), honourAxisOrientation, mURI.invertAxisOrientation() );

if ( !expressionElem.isNull() )
{
Expand Down

0 comments on commit 70425b4

Please sign in to comment.