27 #include <QStringList> 28 #include <QTextStream> 32 #include <netinet/in.h> 38 static const QString
GML_NAMESPACE = QStringLiteral(
"http://www.opengis.net/gml" );
39 static const QString GML32_NAMESPACE = QStringLiteral(
"http://www.opengis.net/gml/3.2" );
40 static const QString OGC_NAMESPACE = QStringLiteral(
"http://www.opengis.net/ogc" );
41 static const QString FES_NAMESPACE = QStringLiteral(
"http://www.opengis.net/fes/2.0" );
46 const QString &geometryName,
47 const QString &srsName,
48 bool honourAxisOrientation,
49 bool invertAxisOrientation )
52 , mGMLVersion( gmlVersion )
53 , mFilterVersion( filterVersion )
54 , mGeometryName( geometryName )
56 , mInvertAxisOrientation( invertAxisOrientation )
57 , mFilterPrefix( ( filterVersion ==
QgsOgcUtils::FILTER_FES_2_0 ) ?
"fes" :
"ogc" )
58 , mPropertyName( ( filterVersion ==
QgsOgcUtils::FILTER_FES_2_0 ) ?
"ValueReference" :
"PropertyName" )
62 if ( !mSrsName.isEmpty() )
68 mInvertAxisOrientation = !mInvertAxisOrientation;
75 QDomElement geometryTypeElement = geometryNode.toElement();
76 QString geomType = geometryTypeElement.tagName();
78 if ( !( geomType == QLatin1String(
"Point" ) || geomType == QLatin1String(
"LineString" ) || geomType == QLatin1String(
"Polygon" ) ||
79 geomType == QLatin1String(
"MultiPoint" ) || geomType == QLatin1String(
"MultiLineString" ) || geomType == QLatin1String(
"MultiPolygon" ) ||
80 geomType == QLatin1String(
"Box" ) || geomType == QLatin1String(
"Envelope" ) ) )
82 QDomNode geometryChild = geometryNode.firstChild();
83 if ( geometryChild.isNull() )
87 geometryTypeElement = geometryChild.toElement();
88 geomType = geometryTypeElement.tagName();
91 if ( !( geomType == QLatin1String(
"Point" ) || geomType == QLatin1String(
"LineString" ) || geomType == QLatin1String(
"Polygon" ) ||
92 geomType == QLatin1String(
"MultiPoint" ) || geomType == QLatin1String(
"MultiLineString" ) || geomType == QLatin1String(
"MultiPolygon" ) ||
93 geomType == QLatin1String(
"Box" ) || geomType == QLatin1String(
"Envelope" ) ) )
96 if ( geomType == QLatin1String(
"Point" ) )
98 return geometryFromGMLPoint( geometryTypeElement );
100 else if ( geomType == QLatin1String(
"LineString" ) )
102 return geometryFromGMLLineString( geometryTypeElement );
104 else if ( geomType == QLatin1String(
"Polygon" ) )
106 return geometryFromGMLPolygon( geometryTypeElement );
108 else if ( geomType == QLatin1String(
"MultiPoint" ) )
110 return geometryFromGMLMultiPoint( geometryTypeElement );
112 else if ( geomType == QLatin1String(
"MultiLineString" ) )
114 return geometryFromGMLMultiLineString( geometryTypeElement );
116 else if ( geomType == QLatin1String(
"MultiPolygon" ) )
118 return geometryFromGMLMultiPolygon( geometryTypeElement );
120 else if ( geomType == QLatin1String(
"Box" ) )
124 else if ( geomType == QLatin1String(
"Envelope" ) )
137 QString xml = QStringLiteral(
"<tmp xmlns=\"%1\" xmlns:gml=\"%1\">%2</tmp>" ).arg(
GML_NAMESPACE, xmlString );
139 if ( !doc.setContent( xml,
true ) )
142 return geometryFromGML( doc.documentElement().firstChildElement() );
146 QgsGeometry QgsOgcUtils::geometryFromGMLPoint(
const QDomElement &geometryElement )
150 QDomNodeList coordList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
151 if ( !coordList.isEmpty() )
153 QDomElement coordElement = coordList.at( 0 ).toElement();
154 if ( readGMLCoordinates( pointCoordinate, coordElement ) != 0 )
161 QDomNodeList posList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"pos" ) );
162 if ( posList.size() < 1 )
166 QDomElement posElement = posList.at( 0 ).toElement();
167 if ( readGMLPositions( pointCoordinate, posElement ) != 0 )
173 if ( pointCoordinate.empty() )
178 QgsPolylineXY::const_iterator point_it = pointCoordinate.constBegin();
179 char e = htonl( 1 ) != 1;
180 double x = point_it->x();
181 double y = point_it->y();
182 int size = 1 +
sizeof( int ) + 2 *
sizeof(
double );
185 unsigned char *wkb =
new unsigned char[size];
188 memcpy( &( wkb )[wkbPosition], &e, 1 );
190 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
191 wkbPosition +=
sizeof( int );
192 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
193 wkbPosition +=
sizeof( double );
194 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
201 QgsGeometry QgsOgcUtils::geometryFromGMLLineString(
const QDomElement &geometryElement )
205 QDomNodeList coordList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
206 if ( !coordList.isEmpty() )
208 QDomElement coordElement = coordList.at( 0 ).toElement();
209 if ( readGMLCoordinates( lineCoordinates, coordElement ) != 0 )
216 QDomNodeList posList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"posList" ) );
217 if ( posList.size() < 1 )
221 QDomElement posElement = posList.at( 0 ).toElement();
222 if ( readGMLPositions( lineCoordinates, posElement ) != 0 )
228 char e = htonl( 1 ) != 1;
229 int size = 1 + 2 *
sizeof( int ) + lineCoordinates.size() * 2 *
sizeof( double );
232 unsigned char *wkb =
new unsigned char[size];
236 int nPoints = lineCoordinates.size();
239 memcpy( &( wkb )[wkbPosition], &e, 1 );
241 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
242 wkbPosition +=
sizeof( int );
243 memcpy( &( wkb )[wkbPosition], &nPoints,
sizeof(
int ) );
244 wkbPosition +=
sizeof( int );
246 QgsPolylineXY::const_iterator iter;
247 for ( iter = lineCoordinates.constBegin(); iter != lineCoordinates.constEnd(); ++iter )
251 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
252 wkbPosition +=
sizeof( double );
253 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
254 wkbPosition +=
sizeof( double );
262 QgsGeometry QgsOgcUtils::geometryFromGMLPolygon(
const QDomElement &geometryElement )
269 QDomNodeList outerBoundaryList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"outerBoundaryIs" ) );
270 if ( !outerBoundaryList.isEmpty() )
272 QDomElement coordinatesElement = outerBoundaryList.at( 0 ).firstChild().firstChild().toElement();
273 if ( coordinatesElement.isNull() )
277 if ( readGMLCoordinates( exteriorPointList, coordinatesElement ) != 0 )
281 ringCoordinates.push_back( exteriorPointList );
284 QDomNodeList innerBoundaryList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"innerBoundaryIs" ) );
285 for (
int i = 0; i < innerBoundaryList.size(); ++i )
288 coordinatesElement = innerBoundaryList.at( i ).firstChild().firstChild().toElement();
289 if ( coordinatesElement.isNull() )
293 if ( readGMLCoordinates( interiorPointList, coordinatesElement ) != 0 )
297 ringCoordinates.push_back( interiorPointList );
303 QDomNodeList exteriorList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"exterior" ) );
304 if ( exteriorList.size() < 1 )
308 QDomElement posElement = exteriorList.at( 0 ).firstChild().firstChild().toElement();
309 if ( posElement.isNull() )
313 if ( readGMLPositions( exteriorPointList, posElement ) != 0 )
317 ringCoordinates.push_back( exteriorPointList );
320 QDomNodeList interiorList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"interior" ) );
321 for (
int i = 0; i < interiorList.size(); ++i )
324 QDomElement posElement = interiorList.at( i ).firstChild().firstChild().toElement();
325 if ( posElement.isNull() )
329 if ( readGMLPositions( interiorPointList, posElement ) != 0 )
333 ringCoordinates.push_back( interiorPointList );
338 int nrings = ringCoordinates.size();
343 for ( QgsMultiPolylineXY::const_iterator it = ringCoordinates.constBegin(); it != ringCoordinates.constEnd(); ++it )
345 npoints += it->size();
347 int size = 1 + 2 *
sizeof( int ) + nrings *
sizeof(
int ) + 2 * npoints *
sizeof( double );
350 unsigned char *wkb =
new unsigned char[size];
353 char e = htonl( 1 ) != 1;
355 int nPointsInRing = 0;
359 memcpy( &( wkb )[wkbPosition], &e, 1 );
361 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
362 wkbPosition +=
sizeof( int );
363 memcpy( &( wkb )[wkbPosition], &nrings,
sizeof(
int ) );
364 wkbPosition +=
sizeof( int );
365 for ( QgsMultiPolylineXY::const_iterator it = ringCoordinates.constBegin(); it != ringCoordinates.constEnd(); ++it )
367 nPointsInRing = it->size();
368 memcpy( &( wkb )[wkbPosition], &nPointsInRing,
sizeof(
int ) );
369 wkbPosition +=
sizeof( int );
371 QgsPolylineXY::const_iterator iter;
372 for ( iter = it->begin(); iter != it->end(); ++iter )
377 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
378 wkbPosition +=
sizeof( double );
379 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
380 wkbPosition +=
sizeof( double );
389 QgsGeometry QgsOgcUtils::geometryFromGMLMultiPoint(
const QDomElement &geometryElement )
393 QDomNodeList pointMemberList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"pointMember" ) );
394 if ( pointMemberList.size() < 1 )
398 QDomNodeList pointNodeList;
400 QDomNodeList coordinatesList;
401 QDomNodeList posList;
402 for (
int i = 0; i < pointMemberList.size(); ++i )
405 pointNodeList = pointMemberList.at( i ).toElement().elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"Point" ) );
406 if ( pointNodeList.size() < 1 )
411 coordinatesList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
412 if ( !coordinatesList.isEmpty() )
414 currentPoint.clear();
415 if ( readGMLCoordinates( currentPoint, coordinatesList.at( 0 ).toElement() ) != 0 )
419 if ( currentPoint.empty() )
423 pointList.push_back( ( *currentPoint.begin() ) );
429 posList = pointNodeList.at( 0 ).toElement().elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"pos" ) );
430 if ( posList.size() < 1 )
434 currentPoint.clear();
435 if ( readGMLPositions( currentPoint, posList.at( 0 ).toElement() ) != 0 )
439 if ( currentPoint.empty() )
443 pointList.push_back( ( *currentPoint.begin() ) );
447 int nPoints = pointList.size();
452 int size = 1 + 2 *
sizeof( int ) + pointList.size() * ( 2 *
sizeof( double ) + 1 +
sizeof(
int ) );
455 unsigned char *wkb =
new unsigned char[size];
458 char e = htonl( 1 ) != 1;
461 memcpy( &( wkb )[wkbPosition], &e, 1 );
463 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
464 wkbPosition +=
sizeof( int );
465 memcpy( &( wkb )[wkbPosition], &nPoints,
sizeof(
int ) );
466 wkbPosition +=
sizeof( int );
468 for ( QgsPolylineXY::const_iterator it = pointList.constBegin(); it != pointList.constEnd(); ++it )
470 memcpy( &( wkb )[wkbPosition], &e, 1 );
472 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
473 wkbPosition +=
sizeof( int );
475 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
476 wkbPosition +=
sizeof( double );
478 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
479 wkbPosition +=
sizeof( double );
487 QgsGeometry QgsOgcUtils::geometryFromGMLMultiLineString(
const QDomElement &geometryElement )
498 QList< QgsPolylineXY > lineCoordinates;
499 QDomElement currentLineStringElement;
500 QDomNodeList currentCoordList;
501 QDomNodeList currentPosList;
503 QDomNodeList lineStringMemberList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"lineStringMember" ) );
504 if ( !lineStringMemberList.isEmpty() )
506 for (
int i = 0; i < lineStringMemberList.size(); ++i )
508 QDomNodeList lineStringNodeList = lineStringMemberList.at( i ).toElement().elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LineString" ) );
509 if ( lineStringNodeList.size() < 1 )
513 currentLineStringElement = lineStringNodeList.at( 0 ).toElement();
514 currentCoordList = currentLineStringElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
515 if ( !currentCoordList.isEmpty() )
518 if ( readGMLCoordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 )
522 lineCoordinates.push_back( currentPointList );
526 currentPosList = currentLineStringElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"posList" ) );
527 if ( currentPosList.size() < 1 )
532 if ( readGMLPositions( currentPointList, currentPosList.at( 0 ).toElement() ) != 0 )
536 lineCoordinates.push_back( currentPointList );
542 QDomNodeList lineStringList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LineString" ) );
543 if ( !lineStringList.isEmpty() )
545 for (
int i = 0; i < lineStringList.size(); ++i )
547 currentLineStringElement = lineStringList.at( i ).toElement();
548 currentCoordList = currentLineStringElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
549 if ( !currentCoordList.isEmpty() )
552 if ( readGMLCoordinates( currentPointList, currentCoordList.at( 0 ).toElement() ) != 0 )
556 lineCoordinates.push_back( currentPointList );
561 currentPosList = currentLineStringElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"posList" ) );
562 if ( currentPosList.size() < 1 )
567 if ( readGMLPositions( currentPointList, currentPosList.at( 0 ).toElement() ) != 0 )
571 lineCoordinates.push_back( currentPointList );
581 int nLines = lineCoordinates.size();
586 int size = ( lineCoordinates.size() + 1 ) * ( 1 + 2 *
sizeof(
int ) );
587 for ( QList< QgsPolylineXY >::const_iterator it = lineCoordinates.constBegin(); it != lineCoordinates.constEnd(); ++it )
589 size += it->size() * 2 *
sizeof( double );
593 unsigned char *wkb =
new unsigned char[size];
596 char e = htonl( 1 ) != 1;
600 memcpy( &( wkb )[wkbPosition], &e, 1 );
602 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
603 wkbPosition +=
sizeof( int );
604 memcpy( &( wkb )[wkbPosition], &nLines,
sizeof(
int ) );
605 wkbPosition +=
sizeof( int );
607 for ( QList< QgsPolylineXY >::const_iterator it = lineCoordinates.constBegin(); it != lineCoordinates.constEnd(); ++it )
609 memcpy( &( wkb )[wkbPosition], &e, 1 );
611 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
612 wkbPosition +=
sizeof( int );
613 nPoints = it->size();
614 memcpy( &( wkb )[wkbPosition], &nPoints,
sizeof(
int ) );
615 wkbPosition +=
sizeof( int );
616 for ( QgsPolylineXY::const_iterator iter = it->begin(); iter != it->end(); ++iter )
621 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
622 wkbPosition +=
sizeof( double );
623 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
624 wkbPosition +=
sizeof( double );
633 QgsGeometry QgsOgcUtils::geometryFromGMLMultiPolygon(
const QDomElement &geometryElement )
637 QDomElement currentPolygonMemberElement;
638 QDomNodeList polygonList;
639 QDomElement currentPolygonElement;
641 QDomNodeList outerBoundaryList;
642 QDomElement currentOuterBoundaryElement;
643 QDomNodeList innerBoundaryList;
644 QDomElement currentInnerBoundaryElement;
646 QDomNodeList exteriorList;
647 QDomElement currentExteriorElement;
648 QDomElement currentInteriorElement;
649 QDomNodeList interiorList;
651 QDomNodeList linearRingNodeList;
652 QDomElement currentLinearRingElement;
654 QDomNodeList currentCoordinateList;
655 QDomNodeList currentPosList;
657 QDomNodeList polygonMemberList = geometryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"polygonMember" ) );
659 for (
int i = 0; i < polygonMemberList.size(); ++i )
661 currentPolygonList.resize( 0 );
662 currentPolygonMemberElement = polygonMemberList.at( i ).toElement();
663 polygonList = currentPolygonMemberElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"Polygon" ) );
664 if ( polygonList.size() < 1 )
668 currentPolygonElement = polygonList.at( 0 ).toElement();
671 outerBoundaryList = currentPolygonElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"outerBoundaryIs" ) );
672 if ( !outerBoundaryList.isEmpty() )
674 currentOuterBoundaryElement = outerBoundaryList.at( 0 ).toElement();
677 linearRingNodeList = currentOuterBoundaryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LinearRing" ) );
678 if ( linearRingNodeList.size() < 1 )
682 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
683 currentCoordinateList = currentLinearRingElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
684 if ( currentCoordinateList.size() < 1 )
688 if ( readGMLCoordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 )
692 currentPolygonList.push_back( ringCoordinates );
695 QDomNodeList innerBoundaryList = currentPolygonElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"innerBoundaryIs" ) );
696 for (
int j = 0; j < innerBoundaryList.size(); ++j )
699 currentInnerBoundaryElement = innerBoundaryList.at( j ).toElement();
700 linearRingNodeList = currentInnerBoundaryElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LinearRing" ) );
701 if ( linearRingNodeList.size() < 1 )
705 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
706 currentCoordinateList = currentLinearRingElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"coordinates" ) );
707 if ( currentCoordinateList.size() < 1 )
711 if ( readGMLCoordinates( ringCoordinates, currentCoordinateList.at( 0 ).toElement() ) != 0 )
715 currentPolygonList.push_back( ringCoordinates );
721 exteriorList = currentPolygonElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"exterior" ) );
722 if ( exteriorList.size() < 1 )
727 currentExteriorElement = exteriorList.at( 0 ).toElement();
730 linearRingNodeList = currentExteriorElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LinearRing" ) );
731 if ( linearRingNodeList.size() < 1 )
735 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
736 currentPosList = currentLinearRingElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"posList" ) );
737 if ( currentPosList.size() < 1 )
741 if ( readGMLPositions( ringPositions, currentPosList.at( 0 ).toElement() ) != 0 )
745 currentPolygonList.push_back( ringPositions );
748 QDomNodeList interiorList = currentPolygonElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"interior" ) );
749 for (
int j = 0; j < interiorList.size(); ++j )
752 currentInteriorElement = interiorList.at( j ).toElement();
753 linearRingNodeList = currentInteriorElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"LinearRing" ) );
754 if ( linearRingNodeList.size() < 1 )
758 currentLinearRingElement = linearRingNodeList.at( 0 ).toElement();
759 currentPosList = currentLinearRingElement.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"posList" ) );
760 if ( currentPosList.size() < 1 )
764 if ( readGMLPositions( ringPositions, currentPosList.at( 0 ).toElement() ) != 0 )
768 currentPolygonList.push_back( ringPositions );
771 multiPolygonPoints.push_back( currentPolygonList );
774 int nPolygons = multiPolygonPoints.size();
778 int size = 1 + 2 *
sizeof( int );
780 for ( QgsMultiPolygonXY::const_iterator it = multiPolygonPoints.constBegin(); it != multiPolygonPoints.constEnd(); ++it )
782 size += 1 + 2 *
sizeof( int );
783 for ( QgsPolygonXY::const_iterator iter = it->begin(); iter != it->end(); ++iter )
785 size +=
sizeof( int ) + 2 * iter->size() *
sizeof( double );
790 unsigned char *wkb =
new unsigned char[size];
792 char e = htonl( 1 ) != 1;
799 memcpy( &( wkb )[wkbPosition], &e, 1 );
801 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
802 wkbPosition +=
sizeof( int );
803 memcpy( &( wkb )[wkbPosition], &nPolygons,
sizeof(
int ) );
804 wkbPosition +=
sizeof( int );
808 for ( QgsMultiPolygonXY::const_iterator it = multiPolygonPoints.constBegin(); it != multiPolygonPoints.constEnd(); ++it )
810 memcpy( &( wkb )[wkbPosition], &e, 1 );
812 memcpy( &( wkb )[wkbPosition], &type,
sizeof(
int ) );
813 wkbPosition +=
sizeof( int );
815 memcpy( &( wkb )[wkbPosition], &nRings,
sizeof(
int ) );
816 wkbPosition +=
sizeof( int );
817 for ( QgsPolygonXY::const_iterator iter = it->begin(); iter != it->end(); ++iter )
819 nPointsInRing = iter->size();
820 memcpy( &( wkb )[wkbPosition], &nPointsInRing,
sizeof(
int ) );
821 wkbPosition +=
sizeof( int );
822 for ( QgsPolylineXY::const_iterator iterator = iter->begin(); iterator != iter->end(); ++iterator )
826 memcpy( &( wkb )[wkbPosition], &x,
sizeof(
double ) );
827 wkbPosition +=
sizeof( double );
828 memcpy( &( wkb )[wkbPosition], &y,
sizeof(
double ) );
829 wkbPosition +=
sizeof( double );
839 bool QgsOgcUtils::readGMLCoordinates(
QgsPolylineXY &coords,
const QDomElement &elem )
841 QString coordSeparator = QStringLiteral(
"," );
842 QString tupelSeparator = QStringLiteral(
" " );
847 if ( elem.hasAttribute( QStringLiteral(
"cs" ) ) )
849 coordSeparator = elem.attribute( QStringLiteral(
"cs" ) );
851 if ( elem.hasAttribute( QStringLiteral(
"ts" ) ) )
853 tupelSeparator = elem.attribute( QStringLiteral(
"ts" ) );
856 QStringList tupels = elem.text().split( tupelSeparator, QString::SkipEmptyParts );
857 QStringList tupel_coords;
859 bool conversionSuccess;
861 QStringList::const_iterator it;
862 for ( it = tupels.constBegin(); it != tupels.constEnd(); ++it )
864 tupel_coords = ( *it ).split( coordSeparator, QString::SkipEmptyParts );
865 if ( tupel_coords.size() < 2 )
869 x = tupel_coords.at( 0 ).toDouble( &conversionSuccess );
870 if ( !conversionSuccess )
874 y = tupel_coords.at( 1 ).toDouble( &conversionSuccess );
875 if ( !conversionSuccess )
888 QDomElement boxElem = boxNode.toElement();
889 if ( boxElem.tagName() != QLatin1String(
"Box" ) )
892 QDomElement bElem = boxElem.firstChild().toElement();
893 QString coordSeparator = QStringLiteral(
"," );
894 QString tupelSeparator = QStringLiteral(
" " );
895 if ( bElem.hasAttribute( QStringLiteral(
"cs" ) ) )
897 coordSeparator = bElem.attribute( QStringLiteral(
"cs" ) );
899 if ( bElem.hasAttribute( QStringLiteral(
"ts" ) ) )
901 tupelSeparator = bElem.attribute( QStringLiteral(
"ts" ) );
904 QString bString = bElem.text();
905 bool ok1, ok2, ok3, ok4;
906 double xmin = bString.section( tupelSeparator, 0, 0 ).section( coordSeparator, 0, 0 ).toDouble( &ok1 );
907 double ymin = bString.section( tupelSeparator, 0, 0 ).section( coordSeparator, 1, 1 ).toDouble( &ok2 );
908 double xmax = bString.section( tupelSeparator, 1, 1 ).section( coordSeparator, 0, 0 ).toDouble( &ok3 );
909 double ymax = bString.section( tupelSeparator, 1, 1 ).section( coordSeparator, 1, 1 ).toDouble( &ok4 );
911 if ( ok1 && ok2 && ok3 && ok4 )
920 bool QgsOgcUtils::readGMLPositions(
QgsPolylineXY &coords,
const QDomElement &elem )
924 QStringList pos = elem.text().split(
' ', QString::SkipEmptyParts );
926 bool conversionSuccess;
927 int posSize = pos.size();
929 int srsDimension = 2;
930 if ( elem.hasAttribute( QStringLiteral(
"srsDimension" ) ) )
932 srsDimension = elem.attribute( QStringLiteral(
"srsDimension" ) ).toInt( &conversionSuccess );
933 if ( !conversionSuccess )
938 else if ( elem.hasAttribute( QStringLiteral(
"dimension" ) ) )
940 srsDimension = elem.attribute( QStringLiteral(
"dimension" ) ).toInt( &conversionSuccess );
941 if ( !conversionSuccess )
947 for (
int i = 0; i < posSize / srsDimension; i++ )
949 x = pos.at( i * srsDimension ).toDouble( &conversionSuccess );
950 if ( !conversionSuccess )
954 y = pos.at( i * srsDimension + 1 ).toDouble( &conversionSuccess );
955 if ( !conversionSuccess )
969 QDomElement envelopeElem = envelopeNode.toElement();
970 if ( envelopeElem.tagName() != QLatin1String(
"Envelope" ) )
973 QDomNodeList lowerCornerList = envelopeElem.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"lowerCorner" ) );
974 if ( lowerCornerList.size() < 1 )
977 QDomNodeList upperCornerList = envelopeElem.elementsByTagNameNS(
GML_NAMESPACE, QStringLiteral(
"upperCorner" ) );
978 if ( upperCornerList.size() < 1 )
981 bool conversionSuccess;
982 int srsDimension = 2;
984 QDomElement elem = lowerCornerList.at( 0 ).toElement();
985 if ( elem.hasAttribute( QStringLiteral(
"srsDimension" ) ) )
987 srsDimension = elem.attribute( QStringLiteral(
"srsDimension" ) ).toInt( &conversionSuccess );
988 if ( !conversionSuccess )
993 else if ( elem.hasAttribute( QStringLiteral(
"dimension" ) ) )
995 srsDimension = elem.attribute( QStringLiteral(
"dimension" ) ).toInt( &conversionSuccess );
996 if ( !conversionSuccess )
1001 QString bString = elem.text();
1003 double xmin = bString.section(
' ', 0, 0 ).toDouble( &conversionSuccess );
1004 if ( !conversionSuccess )
1006 double ymin = bString.section(
' ', 1, 1 ).toDouble( &conversionSuccess );
1007 if ( !conversionSuccess )
1010 elem = upperCornerList.at( 0 ).toElement();
1011 if ( elem.hasAttribute( QStringLiteral(
"srsDimension" ) ) )
1013 srsDimension = elem.attribute( QStringLiteral(
"srsDimension" ) ).toInt( &conversionSuccess );
1014 if ( !conversionSuccess )
1019 else if ( elem.hasAttribute( QStringLiteral(
"dimension" ) ) )
1021 srsDimension = elem.attribute( QStringLiteral(
"dimension" ) ).toInt( &conversionSuccess );
1022 if ( !conversionSuccess )
1028 Q_UNUSED( srsDimension );
1030 bString = elem.text();
1031 double xmax = bString.section(
' ', 0, 0 ).toDouble( &conversionSuccess );
1032 if ( !conversionSuccess )
1034 double ymax = bString.section(
' ', 1, 1 ).toDouble( &conversionSuccess );
1035 if ( !conversionSuccess )
1046 return rectangleToGMLBox( box, doc, QString(),
false, precision );
1050 const QString &srsName,
1051 bool invertAxisOrientation,
1056 return QDomElement();
1059 QDomElement boxElem = doc.createElement( QStringLiteral(
"gml:Box" ) );
1060 if ( !srsName.isEmpty() )
1062 boxElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1064 QDomElement coordElem = doc.createElement( QStringLiteral(
"gml:coordinates" ) );
1065 coordElem.setAttribute( QStringLiteral(
"cs" ), QStringLiteral(
"," ) );
1066 coordElem.setAttribute( QStringLiteral(
"ts" ), QStringLiteral(
" " ) );
1068 QString coordString;
1077 QDomText coordText = doc.createTextNode( coordString );
1078 coordElem.appendChild( coordText );
1079 boxElem.appendChild( coordElem );
1086 return rectangleToGMLEnvelope( env, doc, QString(),
false, precision );
1090 const QString &srsName,
1091 bool invertAxisOrientation,
1096 return QDomElement();
1099 QDomElement envElem = doc.createElement( QStringLiteral(
"gml:Envelope" ) );
1100 if ( !srsName.isEmpty() )
1102 envElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1106 QDomElement lowerCornerElem = doc.createElement( QStringLiteral(
"gml:lowerCorner" ) );
1110 QDomText lowerCornerText = doc.createTextNode( posList );
1111 lowerCornerElem.appendChild( lowerCornerText );
1112 envElem.appendChild( lowerCornerElem );
1114 QDomElement upperCornerElem = doc.createElement( QStringLiteral(
"gml:upperCorner" ) );
1118 QDomText upperCornerText = doc.createTextNode( posList );
1119 upperCornerElem.appendChild( upperCornerText );
1120 envElem.appendChild( upperCornerElem );
1127 return geometryToGML( geometry, doc, ( format == QLatin1String(
"GML2" ) ) ? GML_2_1_2 : GML_3_2_1, QString(),
false, QString(), precision );
1132 const QString &srsName,
1133 bool invertAxisOrientation,
1134 const QString &gmlIdBase,
1138 return QDomElement();
1141 QString cs = QStringLiteral(
"," );
1143 QString ts = QStringLiteral(
" " );
1145 QDomElement baseCoordElem;
1147 bool hasZValue =
false;
1149 QByteArray wkb( geometry.
asWkb() );
1153 wkbPtr.readHeader();
1159 return QDomElement();
1162 if ( gmlVersion != GML_2_1_2 )
1170 baseCoordElem = doc.createElement( QStringLiteral(
"gml:pos" ) );
1173 baseCoordElem = doc.createElement( QStringLiteral(
"gml:posList" ) );
1176 baseCoordElem.setAttribute( QStringLiteral(
"srsDimension" ), QStringLiteral(
"2" ) );
1181 baseCoordElem = doc.createElement( QStringLiteral(
"gml:coordinates" ) );
1182 baseCoordElem.setAttribute( QStringLiteral(
"cs" ), cs );
1183 baseCoordElem.setAttribute( QStringLiteral(
"ts" ), ts );
1193 QDomElement pointElem = doc.createElement( QStringLiteral(
"gml:Point" ) );
1194 if ( gmlVersion == GML_3_2_1 && !gmlIdBase.isEmpty() )
1195 pointElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1196 if ( !srsName.isEmpty() )
1197 pointElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1198 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1202 if ( invertAxisOrientation )
1208 coordElem.appendChild( coordText );
1209 pointElem.appendChild( coordElem );
1218 QDomElement multiPointElem = doc.createElement( QStringLiteral(
"gml:MultiPoint" ) );
1219 if ( gmlVersion == GML_3_2_1 && !gmlIdBase.isEmpty() )
1220 multiPointElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1221 if ( !srsName.isEmpty() )
1222 multiPointElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1227 for (
int idx = 0; idx < nPoints; ++idx )
1229 QDomElement pointMemberElem = doc.createElement( QStringLiteral(
"gml:pointMember" ) );
1230 QDomElement pointElem = doc.createElement( QStringLiteral(
"gml:Point" ) );
1231 if ( gmlVersion == GML_3_2_1 && !gmlIdBase.isEmpty() )
1232 pointElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase + QStringLiteral(
".%1" ).arg( idx + 1 ) );
1233 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1235 wkbPtr.readHeader();
1238 if ( invertAxisOrientation )
1244 coordElem.appendChild( coordText );
1245 pointElem.appendChild( coordElem );
1249 wkbPtr +=
sizeof( double );
1251 pointMemberElem.appendChild( pointElem );
1252 multiPointElem.appendChild( pointMemberElem );
1254 return multiPointElem;
1262 QDomElement lineStringElem = doc.createElement( QStringLiteral(
"gml:LineString" ) );
1263 if ( gmlVersion == GML_3_2_1 && !gmlIdBase.isEmpty() )
1264 lineStringElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1265 if ( !srsName.isEmpty() )
1266 lineStringElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1272 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1273 QString coordString;
1274 for (
int idx = 0; idx < nPoints; ++idx )
1282 if ( invertAxisOrientation )
1290 wkbPtr +=
sizeof( double );
1293 QDomText coordText = doc.createTextNode( coordString );
1294 coordElem.appendChild( coordText );
1295 lineStringElem.appendChild( coordElem );
1296 return lineStringElem;
1304 QDomElement multiLineStringElem = doc.createElement( QStringLiteral(
"gml:MultiLineString" ) );
1305 if ( gmlVersion == GML_3_2_1 && !gmlIdBase.isEmpty() )
1306 multiLineStringElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1307 if ( !srsName.isEmpty() )
1308 multiLineStringElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1313 for (
int jdx = 0; jdx < nLines; jdx++ )
1315 QDomElement lineStringMemberElem = doc.createElement( QStringLiteral(
"gml:lineStringMember" ) );
1316 QDomElement lineStringElem = doc.createElement( QStringLiteral(
"gml:LineString" ) );
1317 if ( gmlVersion == GML_3_2_1 && !gmlIdBase.isEmpty() )
1318 lineStringElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase + QStringLiteral(
".%1" ).arg( jdx + 1 ) );
1320 wkbPtr.readHeader();
1325 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1326 QString coordString;
1327 for (
int idx = 0; idx < nPoints; idx++ )
1335 if ( invertAxisOrientation )
1344 wkbPtr +=
sizeof( double );
1347 QDomText coordText = doc.createTextNode( coordString );
1348 coordElem.appendChild( coordText );
1349 lineStringElem.appendChild( coordElem );
1350 lineStringMemberElem.appendChild( lineStringElem );
1351 multiLineStringElem.appendChild( lineStringMemberElem );
1353 return multiLineStringElem;
1361 QDomElement polygonElem = doc.createElement( QStringLiteral(
"gml:Polygon" ) );
1362 if ( gmlVersion == GML_3_2_1 && !gmlIdBase.isEmpty() )
1363 polygonElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1364 if ( !srsName.isEmpty() )
1365 polygonElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1371 if ( numRings == 0 )
1372 return QDomElement();
1374 int *ringNumPoints =
new int[numRings];
1376 for (
int idx = 0; idx < numRings; idx++ )
1378 QString boundaryName = ( gmlVersion == GML_2_1_2 ) ?
"gml:outerBoundaryIs" :
"gml:exterior";
1381 boundaryName = ( gmlVersion == GML_2_1_2 ) ?
"gml:innerBoundaryIs" :
"gml:interior";
1383 QDomElement boundaryElem = doc.createElement( boundaryName );
1384 QDomElement ringElem = doc.createElement( QStringLiteral(
"gml:LinearRing" ) );
1388 ringNumPoints[idx] = nPoints;
1390 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1391 QString coordString;
1392 for (
int jdx = 0; jdx < nPoints; jdx++ )
1400 if ( invertAxisOrientation )
1408 wkbPtr +=
sizeof( double );
1411 QDomText coordText = doc.createTextNode( coordString );
1412 coordElem.appendChild( coordText );
1413 ringElem.appendChild( coordElem );
1414 boundaryElem.appendChild( ringElem );
1415 polygonElem.appendChild( boundaryElem );
1417 delete [] ringNumPoints;
1426 QDomElement multiPolygonElem = doc.createElement( QStringLiteral(
"gml:MultiPolygon" ) );
1427 if ( gmlVersion == GML_3_2_1 && !gmlIdBase.isEmpty() )
1428 multiPolygonElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase );
1429 if ( !srsName.isEmpty() )
1430 multiPolygonElem.setAttribute( QStringLiteral(
"srsName" ), srsName );
1433 wkbPtr >> numPolygons;
1435 for (
int kdx = 0; kdx < numPolygons; kdx++ )
1437 QDomElement polygonMemberElem = doc.createElement( QStringLiteral(
"gml:polygonMember" ) );
1438 QDomElement polygonElem = doc.createElement( QStringLiteral(
"gml:Polygon" ) );
1439 if ( gmlVersion == GML_3_2_1 && !gmlIdBase.isEmpty() )
1440 polygonElem.setAttribute( QStringLiteral(
"gml:id" ), gmlIdBase + QStringLiteral(
".%1" ).arg( kdx + 1 ) );
1442 wkbPtr.readHeader();
1447 for (
int idx = 0; idx < numRings; idx++ )
1449 QString boundaryName = ( gmlVersion == GML_2_1_2 ) ?
"gml:outerBoundaryIs" :
"gml:exterior";
1452 boundaryName = ( gmlVersion == GML_2_1_2 ) ?
"gml:innerBoundaryIs" :
"gml:interior";
1454 QDomElement boundaryElem = doc.createElement( boundaryName );
1455 QDomElement ringElem = doc.createElement( QStringLiteral(
"gml:LinearRing" ) );
1460 QDomElement coordElem = baseCoordElem.cloneNode().toElement();
1461 QString coordString;
1462 for (
int jdx = 0; jdx < nPoints; jdx++ )
1470 if ( invertAxisOrientation )
1479 wkbPtr +=
sizeof( double );
1482 QDomText coordText = doc.createTextNode( coordString );
1483 coordElem.appendChild( coordText );
1484 ringElem.appendChild( coordElem );
1485 boundaryElem.appendChild( ringElem );
1486 polygonElem.appendChild( boundaryElem );
1487 polygonMemberElem.appendChild( polygonElem );
1488 multiPolygonElem.appendChild( polygonMemberElem );
1491 return multiPolygonElem;
1494 return QDomElement();
1500 return QDomElement();
1506 return geometryToGML( geometry, doc, QStringLiteral(
"GML2" ), precision );
1509 QDomElement QgsOgcUtils::createGMLCoordinates(
const QgsPolylineXY &points, QDomDocument &doc )
1511 QDomElement coordElem = doc.createElement( QStringLiteral(
"gml:coordinates" ) );
1512 coordElem.setAttribute( QStringLiteral(
"cs" ), QStringLiteral(
"," ) );
1513 coordElem.setAttribute( QStringLiteral(
"ts" ), QStringLiteral(
" " ) );
1515 QString coordString;
1516 QVector<QgsPointXY>::const_iterator pointIt = points.constBegin();
1517 for ( ; pointIt != points.constEnd(); ++pointIt )
1519 if ( pointIt != points.constBegin() )
1528 QDomText coordText = doc.createTextNode( coordString );
1529 coordElem.appendChild( coordText );
1533 QDomElement QgsOgcUtils::createGMLPositions(
const QgsPolylineXY &points, QDomDocument &doc )
1535 QDomElement posElem = doc.createElement( QStringLiteral(
"gml:pos" ) );
1536 if ( points.size() > 1 )
1537 posElem = doc.createElement( QStringLiteral(
"gml:posList" ) );
1538 posElem.setAttribute( QStringLiteral(
"srsDimension" ), QStringLiteral(
"2" ) );
1540 QString coordString;
1541 QVector<QgsPointXY>::const_iterator pointIt = points.constBegin();
1542 for ( ; pointIt != points.constEnd(); ++pointIt )
1544 if ( pointIt != points.constBegin() )
1553 QDomText coordText = doc.createTextNode( coordString );
1554 posElem.appendChild( coordText );
1564 if ( fillElement.isNull() || !fillElement.hasChildNodes() )
1572 QDomElement cssElem = fillElement.firstChildElement( QStringLiteral(
"CssParameter" ) );
1573 while ( !cssElem.isNull() )
1575 cssName = cssElem.attribute( QStringLiteral(
"name" ), QStringLiteral(
"not_found" ) );
1576 if ( cssName != QLatin1String(
"not_found" ) )
1578 elemText = cssElem.text();
1579 if ( cssName == QLatin1String(
"fill" ) )
1581 color.setNamedColor( elemText );
1583 else if ( cssName == QLatin1String(
"fill-opacity" ) )
1586 double opacity = elemText.toDouble( &ok );
1589 color.setAlphaF( opacity );
1594 cssElem = cssElem.nextSiblingElement( QStringLiteral(
"CssParameter" ) );
1603 if ( element.isNull() || !element.hasChildNodes() )
1610 if ( element.firstChild().nodeType() == QDomNode::TextNode )
1618 QDomElement childElem = element.firstChildElement();
1619 while ( !childElem.isNull() )
1626 expr->d->mParserErrorString = errorMsg;
1631 if ( !expr->d->mRootNode )
1633 expr->d->mRootNode = node;
1640 childElem = childElem.nextSiblingElement();
1644 expr->d->mExp = expr->
dump();
1650 static const QMap<QString, int> BINARY_OPERATORS_TAG_NAMES_MAP
1670 static int binaryOperatorFromTagName(
const QString &tagName )
1673 return BINARY_OPERATORS_TAG_NAMES_MAP.value( tagName, -1 );
1680 return QStringLiteral(
"PropertyIsLike" );
1682 return BINARY_OPERATORS_TAG_NAMES_MAP.key( op, QString() );
1685 static bool isBinaryOperator(
const QString &tagName )
1687 return binaryOperatorFromTagName( tagName ) >= 0;
1691 static bool isSpatialOperator(
const QString &tagName )
1693 static QStringList spatialOps;
1694 if ( spatialOps.isEmpty() )
1696 spatialOps << QStringLiteral(
"BBOX" ) << QStringLiteral(
"Intersects" ) << QStringLiteral(
"Contains" ) << QStringLiteral(
"Crosses" ) << QStringLiteral(
"Equals" )
1697 << QStringLiteral(
"Disjoint" ) << QStringLiteral(
"Overlaps" ) << QStringLiteral(
"Touches" ) << QStringLiteral(
"Within" );
1700 return spatialOps.contains( tagName );
1707 if ( element.isNull() )
1711 if ( isBinaryOperator( element.tagName() ) )
1713 return nodeBinaryOperatorFromOgcFilter( element,
errorMessage, layer );
1717 if ( isSpatialOperator( element.tagName() ) )
1719 return nodeSpatialOperatorFromOgcFilter( element,
errorMessage );
1724 if ( element.tagName() == QLatin1String(
"Not" ) )
1728 else if ( element.tagName() == QLatin1String(
"PropertyIsNull" ) )
1730 return nodePropertyIsNullFromOgcFilter( element,
errorMessage );
1732 else if ( element.tagName() == QLatin1String(
"Literal" ) )
1734 return nodeLiteralFromOgcFilter( element,
errorMessage, layer );
1736 else if ( element.tagName() == QLatin1String(
"Function" ) )
1738 return nodeFunctionFromOgcFilter( element,
errorMessage );
1740 else if ( element.tagName() == QLatin1String(
"PropertyName" ) )
1742 return nodeColumnRefFromOgcFilter( element,
errorMessage );
1744 else if ( element.tagName() == QLatin1String(
"PropertyIsBetween" ) )
1746 return nodeIsBetweenFromOgcFilter( element,
errorMessage );
1749 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() );
1757 if ( element.isNull() )
1760 int op = binaryOperatorFromTagName( element.tagName() );
1764 errorMessage = QObject::tr(
"'%1' binary operator not supported." ).arg( element.tagName() );
1768 if ( op ==
QgsExpressionNodeBinaryOperator::boLike && element.hasAttribute( QStringLiteral(
"matchCase" ) ) && element.attribute( QStringLiteral(
"matchCase" ) ) == QLatin1String(
"false" ) )
1773 QDomElement operandElem = element.firstChildElement();
1778 errorMessage = QObject::tr(
"invalid left operand for '%1' binary operator" ).arg( element.tagName() );
1782 for ( operandElem = operandElem.nextSiblingElement(); !operandElem.isNull(); operandElem = operandElem.nextSiblingElement() )
1788 errorMessage = QObject::tr(
"invalid right operand for '%1' binary operator" ).arg( element.tagName() );
1796 if ( element.hasAttribute( QStringLiteral(
"wildCard" ) ) )
1798 wildCard = element.attribute( QStringLiteral(
"wildCard" ) );
1801 if ( element.hasAttribute( QStringLiteral(
"singleChar" ) ) )
1803 singleChar = element.attribute( QStringLiteral(
"singleChar" ) );
1805 QString escape = QStringLiteral(
"\\" );
1806 if ( element.hasAttribute( QStringLiteral(
"escape" ) ) )
1808 escape = element.attribute( QStringLiteral(
"escape" ) );
1812 if ( !wildCard.isEmpty() && wildCard != QLatin1String(
"%" ) )
1814 oprValue.replace(
'%', QLatin1String(
"\\%" ) );
1815 if ( oprValue.startsWith( wildCard ) )
1817 oprValue.replace( 0, 1, QStringLiteral(
"%" ) );
1819 QRegExp rx(
"[^" + QRegExp::escape( escape ) +
"](" + QRegExp::escape( wildCard ) +
")" );
1821 while ( ( pos = rx.indexIn( oprValue, pos ) ) != -1 )
1823 oprValue.replace( pos + 1, 1, QStringLiteral(
"%" ) );
1826 oprValue.replace( escape + wildCard, wildCard );
1828 if ( !singleChar.isEmpty() && singleChar != QLatin1String(
"_" ) )
1830 oprValue.replace(
'_', QLatin1String(
"\\_" ) );
1831 if ( oprValue.startsWith( singleChar ) )
1833 oprValue.replace( 0, 1, QStringLiteral(
"_" ) );
1835 QRegExp rx(
"[^" + QRegExp::escape( escape ) +
"](" + QRegExp::escape( singleChar ) +
")" );
1837 while ( ( pos = rx.indexIn( oprValue, pos ) ) != -1 )
1839 oprValue.replace( pos + 1, 1, QStringLiteral(
"_" ) );
1842 oprValue.replace( escape + singleChar, singleChar );
1844 if ( !escape.isEmpty() && escape != QLatin1String(
"\\" ) )
1846 oprValue.replace( escape + escape, escape );
1854 if ( expr == leftOp )
1857 errorMessage = QObject::tr(
"only one operand for '%1' binary operator" ).arg( element.tagName() );
1876 QDomElement childElem = element.firstChildElement();
1878 while ( !childElem.isNull() && gml2Str.isEmpty() )
1880 if ( childElem.tagName() != QLatin1String(
"PropertyName" ) )
1882 QTextStream gml2Stream( &gml2Str );
1883 childElem.save( gml2Stream, 0 );
1885 childElem = childElem.nextSiblingElement();
1887 if ( !gml2Str.isEmpty() )
1893 errorMessage = QObject::tr(
"No OGC Geometry found" );
1908 if ( element.tagName() != QLatin1String(
"Not" ) )
1911 QDomElement operandElem = element.firstChildElement();
1915 if ( errorMessage.isEmpty() )
1916 errorMessage = QObject::tr(
"invalid operand for '%1' unary operator" ).arg( element.tagName() );
1926 if ( element.isNull() || element.tagName() != QLatin1String(
"Function" ) )
1928 errorMessage = QObject::tr(
"ogc:Function expected, got %1" ).arg( element.tagName() );
1936 if ( element.attribute( QStringLiteral(
"name" ) ) != funcDef->
name() )
1941 QDomElement operandElem = element.firstChildElement();
1942 while ( !operandElem.isNull() )
1952 operandElem = operandElem.nextSiblingElement();
1965 if ( element.isNull() || element.tagName() != QLatin1String(
"Literal" ) )
1967 errorMessage = QObject::tr(
"ogc:Literal expected, got %1" ).arg( element.tagName() );
1974 QDomNode childNode = element.firstChild();
1975 while ( !childNode.isNull() )
1979 if ( childNode.nodeType() == QDomNode::ElementNode )
1982 QDomElement operandElem = childNode.toElement();
1983 operand = nodeFromOgcFilter( operandElem,
errorMessage, layer );
1988 errorMessage = QObject::tr(
"'%1' is an invalid or not supported content for ogc:Literal" ).arg( operandElem.tagName() );
1995 QVariant value = childNode.nodeValue();
1997 bool converted =
false;
2000 if ( layer !=
nullptr )
2002 QDomElement propertyNameElement = element.previousSiblingElement( QLatin1String(
"PropertyName" ) );
2003 if ( propertyNameElement.isNull() || propertyNameElement.tagName() != QLatin1String(
"PropertyName" ) )
2005 propertyNameElement = element.nextSiblingElement( QLatin1String(
"PropertyName" ) );
2007 if ( !propertyNameElement.isNull() || propertyNameElement.tagName() == QLatin1String(
"PropertyName" ) )
2009 int fieldIndex = layer->
fields().
indexOf( propertyNameElement.firstChild().nodeValue() );
2010 if ( fieldIndex != -1 )
2023 double d = value.toDouble( &ok );
2043 childNode = childNode.nextSibling();
2055 if ( element.isNull() || element.tagName() != QLatin1String(
"PropertyName" ) )
2057 errorMessage = QObject::tr(
"ogc:PropertyName expected, got %1" ).arg( element.tagName() );
2071 QDomElement operandElem = element.firstChildElement();
2072 while ( !operandElem.isNull() )
2074 if ( operandElem.tagName() == QLatin1String(
"LowerBoundary" ) )
2076 QDomElement lowerBoundElem = operandElem.firstChildElement();
2077 lowerBound = nodeFromOgcFilter( lowerBoundElem, errorMessage );
2079 else if ( operandElem.tagName() == QLatin1String(
"UpperBoundary" ) )
2081 QDomElement upperBoundElem = operandElem.firstChildElement();
2082 upperBound = nodeFromOgcFilter( upperBoundElem, errorMessage );
2089 operand = nodeFromOgcFilter( operandElem, errorMessage );
2090 operand2 = nodeFromOgcFilter( operandElem, errorMessage );
2093 if ( operand && lowerBound && operand2 && upperBound )
2096 operandElem = operandElem.nextSiblingElement();
2099 if ( !operand || !lowerBound || !operand2 || !upperBound )
2105 errorMessage = QObject::tr(
"missing some required sub-elements in ogc:PropertyIsBetween" );
2118 if ( element.tagName() != QLatin1String(
"PropertyIsNull" ) )
2123 QDomElement operandElem = element.firstChildElement();
2138 return expressionToOgcFilter( exp, doc, GML_2_1_2, FILTER_OGC_1_0,
2139 QStringLiteral(
"geometry" ), QString(),
false,
false, errorMessage );
2144 return expressionToOgcExpression( exp, doc, GML_2_1_2, FILTER_OGC_1_0,
2145 QStringLiteral(
"geometry" ), QString(),
false,
false, errorMessage );
2152 const QString &geometryName,
2153 const QString &srsName,
2154 bool honourAxisOrientation,
2155 bool invertAxisOrientation,
2159 return QDomElement();
2161 QgsOgcUtilsExprToFilter utils( doc, gmlVersion, filterVersion, geometryName, srsName, honourAxisOrientation, invertAxisOrientation );
2165 if ( exprRootElem.isNull() )
2166 return QDomElement();
2168 QDomElement filterElem =
2169 ( filterVersion == FILTER_FES_2_0 ) ?
2170 doc.createElementNS( FES_NAMESPACE, QStringLiteral(
"fes:Filter" ) ) :
2171 doc.createElementNS( OGC_NAMESPACE, QStringLiteral(
"ogc:Filter" ) );
2174 QDomAttr attr = doc.createAttribute( QStringLiteral(
"xmlns:gml" ) );
2175 if ( gmlVersion == GML_3_2_1 )
2176 attr.setValue( GML32_NAMESPACE );
2179 filterElem.setAttributeNode( attr );
2181 filterElem.appendChild( exprRootElem );
2189 const QString &geometryName,
2190 const QString &srsName,
2191 bool honourAxisOrientation,
2192 bool invertAxisOrientation,
2197 return QDomElement();
2205 QgsOgcUtilsExprToFilter utils( doc, gmlVersion, filterVersion, geometryName, srsName, honourAxisOrientation, invertAxisOrientation );
2211 if ( !exprRootElem.isNull() )
2213 return exprRootElem;
2220 *errorMessage = QObject::tr(
"Node type not supported in expression translation: %1" ).arg( node->
nodeType() );
2224 return QDomElement();
2231 const QList<LayerProperties> &layerProperties,
2232 bool honourAxisOrientation,
2233 bool invertAxisOrientation,
2234 const QMap< QString, QString> &mapUnprefixedTypenameToPrefixedTypename,
2238 return QDomElement();
2241 layerProperties, honourAxisOrientation, invertAxisOrientation,
2242 mapUnprefixedTypenameToPrefixedTypename );
2246 if ( exprRootElem.isNull() )
2247 return QDomElement();
2249 QDomElement filterElem =
2250 ( filterVersion == FILTER_FES_2_0 ) ?
2251 doc.createElementNS( FES_NAMESPACE, QStringLiteral(
"fes:Filter" ) ) :
2252 doc.createElementNS( OGC_NAMESPACE, QStringLiteral(
"ogc:Filter" ) );
2255 QDomAttr attr = doc.createAttribute( QStringLiteral(
"xmlns:gml" ) );
2256 if ( gmlVersion == GML_3_2_1 )
2257 attr.setValue( GML32_NAMESPACE );
2260 filterElem.setAttributeNode( attr );
2262 filterElem.appendChild( exprRootElem );
2274 return expressionUnaryOperatorToOgcFilter( static_cast<const QgsExpressionNodeUnaryOperator *>( node ) );
2276 return expressionBinaryOperatorToOgcFilter( static_cast<const QgsExpressionNodeBinaryOperator *>( node ) );
2278 return expressionInOperatorToOgcFilter( static_cast<const QgsExpressionNodeInOperator *>( node ) );
2280 return expressionFunctionToOgcFilter( static_cast<const QgsExpressionNodeFunction *>( node ) );
2282 return expressionLiteralToOgcFilter( static_cast<const QgsExpressionNodeLiteral *>( node ) );
2284 return expressionColumnRefToOgcFilter( static_cast<const QgsExpressionNodeColumnRef *>( node ) );
2287 mErrorMessage = QObject::tr(
"Node type not supported: %1" ).arg( node->
nodeType() );
2288 return QDomElement();
2297 if ( !mErrorMessage.isEmpty() )
2298 return QDomElement();
2301 switch ( node->
op() )
2304 uoElem = mDoc.createElement( mFilterPrefix +
":Literal" );
2309 uoElem.appendChild( mDoc.createTextNode(
"-" + operandElem.text() ) );
2310 mDoc.removeChild( operandElem );
2314 mErrorMessage = QObject::tr(
"This use of unary operator not implemented yet" );
2315 return QDomElement();
2319 uoElem = mDoc.createElement( mFilterPrefix +
":Not" );
2320 uoElem.appendChild( operandElem );
2324 mErrorMessage = QObject::tr(
"Unary operator '%1' not implemented yet" ).arg( node->
text() );
2325 return QDomElement();
2335 if ( !mErrorMessage.isEmpty() )
2336 return QDomElement();
2346 if ( rightLit->
value().isNull() )
2349 QDomElement elem = mDoc.createElement( mFilterPrefix +
":PropertyIsNull" );
2350 elem.appendChild( leftElem );
2354 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2355 notElem.appendChild( elem );
2369 if ( !mErrorMessage.isEmpty() )
2370 return QDomElement();
2373 QString opText = binaryOperatorToTagName( op );
2374 if ( opText.isEmpty() )
2378 mErrorMessage = QObject::tr(
"Binary operator %1 not implemented yet" ).arg( node->
text() );
2379 return QDomElement();
2382 QDomElement boElem = mDoc.createElement( mFilterPrefix +
":" + opText );
2387 boElem.setAttribute( QStringLiteral(
"matchCase" ), QStringLiteral(
"false" ) );
2390 boElem.setAttribute( QStringLiteral(
"wildCard" ), QStringLiteral(
"%" ) );
2391 boElem.setAttribute( QStringLiteral(
"singleChar" ), QStringLiteral(
"_" ) );
2393 boElem.setAttribute( QStringLiteral(
"escape" ), QStringLiteral(
"\\" ) );
2395 boElem.setAttribute( QStringLiteral(
"escapeChar" ), QStringLiteral(
"\\" ) );
2398 boElem.appendChild( leftElem );
2399 boElem.appendChild( rightElem );
2407 switch ( node->
value().type() )
2410 value = QString::number( node->
value().toInt() );
2412 case QVariant::Double:
2415 case QVariant::String:
2416 value = node->
value().toString();
2420 mErrorMessage = QObject::tr(
"Literal type not supported: %1" ).arg( node->
value().type() );
2421 return QDomElement();
2424 QDomElement litElem = mDoc.createElement( mFilterPrefix +
":Literal" );
2425 litElem.appendChild( mDoc.createTextNode( value ) );
2432 QDomElement propElem = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
2433 propElem.appendChild( mDoc.createTextNode( node->
name() ) );
2441 if ( node->
list()->
list().size() == 1 )
2444 QDomElement orElem = mDoc.createElement( mFilterPrefix +
":Or" );
2450 if ( !mErrorMessage.isEmpty() )
2451 return QDomElement();
2453 QDomElement eqElem = mDoc.createElement( mFilterPrefix +
":PropertyIsEqualTo" );
2454 eqElem.appendChild( leftNode.cloneNode() );
2455 eqElem.appendChild( listNode );
2457 orElem.appendChild( eqElem );
2462 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2463 notElem.appendChild( orElem );
2470 static const QMap<QString, QString> BINARY_SPATIAL_OPS_MAP
2472 { QStringLiteral(
"disjoint" ), QStringLiteral(
"Disjoint" ) },
2473 { QStringLiteral(
"intersects" ), QStringLiteral(
"Intersects" )},
2474 { QStringLiteral(
"touches" ), QStringLiteral(
"Touches" ) },
2475 { QStringLiteral(
"crosses" ), QStringLiteral(
"Crosses" ) },
2476 { QStringLiteral(
"contains" ), QStringLiteral(
"Contains" ) },
2477 { QStringLiteral(
"overlaps" ), QStringLiteral(
"Overlaps" ) },
2478 { QStringLiteral(
"within" ), QStringLiteral(
"Within" ) }
2481 static bool isBinarySpatialOperator(
const QString &fnName )
2483 return BINARY_SPATIAL_OPS_MAP.contains( fnName );
2486 static QString tagNameForSpatialOperator(
const QString &fnName )
2488 return BINARY_SPATIAL_OPS_MAP.value( fnName );
2498 return fd->
name() == QLatin1String(
"$geometry" );
2510 if ( fnDef->
name() == QLatin1String(
"geom_from_wkt" ) )
2512 const QList<QgsExpressionNode *> &args = fnNode->
args()->
list();
2528 if ( fd->
name() == QLatin1String(
"intersects_bbox" ) )
2530 QList<QgsExpressionNode *> argNodes = node->
args()->
list();
2531 Q_ASSERT( argNodes.count() == 2 );
2533 QgsGeometry geom = geometryFromConstExpr( argNodes[1] );
2534 if ( !geom.isNull() && isGeometryColumn( argNodes[0] ) )
2544 QDomElement geomProperty = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
2545 geomProperty.appendChild( mDoc.createTextNode( mGeometryName ) );
2547 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":BBOX" );
2548 funcElem.appendChild( geomProperty );
2549 funcElem.appendChild( elemBox );
2554 mErrorMessage = QObject::tr(
"<BBOX> is currently supported only in form: bbox($geometry, geomFromWKT('…'))" );
2555 return QDomElement();
2559 if ( isBinarySpatialOperator( fd->
name() ) )
2561 QList<QgsExpressionNode *> argNodes = node->
args()->
list();
2562 Q_ASSERT( argNodes.count() == 2 );
2565 if ( isGeometryColumn( argNodes[0] ) )
2566 otherNode = argNodes[1];
2567 else if ( isGeometryColumn( argNodes[1] ) )
2568 otherNode = argNodes[0];
2571 mErrorMessage = QObject::tr(
"Unable to translate spatial operator: at least one must refer to geometry." );
2572 return QDomElement();
2575 QDomElement otherGeomElem;
2580 mErrorMessage = QObject::tr(
"spatial operator: the other operator must be a geometry constructor function" );
2581 return QDomElement();
2586 if ( otherFnDef->
name() == QLatin1String(
"geom_from_wkt" ) )
2591 mErrorMessage = QObject::tr(
"geom_from_wkt: argument must be string literal" );
2592 return QDomElement();
2597 QStringLiteral(
"qgis_id_geom_%1" ).arg( mGeomId ) );
2600 else if ( otherFnDef->
name() == QLatin1String(
"geom_from_gml" ) )
2605 mErrorMessage = QObject::tr(
"geom_from_gml: argument must be string literal" );
2606 return QDomElement();
2609 QDomDocument geomDoc;
2611 if ( !geomDoc.setContent( gml,
true ) )
2613 mErrorMessage = QObject::tr(
"geom_from_gml: unable to parse XML" );
2614 return QDomElement();
2617 QDomNode geomNode = mDoc.importNode( geomDoc.documentElement(), true );
2618 otherGeomElem = geomNode.toElement();
2622 mErrorMessage = QObject::tr(
"spatial operator: unknown geometry constructor function" );
2623 return QDomElement();
2628 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":" + tagNameForSpatialOperator( fd->
name() ) );
2629 QDomElement geomProperty = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
2630 geomProperty.appendChild( mDoc.createTextNode( mGeometryName ) );
2631 funcElem.appendChild( geomProperty );
2632 funcElem.appendChild( otherGeomElem );
2638 mErrorMessage = QObject::tr(
"Special columns/constants are not supported." );
2639 return QDomElement();
2643 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":Function" );
2644 funcElem.setAttribute( QStringLiteral(
"name" ), fd->
name() );
2648 if ( !mErrorMessage.isEmpty() )
2649 return QDomElement();
2651 funcElem.appendChild( childElem );
2662 const QList<QgsOgcUtils::LayerProperties> &layerProperties,
2663 bool honourAxisOrientation,
2664 bool invertAxisOrientation,
2665 const QMap< QString, QString> &mapUnprefixedTypenameToPrefixedTypename )
2668 , mGMLVersion( gmlVersion )
2669 , mFilterVersion( filterVersion )
2670 , mLayerProperties( layerProperties )
2671 , mHonourAxisOrientation( honourAxisOrientation )
2672 , mInvertAxisOrientation( invertAxisOrientation )
2673 , mFilterPrefix( ( filterVersion ==
QgsOgcUtils::FILTER_FES_2_0 ) ?
"fes" :
"ogc" )
2674 , mPropertyName( ( filterVersion ==
QgsOgcUtils::FILTER_FES_2_0 ) ?
"ValueReference" :
"PropertyName" )
2676 , mMapUnprefixedTypenameToPrefixedTypename( mapUnprefixedTypenameToPrefixedTypename )
2685 return toOgcFilter( static_cast<const QgsSQLStatement::NodeUnaryOperator *>( node ) );
2687 return toOgcFilter( static_cast<const QgsSQLStatement::NodeBinaryOperator *>( node ) );
2689 return toOgcFilter( static_cast<const QgsSQLStatement::NodeInOperator *>( node ) );
2691 return toOgcFilter( static_cast<const QgsSQLStatement::NodeBetweenOperator *>( node ) );
2693 return toOgcFilter( static_cast<const QgsSQLStatement::NodeFunction *>( node ) );
2695 return toOgcFilter( static_cast<const QgsSQLStatement::NodeLiteral *>( node ) );
2697 return toOgcFilter( static_cast<const QgsSQLStatement::NodeColumnRef *>( node ) );
2699 return toOgcFilter( static_cast<const QgsSQLStatement::NodeSelect *>( node ) );
2702 mErrorMessage = QObject::tr(
"Node type not supported: %1" ).arg( node->
nodeType() );
2703 return QDomElement();
2712 if ( !mErrorMessage.isEmpty() )
2713 return QDomElement();
2716 switch ( node->
op() )
2719 uoElem = mDoc.createElement( mFilterPrefix +
":Literal" );
2724 uoElem.appendChild( mDoc.createTextNode(
"-" + operandElem.text() ) );
2725 mDoc.removeChild( operandElem );
2729 mErrorMessage = QObject::tr(
"This use of unary operator not implemented yet" );
2730 return QDomElement();
2734 uoElem = mDoc.createElement( mFilterPrefix +
":Not" );
2735 uoElem.appendChild( operandElem );
2740 return QDomElement();
2750 if ( !mErrorMessage.isEmpty() )
2751 return QDomElement();
2761 if ( rightLit->
value().isNull() )
2764 QDomElement elem = mDoc.createElement( mFilterPrefix +
":PropertyIsNull" );
2765 elem.appendChild( leftElem );
2769 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2770 notElem.appendChild( elem );
2784 if ( !mErrorMessage.isEmpty() )
2785 return QDomElement();
2790 opText = QStringLiteral(
"Or" );
2792 opText = QStringLiteral(
"And" );
2794 opText = QStringLiteral(
"PropertyIsEqualTo" );
2796 opText = QStringLiteral(
"PropertyIsNotEqualTo" );
2798 opText = QStringLiteral(
"PropertyIsLessThanOrEqualTo" );
2800 opText = QStringLiteral(
"PropertyIsGreaterThanOrEqualTo" );
2802 opText = QStringLiteral(
"PropertyIsLessThan" );
2804 opText = QStringLiteral(
"PropertyIsGreaterThan" );
2806 opText = QStringLiteral(
"PropertyIsLike" );
2808 opText = QStringLiteral(
"PropertyIsLike" );
2810 if ( opText.isEmpty() )
2814 return QDomElement();
2817 QDomElement boElem = mDoc.createElement( mFilterPrefix +
":" + opText );
2822 boElem.setAttribute( QStringLiteral(
"matchCase" ), QStringLiteral(
"false" ) );
2825 boElem.setAttribute( QStringLiteral(
"wildCard" ), QStringLiteral(
"%" ) );
2826 boElem.setAttribute( QStringLiteral(
"singleChar" ), QStringLiteral(
"_" ) );
2828 boElem.setAttribute( QStringLiteral(
"escape" ), QStringLiteral(
"\\" ) );
2830 boElem.setAttribute( QStringLiteral(
"escapeChar" ), QStringLiteral(
"\\" ) );
2833 boElem.appendChild( leftElem );
2834 boElem.appendChild( rightElem );
2842 switch ( node->
value().type() )
2845 value = QString::number( node->
value().toInt() );
2847 case QVariant::LongLong:
2848 value = QString::number( node->
value().toLongLong() );
2850 case QVariant::Double:
2853 case QVariant::String:
2854 value = node->
value().toString();
2858 mErrorMessage = QObject::tr(
"Literal type not supported: %1" ).arg( node->
value().type() );
2859 return QDomElement();
2862 QDomElement litElem = mDoc.createElement( mFilterPrefix +
":Literal" );
2863 litElem.appendChild( mDoc.createTextNode( value ) );
2870 QDomElement propElem = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
2871 if ( node->
tableName().isEmpty() || mLayerProperties.size() == 1 )
2872 propElem.appendChild( mDoc.createTextNode( node->
name() ) );
2875 QString tableName( mMapTableAliasToNames[node->
tableName()] );
2876 if ( mMapUnprefixedTypenameToPrefixedTypename.contains( tableName ) )
2877 tableName = mMapUnprefixedTypenameToPrefixedTypename[tableName];
2878 propElem.appendChild( mDoc.createTextNode( tableName +
"/" + node->
name() ) );
2885 if ( node->
list()->
list().size() == 1 )
2888 QDomElement orElem = mDoc.createElement( mFilterPrefix +
":Or" );
2894 if ( !mErrorMessage.isEmpty() )
2895 return QDomElement();
2897 QDomElement eqElem = mDoc.createElement( mFilterPrefix +
":PropertyIsEqualTo" );
2898 eqElem.appendChild( leftNode.cloneNode() );
2899 eqElem.appendChild( listNode );
2901 orElem.appendChild( eqElem );
2906 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2907 notElem.appendChild( orElem );
2916 QDomElement elem = mDoc.createElement( mFilterPrefix +
":PropertyIsBetween" );
2918 QDomElement lowerBoundary = mDoc.createElement( mFilterPrefix +
":LowerBoundary" );
2920 elem.appendChild( lowerBoundary );
2921 QDomElement upperBoundary = mDoc.createElement( mFilterPrefix +
":UpperBoundary" );
2923 elem.appendChild( upperBoundary );
2927 QDomElement notElem = mDoc.createElement( mFilterPrefix +
":Not" );
2928 notElem.appendChild( elem );
2935 static QString mapBinarySpatialToOgc(
const QString &name )
2937 QString nameCompare( name );
2938 if ( name.size() > 3 && name.midRef( 0, 3 ).compare( QStringLiteral(
"ST_" ), Qt::CaseInsensitive ) == 0 )
2939 nameCompare = name.mid( 3 );
2940 QStringList spatialOps;
2941 spatialOps << QStringLiteral(
"BBOX" ) << QStringLiteral(
"Intersects" ) << QStringLiteral(
"Contains" ) << QStringLiteral(
"Crosses" ) << QStringLiteral(
"Equals" )
2942 << QStringLiteral(
"Disjoint" ) << QStringLiteral(
"Overlaps" ) << QStringLiteral(
"Touches" ) << QStringLiteral(
"Within" );
2943 Q_FOREACH ( QString op, spatialOps )
2945 if ( nameCompare.compare( op, Qt::CaseInsensitive ) == 0 )
2951 static QString mapTernarySpatialToOgc(
const QString &name )
2953 QString nameCompare( name );
2954 if ( name.size() > 3 && name.midRef( 0, 3 ).compare( QStringLiteral(
"ST_" ), Qt::CaseInsensitive ) == 0 )
2955 nameCompare = name.mid( 3 );
2956 if ( nameCompare.compare( QLatin1String(
"DWithin" ), Qt::CaseInsensitive ) == 0 )
2957 return QStringLiteral(
"DWithin" );
2958 if ( nameCompare.compare( QLatin1String(
"Beyond" ), Qt::CaseInsensitive ) == 0 )
2959 return QStringLiteral(
"Beyond" );
2963 QString QgsOgcUtilsSQLStatementToFilter::getGeometryColumnSRSName(
const QgsSQLStatement::Node *node )
2973 if ( prop.
mName.compare( mMapTableAliasToNames[col->
tableName()], Qt::CaseInsensitive ) == 0 &&
2980 if ( !mLayerProperties.empty() &&
2981 mLayerProperties.at( 0 ).mGeometryAttribute.compare( col->
name(), Qt::CaseInsensitive ) == 0 )
2983 return mLayerProperties.at( 0 ).mSRSName;
2989 QList<QgsSQLStatement::Node *> args,
2990 bool lastArgIsSRSName,
2992 bool &axisInversion )
2994 srsName = mCurrentSRSName;
2995 axisInversion = mInvertAxisOrientation;
2997 if ( lastArgIsSRSName )
3002 mErrorMessage = QObject::tr(
"%1: Last argument must be string or integer literal" ).arg( mainNode->
name() );
3006 if ( lit->
value().type() == QVariant::Int )
3010 srsName =
"EPSG:" + QString::number( lit->
value().toInt() );
3014 srsName =
"urn:ogc:def:crs:EPSG::" + QString::number( lit->
value().toInt() );
3019 srsName = lit->
value().toString();
3020 if ( srsName.startsWith( QLatin1String(
"EPSG:" ), Qt::CaseInsensitive ) )
3026 if ( !srsName.isEmpty() )
3032 axisInversion = !axisInversion;
3042 if ( node->
name().compare( QLatin1String(
"ST_GeometryFromText" ), Qt::CaseInsensitive ) == 0 )
3044 QList<QgsSQLStatement::Node *> args = node->
args()->
list();
3045 if ( args.size() != 1 && args.size() != 2 )
3047 mErrorMessage = QObject::tr(
"Function %1 should have 1 or 2 arguments" ).arg( node->
name() );
3048 return QDomElement();
3054 mErrorMessage = QObject::tr(
"%1: First argument must be string literal" ).arg( node->
name() );
3055 return QDomElement();
3060 if ( ! processSRSName( node, args, args.size() == 2, srsName, axisInversion ) )
3062 return QDomElement();
3068 QStringLiteral(
"qgis_id_geom_%1" ).arg( mGeomId ) );
3070 if ( geomElem.isNull() )
3072 mErrorMessage = QObject::tr(
"%1: invalid WKT" ).arg( node->
name() );
3073 return QDomElement();
3080 if ( node->
name().compare( QLatin1String(
"ST_MakeEnvelope" ), Qt::CaseInsensitive ) == 0 )
3082 QList<QgsSQLStatement::Node *> args = node->
args()->
list();
3083 if ( args.size() != 4 && args.size() != 5 )
3085 mErrorMessage = QObject::tr(
"Function %1 should have 4 or 5 arguments" ).arg( node->
name() );
3086 return QDomElement();
3091 for (
int i = 0; i < 4; i++ )
3096 mErrorMessage = QObject::tr(
"%1: Argument %2 must be numeric literal" ).arg( node->
name() ).arg( i + 1 );
3097 return QDomElement();
3101 if ( lit->
value().type() == QVariant::Int )
3102 val = lit->
value().toInt();
3103 else if ( lit->
value().type() == QVariant::LongLong )
3104 val = lit->
value().toLongLong();
3105 else if ( lit->
value().type() == QVariant::Double )
3106 val = lit->
value().toDouble();
3109 mErrorMessage = QObject::tr(
"%1 Argument %2 must be numeric literal" ).arg( node->
name() ).arg( i + 1 );
3110 return QDomElement();
3124 if ( ! processSRSName( node, args, args.size() == 5, srsName, axisInversion ) )
3126 return QDomElement();
3137 if ( node->
name().compare( QLatin1String(
"ST_GeomFromGML" ), Qt::CaseInsensitive ) == 0 )
3139 QList<QgsSQLStatement::Node *> args = node->
args()->
list();
3140 if ( args.size() != 1 )
3142 mErrorMessage = QObject::tr(
"Function %1 should have 1 argument" ).arg( node->
name() );
3143 return QDomElement();
3149 mErrorMessage = QObject::tr(
"%1: Argument must be string literal" ).arg( node->
name() );
3150 return QDomElement();
3153 QDomDocument geomDoc;
3155 if ( !geomDoc.setContent( gml,
true ) )
3157 mErrorMessage = QObject::tr(
"ST_GeomFromGML: unable to parse XML" );
3158 return QDomElement();
3161 QDomNode geomNode = mDoc.importNode( geomDoc.documentElement(), true );
3163 return geomNode.toElement();
3167 QString ogcName( mapBinarySpatialToOgc( node->
name() ) );
3168 if ( !ogcName.isEmpty() )
3170 QList<QgsSQLStatement::Node *> args = node->
args()->
list();
3171 if ( args.size() != 2 )
3173 mErrorMessage = QObject::tr(
"Function %1 should have 2 arguments" ).arg( node->
name() );
3174 return QDomElement();
3177 for (
int i = 0; i < 2; i ++ )
3180 ( static_cast<const QgsSQLStatement::NodeFunction *>( args[i] )->name().compare( QLatin1String(
"ST_GeometryFromText" ), Qt::CaseInsensitive ) == 0 ||
3181 static_cast<const QgsSQLStatement::NodeFunction *>( args[i] )->name().compare( QLatin1String(
"ST_MakeEnvelope" ), Qt::CaseInsensitive ) == 0 ) )
3183 mCurrentSRSName = getGeometryColumnSRSName( args[1 - i] );
3190 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":" + ogcName );
3194 if ( !mErrorMessage.isEmpty() )
3196 mCurrentSRSName.clear();
3197 return QDomElement();
3200 funcElem.appendChild( childElem );
3203 mCurrentSRSName.clear();
3207 ogcName = mapTernarySpatialToOgc( node->
name() );
3208 if ( !ogcName.isEmpty() )
3210 QList<QgsSQLStatement::Node *> args = node->
args()->
list();
3211 if ( args.size() != 3 )
3213 mErrorMessage = QObject::tr(
"Function %1 should have 3 arguments" ).arg( node->
name() );
3214 return QDomElement();
3217 for (
int i = 0; i < 2; i ++ )
3220 ( static_cast<const QgsSQLStatement::NodeFunction *>( args[i] )->name().compare( QLatin1String(
"ST_GeometryFromText" ), Qt::CaseInsensitive ) == 0 ||
3221 static_cast<const QgsSQLStatement::NodeFunction *>( args[i] )->name().compare( QLatin1String(
"ST_MakeEnvelope" ), Qt::CaseInsensitive ) == 0 ) )
3223 mCurrentSRSName = getGeometryColumnSRSName( args[1 - i] );
3228 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":" + node->
name().mid( 3 ) );
3229 for (
int i = 0; i < 2; i++ )
3232 if ( !mErrorMessage.isEmpty() )
3234 mCurrentSRSName.clear();
3235 return QDomElement();
3238 funcElem.appendChild( childElem );
3240 mCurrentSRSName.clear();
3245 mErrorMessage = QObject::tr(
"Function %1 3rd argument should be a numeric value or a string made of a numeric value followed by a string" ).arg( node->
name() );
3246 return QDomElement();
3249 if ( lit->
value().isNull() )
3251 mErrorMessage = QObject::tr(
"Function %1 3rd argument should be a numeric value or a string made of a numeric value followed by a string" ).arg( node->
name() );
3252 return QDomElement();
3255 QString unit( QStringLiteral(
"m" ) );
3256 switch ( lit->
value().type() )
3259 distance = QString::number( lit->
value().toInt() );
3261 case QVariant::LongLong:
3262 distance = QString::number( lit->
value().toLongLong() );
3264 case QVariant::Double:
3267 case QVariant::String:
3269 distance = lit->
value().toString();
3270 for (
int i = 0; i < distance.size(); i++ )
3272 if ( !( ( distance[i] >=
'0' && distance[i] <=
'9' ) || distance[i] ==
'-' || distance[i] ==
'.' || distance[i] ==
'e' || distance[i] ==
'E' ) )
3274 unit = distance.mid( i ).trimmed();
3275 distance = distance.mid( 0, i );
3283 mErrorMessage = QObject::tr(
"Literal type not supported: %1" ).arg( lit->
value().type() );
3284 return QDomElement();
3287 QDomElement distanceElem = mDoc.createElement( mFilterPrefix +
":Distance" );
3289 distanceElem.setAttribute( QStringLiteral(
"uom" ), unit );
3291 distanceElem.setAttribute( QStringLiteral(
"unit" ), unit );
3292 distanceElem.appendChild( mDoc.createTextNode( distance ) );
3293 funcElem.appendChild( distanceElem );
3298 QDomElement funcElem = mDoc.createElement( mFilterPrefix +
":Function" );
3299 funcElem.setAttribute( QStringLiteral(
"name" ), node->
name() );
3303 if ( !mErrorMessage.isEmpty() )
3304 return QDomElement();
3306 funcElem.appendChild( childElem );
3312 const QString &leftTable )
3320 QList<QDomElement> listElem;
3321 Q_FOREACH (
const QString &columnName, node->
usingColumns() )
3323 QDomElement eqElem = mDoc.createElement( mFilterPrefix +
":PropertyIsEqualTo" );
3324 QDomElement propElem1 = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
3325 propElem1.appendChild( mDoc.createTextNode( leftTable +
"/" + columnName ) );
3326 eqElem.appendChild( propElem1 );
3327 QDomElement propElem2 = mDoc.createElement( mFilterPrefix +
":" + mPropertyName );
3328 propElem2.appendChild( mDoc.createTextNode( node->
tableDef()->
name() +
"/" + columnName ) );
3329 eqElem.appendChild( propElem2 );
3330 listElem.append( eqElem );
3333 if ( listElem.size() == 1 )
3337 else if ( listElem.size() > 1 )
3339 QDomElement andElem = mDoc.createElement( mFilterPrefix +
":And" );
3340 Q_FOREACH (
const QDomElement &elem, listElem )
3342 andElem.appendChild( elem );
3347 return QDomElement();
3352 if ( node->
alias().isEmpty() )
3354 mMapTableAliasToNames[ node->
name()] = node->
name();
3358 mMapTableAliasToNames[ node->
alias()] = node->
name();
3364 QList<QDomElement> listElem;
3367 ( node->
tables().size() != 1 || !node->
joins().empty() ) )
3369 mErrorMessage = QObject::tr(
"Joins are only supported with WFS 2.0" );
3370 return QDomElement();
3384 QList< QgsSQLStatement::NodeTableDef *> nodeTables = node->
tables();
3385 QString leftTable = nodeTables.at( nodeTables.length() - 1 )->name();
3388 QDomElement joinElem =
toOgcFilter( join, leftTable );
3389 if ( !mErrorMessage.isEmpty() )
3390 return QDomElement();
3391 listElem.append( joinElem );
3396 if ( node->
where() )
3399 if ( !mErrorMessage.isEmpty() )
3400 return QDomElement();
3401 listElem.append( whereElem );
3405 if ( listElem.size() == 1 )
3409 else if ( listElem.size() > 1 )
3411 QDomElement andElem = mDoc.createElement( mFilterPrefix +
":And" );
3412 Q_FOREACH (
const QDomElement &elem, listElem )
3414 andElem.appendChild( elem );
3419 return QDomElement();
Class for parsing and evaluation of expressions (formerly called "search strings").
QgsSQLStatement::NodeList * list() const
Values list.
A rectangle specified with double values.
Internal use by QgsOgcUtils.
QgsExpressionNode::NodeList * args() const
Returns a list of arguments specified for the function.
QgsSQLStatement::Node * onExpr() const
On expression. Will be nullptr if usingColumns() is not empty.
int params() const
The number of parameters this function takes.
void setXMaximum(double x)
Set the maximum x value.
Function with a name and arguments node.
QgsOgcUtilsExprToFilter(QDomDocument &doc, QgsOgcUtils::GMLVersion gmlVersion, QgsOgcUtils::FilterVersion filterVersion, const QString &geometryName, const QString &srsName, bool honourAxisOrientation, bool invertAxisOrientation)
Constructor.
void setExpression(const QString &expression)
Set the expression string, will reset the whole internal structure.
void fromWkb(unsigned char *wkb, int length)
Set the geometry, feeding in the buffer containing OGC Well-Known Binary and the buffer's length...
QgsExpressionNode * opRight() const
Returns the node to the right of the operator.
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
A class to represent a 2D point.
QgsSQLStatement::NodeTableDef * tableDef() const
Table definition.
QString dump() const
Returns an expression string, constructed from the internal abstract syntax tree. ...
QgsSQLStatement::Node * operand() const
Operand.
QgsSQLStatement::Node * where() const
Returns the where clause.
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item...
static const char * BINARY_OPERATOR_TEXT[]
bool convertCompatible(QVariant &v) const
Converts the provided variant to a compatible format.
QString errorMessage() const
Returns the error message.
bool GMLNamespaceUsed() const
Returns whether the gml: namespace is used.
QDomElement expressionNodeToOgcFilter(const QgsExpressionNode *node)
Convert an expression to a OGC filter.
A geometry is the spatial representation of a feature.
QgsExpressionNode::NodeList * list() const
Returns the list of nodes to search for matching values within.
QgsExpressionNode * opLeft() const
Returns the node to the left of the operator.
static QDomElement rectangleToGMLBox(QgsRectangle *box, QDomDocument &doc, int precision=17)
Exports the rectangle to GML2 Box.
QDomElement toOgcFilter(const QgsSQLStatement::Node *node)
Convert a SQL statement to a OGC filter.
Binary logical/arithmetical operator (AND, OR, =, +, ...)
QString name() const
The name of the column.
QVector< QgsPolygonXY > QgsMultiPolygonXY
A collection of QgsPolygons that share a common collection of attributes.
QString name() const
Returns function name.
QgsOgcUtilsSQLStatementToFilter(QDomDocument &doc, QgsOgcUtils::GMLVersion gmlVersion, QgsOgcUtils::FilterVersion filterVersion, const QList< QgsOgcUtils::LayerProperties > &layerProperties, bool honourAxisOrientation, bool invertAxisOrientation, const QMap< QString, QString > &mapUnprefixedTypenameToPrefixedTypename)
Constructor.
static QgsRectangle rectangleFromGMLBox(const QDomNode &boxNode)
Read rectangle from GML2 Box.
QgsSQLStatement::Node * node() const
Variable at the left of BETWEEN.
QList< QString > usingColumns() const
Columns referenced by USING.
const QString GML_NAMESPACE
static QgsRectangle rectangleFromGMLEnvelope(const QDomNode &envelopeNode)
Read rectangle from GML3 Envelope.
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
QgsSQLStatement::Node * minVal() const
Minimum bound.
bool GMLNamespaceUsed() const
Returns whether the gml: namespace is used.
bool isNotIn() const
Whether this is a NOT IN operator.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
QString text() const
Returns a the name of this operator without the operands.
Class for parsing SQL statements.
Type
The WKB type describes the number of dimensions a geometry has.
QString name() const
Table name.
QgsFields fields() const override
Returns the list of fields of this layer.
QString alias() const
Table alias.
static int functionIndex(const QString &name)
Returns index of the function in Functions array.
QgsSQLStatement::NodeList * args() const
Returns arguments.
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
void setYMinimum(double y)
Set the minimum y value.
BinaryOperator
list of binary operators
An expression node for value IN or NOT IN clauses.
Literal value (integer, integer64, double, string)
QString errorMessage() const
Returns the error message.
QString name() const
The name of the column.
QList< QgsSQLStatement::NodeTableDef * > tables() const
Returns the list of tables.
Internal use by QgsOgcUtils.
An expression node which takes it value from a feature's field.
Unary logicial/arithmetical operator ( NOT, - )
QgsSQLStatement::BinaryOperator op() const
Operator.
const QgsSQLStatement::Node * rootNode() const
Returns root node of the statement. Root node is null is parsing has failed.
static QDomElement SQLStatementToOgcFilter(const QgsSQLStatement &statement, QDomDocument &doc, QgsOgcUtils::GMLVersion gmlVersion, FilterVersion filterVersion, const QList< LayerProperties > &layerProperties, bool honourAxisOrientation, bool invertAxisOrientation, const QMap< QString, QString > &mapUnprefixedTypenameToPrefixedTypename, QString *errorMessage=nullptr)
Creates OGC filter XML element from the WHERE and JOIN clauses of a SQL statement.
BinaryOperator
list of binary operators
QString mSRSName
SRS name.
Abstract base class for all nodes that can appear in an expression.
Encapsulate a field in an attribute table or data source.
An expression node for expression functions.
static const QList< QgsExpressionFunction * > & Functions()
QgsSQLStatement::Node * maxVal() const
Maximum bound.
bool isNotBetween() const
Whether this is a NOT BETWEEN operator.
FilterVersion
OGC filter version.
QByteArray asWkb() const
Export the geometry to WKB.
'X BETWEEN y and z' operator
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
QString name() const
The name of the function.
Custom exception class for Wkb related exceptions.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
QVariant value() const
The value of the literal.
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
QList< QgsSQLStatement::NodeJoin * > joins() const
Returns the list of joins.
A abstract base class for defining QgsExpression functions.
A list of expression nodes.
static QgsGeometry geometryFromGML(const QString &xmlString)
Static method that creates geometry from GML.
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
QList< QgsExpressionNode * > list()
Gets a list of all the nodes.
QgsExpressionNodeUnaryOperator::UnaryOperator op() const
Returns the unary operator.
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
An expression node for literal values.
const QgsExpressionNode * rootNode() const
Returns root node of the expression. Root node is null is parsing has failed.
void setYMaximum(double y)
Set the maximum y value.
static QDomElement expressionToOgcFilter(const QgsExpression &exp, QDomDocument &doc, QString *errorMessage=nullptr)
Creates OGC filter XML element.
QList< QgsSQLStatement::Node * > list()
Returns list.
A unary node is either negative as in boolean (not) or as in numbers (minus).
static QDomElement expressionToOgcExpression(const QgsExpression &exp, QDomDocument &doc, QString *errorMessage=nullptr)
Creates an OGC expression XML element.
A binary expression operator, which operates on two values.
bool hasAxisInverted() const
Returns whether axis is inverted (e.g., for WMS 1.3) for the CRS.
This class represents a coordinate reference system (CRS).
static QDomElement geometryToGML(const QgsGeometry &geometry, QDomDocument &doc, QgsOgcUtils::GMLVersion gmlVersion, const QString &srsName, bool invertAxisOrientation, const QString &gmlIdBase, int precision=17)
Exports the geometry to GML.
QString text() const
Returns a the name of this operator without the operands.
static QDomElement rectangleToGMLEnvelope(QgsRectangle *env, QDomDocument &doc, int precision=17)
Exports the rectangle to GML3 Envelope.
static const char * UNARY_OPERATOR_TEXT[]
double xMinimum() const
Returns the x minimum value (left side of rectangle).
QString mGeometryAttribute
Geometry attribute name.
static QColor colorFromOgcFill(const QDomElement &fillElement)
Parse XML with OGC fill into QColor.
QString tableName() const
The name of the table. May be empty.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
void normalize()
Normalize the rectangle so it has non-negative width/height.
QgsSQLStatement::UnaryOperator op() const
Operator.
void append(QgsExpressionNode *node)
Takes ownership of the provided node.
static QgsExpression * expressionFromOgcFilter(const QDomElement &element, QgsVectorLayer *layer=nullptr)
Parse XML with OGC filter into QGIS expression.
QgsExpressionNode * node() const
Returns the expression node.
Represents a vector layer which manages a vector based data sets.
'x IN (y, z)' operator
bool isNotIn() const
Returns true if this node is a "NOT IN" operator, or false if the node is a normal "IN" operator...
virtual QgsExpressionNode::NodeType nodeType() const =0
Gets the type of this node.
QgsExpressionNode * operand() const
Returns the node the operator will operate upon.
QgsSQLStatement::Node * node() const
Variable at the left of IN.
The QgsOgcUtils class provides various utility functions for conversion between OGC (Open Geospatial ...
QgsExpressionNodeBinaryOperator::BinaryOperator op() const
Returns the binary operator.
QgsSQLStatement::Node * opLeft() const
Left operand.
QgsField field(int fieldIdx) const
Gets field at particular index (must be in range 0..N-1)
QgsSQLStatement::Node * opRight() const
Right operand.
void setXMinimum(double x)
Set the minimum x value.
QVariant value() const
The value of the literal.
virtual QgsSQLStatement::NodeType nodeType() const =0
Abstract virtual that returns the type of this node.
int fnIndex() const
Returns the index of the node's function.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.