Skip to content

Commit edfa401

Browse files
committedSep 13, 2018
Add new class to build expression from WFS filter
1 parent 3b1b41f commit edfa401

File tree

2 files changed

+359
-255
lines changed

2 files changed

+359
-255
lines changed
 

‎src/core/qgsogcutils.cpp

Lines changed: 335 additions & 255 deletions
Original file line numberDiff line numberDiff line change
@@ -1600,6 +1600,11 @@ QColor QgsOgcUtils::colorFromOgcFill( const QDomElement &fillElement )
16001600

16011601

16021602
QgsExpression *QgsOgcUtils::expressionFromOgcFilter( const QDomElement &element, QgsVectorLayer *layer )
1603+
{
1604+
return expressionFromOgcFilter( element, QgsOgcUtils::FILTER_OGC_1_0, layer );
1605+
}
1606+
1607+
QgsExpression *QgsOgcUtils::expressionFromOgcFilter( const QDomElement &element, const FilterVersion version, QgsVectorLayer *layer )
16031608
{
16041609
if ( element.isNull() || !element.hasChildNodes() )
16051610
return nullptr;
@@ -1614,17 +1619,19 @@ QgsExpression *QgsOgcUtils::expressionFromOgcFilter( const QDomElement &element,
16141619
return expr;
16151620
}
16161621

1622+
QgsOgcUtilsExprFromFilter utils( version, layer );
1623+
16171624
// then check OGC DOM elements that contain OGC tags specifying
16181625
// OGC operators.
16191626
QDomElement childElem = element.firstChildElement();
16201627
while ( !childElem.isNull() )
16211628
{
1622-
QString errorMsg;
1623-
QgsExpressionNode *node = nodeFromOgcFilter( childElem, errorMsg, layer );
1629+
QgsExpressionNode *node = utils.nodeFromOgcFilter( childElem );
1630+
16241631
if ( !node )
16251632
{
16261633
// invalid expression, parser error
1627-
expr->d->mParserErrorString = errorMsg;
1634+
expr->d->mParserErrorString = utils.errorMessage();
16281635
return expr;
16291636
}
16301637

@@ -1647,7 +1654,6 @@ QgsExpression *QgsOgcUtils::expressionFromOgcFilter( const QDomElement &element,
16471654
return expr;
16481655
}
16491656

1650-
16511657
static const QMap<QString, int> BINARY_OPERATORS_TAG_NAMES_MAP
16521658
{
16531659
// logical
@@ -1701,173 +1707,22 @@ static bool isSpatialOperator( const QString &tagName )
17011707
return spatialOps.contains( tagName );
17021708
}
17031709

1704-
1705-
17061710
QgsExpressionNode *QgsOgcUtils::nodeFromOgcFilter( QDomElement &element, QString &errorMessage, QgsVectorLayer *layer )
17071711
{
1708-
if ( element.isNull() )
1709-
return nullptr;
1710-
1711-
// check for binary operators
1712-
if ( isBinaryOperator( element.tagName() ) )
1713-
{
1714-
return nodeBinaryOperatorFromOgcFilter( element, errorMessage, layer );
1715-
}
1716-
1717-
// check for spatial operators
1718-
if ( isSpatialOperator( element.tagName() ) )
1719-
{
1720-
return nodeSpatialOperatorFromOgcFilter( element, errorMessage );
1721-
}
1722-
1723-
// check for other OGC operators, convert them to expressions
1724-
1725-
if ( element.tagName() == QLatin1String( "Not" ) )
1726-
{
1727-
return nodeNotFromOgcFilter( element, errorMessage );
1728-
}
1729-
else if ( element.tagName() == QLatin1String( "PropertyIsNull" ) )
1730-
{
1731-
return nodePropertyIsNullFromOgcFilter( element, errorMessage );
1732-
}
1733-
else if ( element.tagName() == QLatin1String( "Literal" ) )
1734-
{
1735-
return nodeLiteralFromOgcFilter( element, errorMessage, layer );
1736-
}
1737-
else if ( element.tagName() == QLatin1String( "Function" ) )
1738-
{
1739-
return nodeFunctionFromOgcFilter( element, errorMessage );
1740-
}
1741-
else if ( element.tagName() == QLatin1String( "PropertyName" ) )
1742-
{
1743-
return nodeColumnRefFromOgcFilter( element, errorMessage );
1744-
}
1745-
else if ( element.tagName() == QLatin1String( "PropertyIsBetween" ) )
1746-
{
1747-
return nodeIsBetweenFromOgcFilter( element, errorMessage );
1748-
}
1749-
1750-
errorMessage += QObject::tr( "unable to convert '%1' element to a valid expression: it is not supported yet or it has invalid arguments" ).arg( element.tagName() );
1751-
return nullptr;
1712+
QgsOgcUtilsExprFromFilter utils( QgsOgcUtils::FILTER_OGC_1_0, layer );
1713+
QgsExpressionNode *node = utils.nodeFromOgcFilter( element );
1714+
errorMessage = utils.errorMessage();
1715+
return node;
17521716
}
17531717

1754-
1755-
17561718
QgsExpressionNodeBinaryOperator *QgsOgcUtils::nodeBinaryOperatorFromOgcFilter( QDomElement &element, QString &errorMessage, QgsVectorLayer *layer )
17571719
{
1758-
if ( element.isNull() )
1759-
return nullptr;
1760-
1761-
int op = binaryOperatorFromTagName( element.tagName() );
1762-
if ( op < 0 )
1763-
{
1764-
if ( errorMessage.isEmpty() )
1765-
errorMessage = QObject::tr( "'%1' binary operator not supported." ).arg( element.tagName() );
1766-
return nullptr;
1767-
}
1768-
1769-
if ( op == QgsExpressionNodeBinaryOperator::boLike && element.hasAttribute( QStringLiteral( "matchCase" ) ) && element.attribute( QStringLiteral( "matchCase" ) ) == QLatin1String( "false" ) )
1770-
{
1771-
op = QgsExpressionNodeBinaryOperator::boILike;
1772-
}
1773-
1774-
QDomElement operandElem = element.firstChildElement();
1775-
QgsExpressionNode *expr = nodeFromOgcFilter( operandElem, errorMessage, layer ), *leftOp = expr;
1776-
if ( !expr )
1777-
{
1778-
if ( errorMessage.isEmpty() )
1779-
errorMessage = QObject::tr( "invalid left operand for '%1' binary operator" ).arg( element.tagName() );
1780-
return nullptr;
1781-
}
1782-
1783-
for ( operandElem = operandElem.nextSiblingElement(); !operandElem.isNull(); operandElem = operandElem.nextSiblingElement() )
1784-
{
1785-
QgsExpressionNode *opRight = nodeFromOgcFilter( operandElem, errorMessage, layer );
1786-
if ( !opRight )
1787-
{
1788-
if ( errorMessage.isEmpty() )
1789-
errorMessage = QObject::tr( "invalid right operand for '%1' binary operator" ).arg( element.tagName() );
1790-
delete expr;
1791-
return nullptr;
1792-
}
1793-
1794-
if ( op == QgsExpressionNodeBinaryOperator::boLike || op == QgsExpressionNodeBinaryOperator::boILike )
1795-
{
1796-
QString wildCard;
1797-
if ( element.hasAttribute( QStringLiteral( "wildCard" ) ) )
1798-
{
1799-
wildCard = element.attribute( QStringLiteral( "wildCard" ) );
1800-
}
1801-
QString singleChar;
1802-
if ( element.hasAttribute( QStringLiteral( "singleChar" ) ) )
1803-
{
1804-
singleChar = element.attribute( QStringLiteral( "singleChar" ) );
1805-
}
1806-
QString escape = QStringLiteral( "\\" );
1807-
if ( element.hasAttribute( QStringLiteral( "escape" ) ) )
1808-
{
1809-
escape = element.attribute( QStringLiteral( "escape" ) );
1810-
}
1811-
// replace
1812-
QString oprValue = static_cast<const QgsExpressionNodeLiteral *>( opRight )->value().toString();
1813-
if ( !wildCard.isEmpty() && wildCard != QLatin1String( "%" ) )
1814-
{
1815-
oprValue.replace( '%', QLatin1String( "\\%" ) );
1816-
if ( oprValue.startsWith( wildCard ) )
1817-
{
1818-
oprValue.replace( 0, 1, QStringLiteral( "%" ) );
1819-
}
1820-
QRegExp rx( "[^" + QRegExp::escape( escape ) + "](" + QRegExp::escape( wildCard ) + ")" );
1821-
int pos = 0;
1822-
while ( ( pos = rx.indexIn( oprValue, pos ) ) != -1 )
1823-
{
1824-
oprValue.replace( pos + 1, 1, QStringLiteral( "%" ) );
1825-
pos += 1;
1826-
}
1827-
oprValue.replace( escape + wildCard, wildCard );
1828-
}
1829-
if ( !singleChar.isEmpty() && singleChar != QLatin1String( "_" ) )
1830-
{
1831-
oprValue.replace( '_', QLatin1String( "\\_" ) );
1832-
if ( oprValue.startsWith( singleChar ) )
1833-
{
1834-
oprValue.replace( 0, 1, QStringLiteral( "_" ) );
1835-
}
1836-
QRegExp rx( "[^" + QRegExp::escape( escape ) + "](" + QRegExp::escape( singleChar ) + ")" );
1837-
int pos = 0;
1838-
while ( ( pos = rx.indexIn( oprValue, pos ) ) != -1 )
1839-
{
1840-
oprValue.replace( pos + 1, 1, QStringLiteral( "_" ) );
1841-
pos += 1;
1842-
}
1843-
oprValue.replace( escape + singleChar, singleChar );
1844-
}
1845-
if ( !escape.isEmpty() && escape != QLatin1String( "\\" ) )
1846-
{
1847-
oprValue.replace( escape + escape, escape );
1848-
}
1849-
opRight = new QgsExpressionNodeLiteral( oprValue );
1850-
}
1851-
1852-
expr = new QgsExpressionNodeBinaryOperator( static_cast< QgsExpressionNodeBinaryOperator::BinaryOperator >( op ), expr, opRight );
1853-
}
1854-
1855-
if ( expr == leftOp )
1856-
{
1857-
if ( errorMessage.isEmpty() )
1858-
errorMessage = QObject::tr( "only one operand for '%1' binary operator" ).arg( element.tagName() );
1859-
delete expr;
1860-
return nullptr;
1861-
}
1862-
1863-
QgsExpressionNodeBinaryOperator *ret = dynamic_cast< QgsExpressionNodeBinaryOperator * >( expr );
1864-
if ( !ret )
1865-
delete expr;
1866-
1867-
return ret;
1720+
QgsOgcUtilsExprFromFilter utils( QgsOgcUtils::FILTER_OGC_1_0, layer );
1721+
QgsExpressionNode *node = utils.nodeBinaryOperatorFromOgcFilter( element );
1722+
errorMessage = utils.errorMessage();
1723+
retur node;
18681724
}
18691725

1870-
18711726
QgsExpressionNodeFunction *QgsOgcUtils::nodeSpatialOperatorFromOgcFilter( QDomElement &element, QString &errorMessage )
18721727
{
18731728
// we are exploiting the fact that our function names are the same as the XML tag names
@@ -1963,103 +1818,19 @@ QgsExpressionNodeFunction *QgsOgcUtils::nodeFunctionFromOgcFilter( QDomElement &
19631818

19641819
QgsExpressionNode *QgsOgcUtils::nodeLiteralFromOgcFilter( QDomElement &element, QString &errorMessage, QgsVectorLayer *layer )
19651820
{
1966-
if ( element.isNull() || element.tagName() != QLatin1String( "Literal" ) )
1967-
{
1968-
errorMessage = QObject::tr( "ogc:Literal expected, got %1" ).arg( element.tagName() );
1969-
return nullptr;
1970-
}
1971-
1972-
QgsExpressionNode *root = nullptr;
1973-
1974-
// the literal content can have more children (e.g. CDATA section, text, ...)
1975-
QDomNode childNode = element.firstChild();
1976-
while ( !childNode.isNull() )
1977-
{
1978-
QgsExpressionNode *operand = nullptr;
1979-
1980-
if ( childNode.nodeType() == QDomNode::ElementNode )
1981-
{
1982-
// found a element node (e.g. PropertyName), convert it
1983-
QDomElement operandElem = childNode.toElement();
1984-
operand = nodeFromOgcFilter( operandElem, errorMessage, layer );
1985-
if ( !operand )
1986-
{
1987-
delete root;
1988-
1989-
errorMessage = QObject::tr( "'%1' is an invalid or not supported content for ogc:Literal" ).arg( operandElem.tagName() );
1990-
return nullptr;
1991-
}
1992-
}
1993-
else
1994-
{
1995-
// probably a text/CDATA node
1996-
QVariant value = childNode.nodeValue();
1997-
1998-
bool converted = false;
1999-
2000-
// try to convert the node content to corresponding field type if possible
2001-
if ( layer != nullptr )
2002-
{
2003-
QDomElement propertyNameElement = element.previousSiblingElement( QLatin1String( "PropertyName" ) );
2004-
if ( propertyNameElement.isNull() || propertyNameElement.tagName() != QLatin1String( "PropertyName" ) )
2005-
{
2006-
propertyNameElement = element.nextSiblingElement( QLatin1String( "PropertyName" ) );
2007-
}
2008-
if ( !propertyNameElement.isNull() || propertyNameElement.tagName() == QLatin1String( "PropertyName" ) )
2009-
{
2010-
int fieldIndex = layer->fields().indexOf( propertyNameElement.firstChild().nodeValue() );
2011-
if ( fieldIndex != -1 )
2012-
{
2013-
QgsField field = layer->fields().field( propertyNameElement.firstChild().nodeValue() );
2014-
field.convertCompatible( value );
2015-
converted = true;
2016-
}
2017-
}
2018-
}
2019-
if ( !converted )
2020-
{
2021-
// try to convert the node content to number if possible,
2022-
// otherwise let's use it as string
2023-
bool ok;
2024-
double d = value.toDouble( &ok );
2025-
if ( ok )
2026-
value = d;
2027-
}
2028-
2029-
operand = new QgsExpressionNodeLiteral( value );
2030-
if ( !operand )
2031-
continue;
2032-
}
2033-
2034-
// use the concat operator to merge the ogc:Literal children
2035-
if ( !root )
2036-
{
2037-
root = operand;
2038-
}
2039-
else
2040-
{
2041-
root = new QgsExpressionNodeBinaryOperator( QgsExpressionNodeBinaryOperator::boConcat, root, operand );
2042-
}
2043-
2044-
childNode = childNode.nextSibling();
2045-
}
2046-
2047-
if ( root )
2048-
return root;
2049-
2050-
return nullptr;
1821+
QgsOgcUtilsExprFromFilter utils( QgsOgcUtils::FILTER_OGC_1_0, layer );
1822+
QgsExpressionNode *node = utils.nodeLiteralFromOgcFilter( element );
1823+
errorMessage = utils.errorMessage();
1824+
return node;
20511825
}
20521826

20531827

20541828
QgsExpressionNodeColumnRef *QgsOgcUtils::nodeColumnRefFromOgcFilter( QDomElement &element, QString &errorMessage )
20551829
{
2056-
if ( element.isNull() || element.tagName() != QLatin1String( "PropertyName" ) )
2057-
{
2058-
errorMessage = QObject::tr( "ogc:PropertyName expected, got %1" ).arg( element.tagName() );
2059-
return nullptr;
2060-
}
2061-
2062-
return new QgsExpressionNodeColumnRef( element.firstChild().nodeValue() );
1830+
QgsOgcUtilsExprFromFilter utils( QgsOgcUtils::FILTER_OGC_1_0 );
1831+
QgsExpressionNode *node = utils.nodeColumnRefFromOgcFilter( element );
1832+
errorMessage = utils.errorMessage();
1833+
return node;
20631834
}
20641835

20651836

@@ -3443,3 +3214,312 @@ QDomElement QgsOgcUtilsSQLStatementToFilter::toOgcFilter( const QgsSQLStatement:
34433214

34443215
return QDomElement();
34453216
}
3217+
3218+
QgsOgcUtilsExprFromFilter::QgsOgcUtilsExprFromFilter( const QgsOgcUtils::FilterVersion version, QgsVectorLayer *layer )
3219+
: mVersion( version )
3220+
, mLayer( layer )
3221+
{
3222+
mPropertyName = QStringLiteral( "PropertyName" );
3223+
3224+
if ( version == QgsOgcUtils::FILTER_FES_2_0 )
3225+
mPropertyName = QStringLiteral( "ValueReference" );
3226+
}
3227+
3228+
QgsExpressionNode *QgsOgcUtilsExprFromFilter::nodeFromOgcFilter( const QDomElement &element )
3229+
{
3230+
if ( element.isNull() )
3231+
return nullptr;
3232+
3233+
// check for binary operators
3234+
if ( isBinaryOperator( element.tagName() ) )
3235+
{
3236+
return nodeBinaryOperatorFromOgcFilter( element );
3237+
}
3238+
3239+
// check for spatial operators
3240+
if ( isSpatialOperator( element.tagName() ) )
3241+
{
3242+
return nodeSpatialOperatorFromOgcFilter( element );
3243+
}
3244+
3245+
// check for other OGC operators, convert them to expressions
3246+
3247+
if ( element.tagName() == QLatin1String( "Not" ) )
3248+
{
3249+
// return nodeNotFromOgcFilter( element, errorMessage );
3250+
}
3251+
else if ( element.tagName() == QLatin1String( "PropertyIsNull" ) )
3252+
{
3253+
// return nodePropertyIsNullFromOgcFilter( element, errorMessage );
3254+
}
3255+
else if ( element.tagName() == QLatin1String( "Literal" ) )
3256+
{
3257+
return nodeLiteralFromOgcFilter( element );
3258+
}
3259+
else if ( element.tagName() == QLatin1String( "Function" ) )
3260+
{
3261+
// return nodeFunctionFromOgcFilter( element, errorMessage );
3262+
}
3263+
else if ( element.tagName() == mPropertyName )
3264+
{
3265+
return nodeColumnRefFromOgcFilter( element );
3266+
}
3267+
else if ( element.tagName() == QLatin1String( "PropertyIsBetween" ) )
3268+
{
3269+
// return nodeIsBetweenFromOgcFilter( element, errorMessage );
3270+
}
3271+
3272+
mErrorMessage += QObject::tr( "unable to convert '%1' element to a valid expression: it is not supported yet or it has invalid arguments" ).arg( element.tagName() );
3273+
return nullptr;
3274+
}
3275+
3276+
QgsExpressionNodeBinaryOperator *QgsOgcUtilsExprFromFilter::nodeBinaryOperatorFromOgcFilter( const QDomElement &element )
3277+
{
3278+
if ( element.isNull() )
3279+
return nullptr;
3280+
3281+
int op = binaryOperatorFromTagName( element.tagName() );
3282+
if ( op < 0 )
3283+
{
3284+
mErrorMessage = QObject::tr( "'%1' binary operator not supported." ).arg( element.tagName() );
3285+
return nullptr;
3286+
}
3287+
3288+
if ( op == QgsExpressionNodeBinaryOperator::boLike && element.hasAttribute( QStringLiteral( "matchCase" ) ) && element.attribute( QStringLiteral( "matchCase" ) ) == QLatin1String( "false" ) )
3289+
{
3290+
op = QgsExpressionNodeBinaryOperator::boILike;
3291+
}
3292+
3293+
QDomElement operandElem = element.firstChildElement();
3294+
QgsExpressionNode *expr = nodeFromOgcFilter( operandElem ), *leftOp = expr;
3295+
if ( !expr )
3296+
{
3297+
mErrorMessage = QObject::tr( "invalid left operand for '%1' binary operator" ).arg( element.tagName() );
3298+
return nullptr;
3299+
}
3300+
3301+
for ( operandElem = operandElem.nextSiblingElement(); !operandElem.isNull(); operandElem = operandElem.nextSiblingElement() )
3302+
{
3303+
QgsExpressionNode *opRight = nodeFromOgcFilter( operandElem );
3304+
if ( !opRight )
3305+
{
3306+
mErrorMessage = QObject::tr( "invalid right operand for '%1' binary operator" ).arg( element.tagName() );
3307+
delete expr;
3308+
return nullptr;
3309+
}
3310+
3311+
if ( op == QgsExpressionNodeBinaryOperator::boLike || op == QgsExpressionNodeBinaryOperator::boILike )
3312+
{
3313+
QString wildCard;
3314+
if ( element.hasAttribute( QStringLiteral( "wildCard" ) ) )
3315+
{
3316+
wildCard = element.attribute( QStringLiteral( "wildCard" ) );
3317+
}
3318+
QString singleChar;
3319+
if ( element.hasAttribute( QStringLiteral( "singleChar" ) ) )
3320+
{
3321+
singleChar = element.attribute( QStringLiteral( "singleChar" ) );
3322+
}
3323+
QString escape = QStringLiteral( "\\" );
3324+
if ( element.hasAttribute( QStringLiteral( "escape" ) ) )
3325+
{
3326+
escape = element.attribute( QStringLiteral( "escape" ) );
3327+
}
3328+
// replace
3329+
QString oprValue = static_cast<const QgsExpressionNodeLiteral *>( opRight )->value().toString();
3330+
if ( !wildCard.isEmpty() && wildCard != QLatin1String( "%" ) )
3331+
{
3332+
oprValue.replace( '%', QLatin1String( "\\%" ) );
3333+
if ( oprValue.startsWith( wildCard ) )
3334+
{
3335+
oprValue.replace( 0, 1, QStringLiteral( "%" ) );
3336+
}
3337+
QRegExp rx( "[^" + QRegExp::escape( escape ) + "](" + QRegExp::escape( wildCard ) + ")" );
3338+
int pos = 0;
3339+
while ( ( pos = rx.indexIn( oprValue, pos ) ) != -1 )
3340+
{
3341+
oprValue.replace( pos + 1, 1, QStringLiteral( "%" ) );
3342+
pos += 1;
3343+
}
3344+
oprValue.replace( escape + wildCard, wildCard );
3345+
}
3346+
if ( !singleChar.isEmpty() && singleChar != QLatin1String( "_" ) )
3347+
{
3348+
oprValue.replace( '_', QLatin1String( "\\_" ) );
3349+
if ( oprValue.startsWith( singleChar ) )
3350+
{
3351+
oprValue.replace( 0, 1, QStringLiteral( "_" ) );
3352+
}
3353+
QRegExp rx( "[^" + QRegExp::escape( escape ) + "](" + QRegExp::escape( singleChar ) + ")" );
3354+
int pos = 0;
3355+
while ( ( pos = rx.indexIn( oprValue, pos ) ) != -1 )
3356+
{
3357+
oprValue.replace( pos + 1, 1, QStringLiteral( "_" ) );
3358+
pos += 1;
3359+
}
3360+
oprValue.replace( escape + singleChar, singleChar );
3361+
}
3362+
if ( !escape.isEmpty() && escape != QLatin1String( "\\" ) )
3363+
{
3364+
oprValue.replace( escape + escape, escape );
3365+
}
3366+
opRight = new QgsExpressionNodeLiteral( oprValue );
3367+
}
3368+
3369+
expr = new QgsExpressionNodeBinaryOperator( static_cast< QgsExpressionNodeBinaryOperator::BinaryOperator >( op ), expr, opRight );
3370+
}
3371+
3372+
if ( expr == leftOp )
3373+
{
3374+
mErrorMessage = QObject::tr( "only one operand for '%1' binary operator" ).arg( element.tagName() );
3375+
delete expr;
3376+
return nullptr;
3377+
}
3378+
3379+
QgsExpressionNodeBinaryOperator *ret = dynamic_cast< QgsExpressionNodeBinaryOperator * >( expr );
3380+
if ( !ret )
3381+
delete expr;
3382+
3383+
return ret;
3384+
}
3385+
3386+
3387+
QgsExpressionNodeFunction *QgsOgcUtilsExprFromFilter::nodeSpatialOperatorFromOgcFilter( const QDomElement &element )
3388+
{
3389+
// we are exploiting the fact that our function names are the same as the XML tag names
3390+
int opIdx = QgsExpression::functionIndex( element.tagName().toLower() );
3391+
3392+
QgsExpressionNode::NodeList *gml2Args = new QgsExpressionNode::NodeList();
3393+
QDomElement childElem = element.firstChildElement();
3394+
QString gml2Str;
3395+
while ( !childElem.isNull() && gml2Str.isEmpty() )
3396+
{
3397+
if ( childElem.tagName() != mPropertyName )
3398+
{
3399+
QTextStream gml2Stream( &gml2Str );
3400+
childElem.save( gml2Stream, 0 );
3401+
}
3402+
childElem = childElem.nextSiblingElement();
3403+
}
3404+
if ( !gml2Str.isEmpty() )
3405+
{
3406+
gml2Args->append( new QgsExpressionNodeLiteral( QVariant( gml2Str.remove( '\n' ) ) ) );
3407+
}
3408+
else
3409+
{
3410+
mErrorMessage = QObject::tr( "No OGC Geometry found" );
3411+
delete gml2Args;
3412+
return nullptr;
3413+
}
3414+
3415+
QgsExpressionNode::NodeList *opArgs = new QgsExpressionNode::NodeList();
3416+
opArgs->append( new QgsExpressionNodeFunction( QgsExpression::functionIndex( QStringLiteral( "$geometry" ) ), new QgsExpressionNode::NodeList() ) );
3417+
opArgs->append( new QgsExpressionNodeFunction( QgsExpression::functionIndex( QStringLiteral( "geomFromGML" ) ), gml2Args ) );
3418+
3419+
return new QgsExpressionNodeFunction( opIdx, opArgs );
3420+
}
3421+
3422+
QgsExpressionNodeColumnRef *QgsOgcUtilsExprFromFilter::nodeColumnRefFromOgcFilter( const QDomElement &element )
3423+
{
3424+
if ( element.isNull() || element.tagName() != mPropertyName )
3425+
{
3426+
mErrorMessage = QObject::tr( "ogc:PropertyName expected, got %1" ).arg( element.tagName() );
3427+
return nullptr;
3428+
}
3429+
3430+
return new QgsExpressionNodeColumnRef( element.firstChild().nodeValue() );
3431+
}
3432+
3433+
QgsExpressionNode *QgsOgcUtilsExprFromFilter::nodeLiteralFromOgcFilter( const QDomElement &element )
3434+
{
3435+
if ( element.isNull() || element.tagName() != QLatin1String( "Literal" ) )
3436+
{
3437+
mErrorMessage = QObject::tr( "ogc:Literal expected, got %1" ).arg( element.tagName() );
3438+
return nullptr;
3439+
}
3440+
3441+
QgsExpressionNode *root = nullptr;
3442+
3443+
// the literal content can have more children (e.g. CDATA section, text, ...)
3444+
QDomNode childNode = element.firstChild();
3445+
while ( !childNode.isNull() )
3446+
{
3447+
QgsExpressionNode *operand = nullptr;
3448+
3449+
if ( childNode.nodeType() == QDomNode::ElementNode )
3450+
{
3451+
// found a element node (e.g. PropertyName), convert it
3452+
QDomElement operandElem = childNode.toElement();
3453+
operand = nodeFromOgcFilter( operandElem );
3454+
if ( !operand )
3455+
{
3456+
delete root;
3457+
3458+
mErrorMessage = QObject::tr( "'%1' is an invalid or not supported content for ogc:Literal" ).arg( operandElem.tagName() );
3459+
return nullptr;
3460+
}
3461+
}
3462+
else
3463+
{
3464+
// probably a text/CDATA node
3465+
QVariant value = childNode.nodeValue();
3466+
3467+
bool converted = false;
3468+
3469+
// try to convert the node content to corresponding field type if possible
3470+
if ( mLayer )
3471+
{
3472+
QDomElement propertyNameElement = element.previousSiblingElement( mPropertyName );
3473+
if ( propertyNameElement.isNull() || propertyNameElement.tagName() != mPropertyName )
3474+
{
3475+
propertyNameElement = element.nextSiblingElement( mPropertyName );
3476+
}
3477+
if ( !propertyNameElement.isNull() || propertyNameElement.tagName() == mPropertyName )
3478+
{
3479+
int fieldIndex = mLayer->fields().indexOf( propertyNameElement.firstChild().nodeValue() );
3480+
if ( fieldIndex != -1 )
3481+
{
3482+
QgsField field = mLayer->fields().field( propertyNameElement.firstChild().nodeValue() );
3483+
field.convertCompatible( value );
3484+
converted = true;
3485+
}
3486+
}
3487+
}
3488+
if ( !converted )
3489+
{
3490+
// try to convert the node content to number if possible,
3491+
// otherwise let's use it as string
3492+
bool ok;
3493+
double d = value.toDouble( &ok );
3494+
if ( ok )
3495+
value = d;
3496+
}
3497+
3498+
operand = new QgsExpressionNodeLiteral( value );
3499+
if ( !operand )
3500+
continue;
3501+
}
3502+
3503+
// use the concat operator to merge the ogc:Literal children
3504+
if ( !root )
3505+
{
3506+
root = operand;
3507+
}
3508+
else
3509+
{
3510+
root = new QgsExpressionNodeBinaryOperator( QgsExpressionNodeBinaryOperator::boConcat, root, operand );
3511+
}
3512+
3513+
childNode = childNode.nextSibling();
3514+
}
3515+
3516+
if ( root )
3517+
return root;
3518+
3519+
return nullptr;
3520+
}
3521+
3522+
QString QgsOgcUtilsExprFromFilter::errorMessage() const
3523+
{
3524+
return mErrorMessage;
3525+
}

‎src/core/qgsogcutils.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ class CORE_EXPORT QgsOgcUtils
161161
FILTER_FES_2_0
162162
};
163163

164+
static QgsExpression *expressionFromOgcFilter( const QDomElement &element, FilterVersion version, QgsVectorLayer *layer = nullptr ) SIP_FACTORY;
165+
164166
/**
165167
* Creates OGC filter XML element. Supports minimum standard filter
166168
* according to the OGC filter specs (=,!=,<,>,<=,>=,AND,OR,NOT)
@@ -367,6 +369,28 @@ class QgsOgcUtilsExprToFilter
367369
QDomElement expressionFunctionToOgcFilter( const QgsExpressionNodeFunction *node, QgsExpression *expression, const QgsExpressionContext *context );
368370
};
369371

372+
class QgsOgcUtilsExprFromFilter
373+
{
374+
public:
375+
QgsOgcUtilsExprFromFilter( QgsOgcUtils::FilterVersion version = QgsOgcUtils::FILTER_OGC_1_0,
376+
QgsVectorLayer *layer = nullptr );
377+
378+
QgsExpressionNode *nodeFromOgcFilter( const QDomElement &element );
379+
380+
QString errorMessage() const;
381+
382+
QgsExpressionNodeBinaryOperator *nodeBinaryOperatorFromOgcFilter( const QDomElement &element );
383+
QgsExpressionNodeFunction *nodeSpatialOperatorFromOgcFilter( const QDomElement &element );
384+
QgsExpressionNodeColumnRef *nodeColumnRefFromOgcFilter( const QDomElement &element );
385+
QgsExpressionNode *nodeLiteralFromOgcFilter( const QDomElement &element );
386+
387+
private:
388+
QgsOgcUtils::FilterVersion mVersion = QgsOgcUtils::FILTER_OGC_1_0;
389+
QgsVectorLayer *mLayer = nullptr;
390+
QString mErrorMessage;
391+
QString mPropertyName;
392+
};
393+
370394
/**
371395
* \ingroup core
372396
* Internal use by QgsOgcUtils

0 commit comments

Comments
 (0)
Please sign in to comment.