Skip to content

Commit d628c2c

Browse files
committedMar 6, 2013
Improved support for parsing of GML2, added some autotests
1 parent ed48ffb commit d628c2c

File tree

6 files changed

+175
-16
lines changed

6 files changed

+175
-16
lines changed
 

‎python/core/qgsgeometry.sip

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,18 @@ class QgsGeometry
4141
/** static method that creates geometry from Wkt */
4242
static QgsGeometry* fromWkt( QString wkt ) /Factory/;
4343

44+
/** static method that creates geometry from GML2
45+
@param XML representation of the geometry. GML elements are expected to be
46+
in default namespace (<Point>...</Point>) or in "gml" namespace (<gml:Point>...</gml:Point>)
47+
@note added in 1.9
48+
*/
49+
static QgsGeometry* fromGML2( const QString& xmlString ) /Factory/;
50+
51+
/** static method that creates geometry from GML2
52+
@note added in 1.9
53+
*/
54+
static QgsGeometry* fromGML2( const QDomNode& geometryNode ) /Factory/;
55+
4456
/** construct geometry from a point */
4557
static QgsGeometry* fromPoint( const QgsPoint& point ) /Factory/;
4658
/** construct geometry from a multipoint */

‎src/core/qgsexpression.cpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -795,21 +795,8 @@ static QVariant fcnGeomFromWKT( const QVariantList& values, QgsFeature*, QgsExpr
795795
}
796796
static QVariant fcnGeomFromGML2( const QVariantList& values, QgsFeature*, QgsExpression* parent )
797797
{
798-
QDomDocument doc;
799-
QString errorMsg;
800798
QString gml = getStringValue( values.at( 0 ), parent );
801-
if ( !doc.setContent( gml, true, &errorMsg ) )
802-
return QVariant();
803-
804-
QgsGeometry* geom = 0;
805-
QDomElement elem = doc.documentElement();
806-
if ( elem.tagName() == "Box" )
807-
{
808-
QgsRectangle* rect = new QgsRectangle( elem );
809-
geom = QgsGeometry::fromRect( *rect );
810-
}
811-
else
812-
geom = QgsGeometry::fromGML2( doc.documentElement() );
799+
QgsGeometry* geom = QgsGeometry::fromGML2( gml );
813800

814801
if ( geom )
815802
return QVariant::fromValue( *geom );

‎src/core/qgsgeometry.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ QgsGeometry* QgsGeometry::fromGML2( const QDomNode& geometryNode )
540540
QDomElement geometryTypeElement = geometryNode.toElement();
541541
QString geomType = geometryTypeElement.tagName();
542542

543-
if ( !( geomType == "Point" || geomType == "LineString" || geomType == "Polygon" || geomType == "MultiPoint" || geomType == "MultiLineString" || geomType == "MultiPolygon" ) )
543+
if ( !( geomType == "Point" || geomType == "LineString" || geomType == "Polygon" || geomType == "MultiPoint" || geomType == "MultiLineString" || geomType == "MultiPolygon" || geomType == "Box" ) )
544544
{
545545
QDomNode geometryChild = geometryNode.firstChild();
546546
if ( geometryChild.isNull() )
@@ -551,7 +551,7 @@ QgsGeometry* QgsGeometry::fromGML2( const QDomNode& geometryNode )
551551
geomType = geometryTypeElement.tagName();
552552
}
553553

554-
if ( !( geomType == "Point" || geomType == "LineString" || geomType == "Polygon" || geomType == "MultiPoint" || geomType == "MultiLineString" || geomType == "MultiPolygon" ) )
554+
if ( !( geomType == "Point" || geomType == "LineString" || geomType == "Polygon" || geomType == "MultiPoint" || geomType == "MultiLineString" || geomType == "MultiPolygon" || geomType == "Box" ) )
555555
return 0;
556556

557557
if ( geomType == "Point" && g->setFromGML2Point( geometryTypeElement ) )
@@ -578,12 +578,28 @@ QgsGeometry* QgsGeometry::fromGML2( const QDomNode& geometryNode )
578578
{
579579
return g;
580580
}
581+
else if ( geomType == "Box" )
582+
{
583+
return QgsGeometry::fromRect( QgsRectangle( geometryTypeElement ) );
584+
}
581585
else //unknown type
582586
{
583587
return 0;
584588
}
585589
}
586590

591+
QgsGeometry* QgsGeometry::fromGML2( const QString& xmlString )
592+
{
593+
// wrap the string into a root tag to have "gml" namespace (and also as a default namespace)
594+
QString xml = QString( "<tmp xmlns=\"%1\" xmlns:gml=\"%1\">%2</tmp>").arg( GML_NAMESPACE ).arg( xmlString );
595+
QDomDocument doc;
596+
if ( !doc.setContent( xml, true ) )
597+
return 0;
598+
599+
return fromGML2( doc.documentElement().firstChildElement() );
600+
}
601+
602+
587603
bool QgsGeometry::setFromGML2Point( const QDomElement& geometryElement )
588604
{
589605
QDomNodeList coordList = geometryElement.elementsByTagNameNS( GML_NAMESPACE, "coordinates" );

‎src/core/qgsgeometry.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,13 @@ class CORE_EXPORT QgsGeometry
8989
/** static method that creates geometry from Wkt */
9090
static QgsGeometry* fromWkt( QString wkt );
9191

92+
/** static method that creates geometry from GML2
93+
@param XML representation of the geometry. GML elements are expected to be
94+
in default namespace (<Point>...</Point>) or in "gml" namespace (<gml:Point>...</gml:Point>)
95+
@note added in 1.9
96+
*/
97+
static QgsGeometry* fromGML2( const QString& xmlString );
98+
9299
/** static method that creates geometry from GML2
93100
@note added in 1.9
94101
*/

‎tests/src/core/testqgsexpression.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,20 @@ class TestQgsExpression: public QObject
569569
QTest::newRow( "geomFromWKT Line" ) << "geomFromWKT('" + QgsGeometry::fromPolyline( line )->exportToWkt() + "')" << ( void* ) QgsGeometry::fromPolyline( line ) << false;
570570
QTest::newRow( "geomFromWKT Polyline" ) << "geomFromWKT('" + QgsGeometry::fromPolyline( polyline )->exportToWkt() + "')" << ( void* ) QgsGeometry::fromPolyline( polyline ) << false;
571571
QTest::newRow( "geomFromWKT Polygon" ) << "geomFromWKT('" + QgsGeometry::fromPolygon( polygon )->exportToWkt() + "')" << ( void* ) QgsGeometry::fromPolygon( polygon ) << false;
572+
573+
// GML Point
574+
QTest::newRow( "GML Point (coordinates)" ) << "geomFromGML2('<gml:Point><gml:coordinates>123,456</gml:coordinates></gml:Point>')" << ( void * ) QgsGeometry::fromPoint( point ) << false;
575+
// gml:pos if from GML3
576+
//QTest::newRow( "GML Point (pos)" ) << "geomFromGML2('<gml:Point srsName=\"foo\"><gml:pos srsDimension=\"2\">123 456</gml:pos></gml:Point>')" << ( void * ) QgsGeometry::fromPoint( point ) << false;
577+
578+
// GML Box
579+
QgsRectangle rect( 135.2239, 34.4879, 135.8578, 34.8471 );
580+
QTest::newRow( "GML Box" ) << "geomFromGML2('<gml:Box srsName=\"foo\"><gml:coordinates>135.2239,34.4879 135.8578,34.8471</gml:coordinates></gml:Box>')" << ( void * ) QgsGeometry::fromRect( rect ) << false;
581+
// Envelope is from GML3 ?
582+
//QTest::newRow( "GML Envelope" ) << "geomFromGML2('<gml:Envelope>"
583+
// "<gml:lowerCorner>135.2239 34.4879</gml:lowerCorner>"
584+
// "<gml:upperCorner>135.8578 34.8471</gml:upperCorner>"
585+
// "</gml:Envelope>')" << ( void * ) QgsGeometry::fromRect( rect ) << false;
572586
}
573587

574588
void eval_geometry_constructor()
@@ -744,6 +758,113 @@ class TestQgsExpression: public QObject
744758
QgsExpression::unsetSpecialColumn( "$var1" );
745759
}
746760

761+
762+
void test_from_ogc_filter_data()
763+
{
764+
QTest::addColumn<QString>( "xmlText" );
765+
QTest::addColumn<QString>( "dumpText" );
766+
767+
QTest::newRow( "=" ) << QString(
768+
"<Filter><PropertyIsEqualTo>"
769+
"<PropertyName>NAME</PropertyName>"
770+
"<Literal>New York</Literal>"
771+
"</PropertyIsEqualTo></Filter>" )
772+
<< QString( "NAME = 'New York'" );
773+
774+
QTest::newRow( ">" ) << QString(
775+
"<Filter><PropertyIsGreaterThan>"
776+
"<PropertyName>COUNT</PropertyName>"
777+
"<Literal>3</Literal>"
778+
"</PropertyIsGreaterThan></Filter>" )
779+
<< QString( "COUNT > 3" );
780+
781+
QTest::newRow( "AND" ) << QString(
782+
"<ogc:Filter>"
783+
"<ogc:And>"
784+
"<ogc:PropertyIsGreaterThanOrEqualTo>"
785+
"<ogc:PropertyName>pop</ogc:PropertyName>"
786+
"<ogc:Literal>50000</ogc:Literal>"
787+
"</ogc:PropertyIsGreaterThanOrEqualTo>"
788+
"<ogc:PropertyIsLessThan>"
789+
"<ogc:PropertyName>pop</ogc:PropertyName>"
790+
"<ogc:Literal>100000</ogc:Literal>"
791+
"</ogc:PropertyIsLessThan>"
792+
"</ogc:And>"
793+
"</ogc:Filter>" )
794+
<< QString( "pop >= 50000 AND pop < 100000" );
795+
796+
// TODO: should work also without <Literal> tags in Lower/Upper-Boundary tags?
797+
QTest::newRow( "between" ) << QString(
798+
"<Filter>"
799+
"<PropertyIsBetween><PropertyName>POPULATION</PropertyName>"
800+
"<LowerBoundary><Literal>100</Literal></LowerBoundary>"
801+
"<UpperBoundary><Literal>200</Literal></UpperBoundary></PropertyIsBetween>"
802+
"</Filter>" )
803+
<< QString( "POPULATION >= 100 AND POPULATION <= 200" );
804+
805+
// TODO: needs to handle different wildcards, single chars, escape chars
806+
QTest::newRow( "like" ) << QString(
807+
"<Filter>"
808+
"<PropertyIsLike wildcard='*' singleChar='.' escape='!'>"
809+
"<PropertyName>NAME</PropertyName><Literal>*QGIS*</Literal></PropertyIsLike>"
810+
"</Filter>" )
811+
<< QString( "NAME LIKE '*QGIS*'" );
812+
813+
QTest::newRow( "is null" ) << QString(
814+
"<Filter>"
815+
"<ogc:PropertyIsNull>"
816+
"<ogc:PropertyName>FIRST_NAME</ogc:PropertyName>"
817+
"</ogc:PropertyIsNull>"
818+
"</Filter>" )
819+
<< QString( "FIRST_NAME IS NULL" );
820+
821+
QTest::newRow( "bbox" ) << QString(
822+
"<Filter>"
823+
"<BBOX><PropertyName>Name>NAME</PropertyName><gml:Box srsName='foo'>"
824+
"<gml:coordinates>135.2239,34.4879 135.8578,34.8471</gml:coordinates></gml:Box></BBOX>"
825+
"</Filter>" )
826+
<< QString( "bbox($geometry, geomFromGML2('<Box srsName=\"foo\"><coordinates>135.2239,34.4879 135.8578,34.8471</coordinates></Box>'))" );
827+
828+
QTest::newRow( "Intersects" ) << QString(
829+
"<Filter>"
830+
"<Intersects>"
831+
"<PropertyName>GEOMETRY</PropertyName>"
832+
"<gml:Point>"
833+
"<gml:coordinates>123,456</gml:coordinates>"
834+
"</gml:Point>"
835+
"</Intersects>"
836+
"</Filter>" )
837+
<< QString( "intersects($geometry, geomFromGML2('<Point><coordinates>123,456</coordinates></Point>'))" );
838+
}
839+
840+
void test_from_ogc_filter()
841+
{
842+
QFETCH( QString, xmlText );
843+
QFETCH( QString, dumpText );
844+
845+
QDomDocument doc;
846+
QVERIFY(doc.setContent(xmlText, true));
847+
QDomElement rootElem = doc.documentElement();
848+
849+
QgsExpression* expr = QgsExpression::createFromOgcFilter( rootElem );
850+
QVERIFY( expr );
851+
852+
qDebug("OGC XML : %s", xmlText.toAscii().data() );
853+
qDebug("EXPR-DUMP: %s", expr->dump().toAscii().data() );
854+
855+
if ( expr->hasParserError() )
856+
qDebug( "ERROR: %s ", expr->parserErrorString().toAscii().data() );
857+
QVERIFY( !expr->hasParserError() );
858+
859+
QCOMPARE( dumpText, expr->dump() );
860+
861+
delete expr;
862+
}
863+
864+
void test_to_ogc_filter()
865+
{
866+
// TODO
867+
}
747868
};
748869

749870
QTEST_MAIN( TestQgsExpression )

‎tests/src/core/testqgsgeometry.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ class TestQgsGeometry: public QObject
5555
void differenceCheck1();
5656
void differenceCheck2();
5757
void bufferCheck();
58+
59+
void gmlTest();
60+
5861
private:
5962
/** A helper method to do a render check to see if the geometry op is as expected */
6063
bool renderCheck( QString theTestName, QString theComment = "" );
@@ -369,6 +372,19 @@ void TestQgsGeometry::dumpPolyline( QgsPolyline &thePolyline )
369372
mpPainter->drawPolyline( myPoints );
370373
}
371374

375+
void TestQgsGeometry::gmlTest()
376+
{
377+
QgsGeometry* geom = QgsGeometry::fromGML2( "<Point><coordinates>123,456</coordinates></Point>" );
378+
QVERIFY( geom );
379+
QVERIFY( geom->wkbType() == QGis::WKBPoint );
380+
QVERIFY( geom->asPoint() == QgsPoint( 123, 456 ) );
381+
382+
QgsGeometry* geomBox = QgsGeometry::fromGML2( "<gml:Box srsName=\"foo\"><gml:coordinates>135.2239,34.4879 135.8578,34.8471</gml:coordinates></gml:Box>" );
383+
QVERIFY( geomBox );
384+
QVERIFY( geomBox->wkbType() == QGis::WKBPolygon );
385+
}
386+
387+
372388
QTEST_MAIN( TestQgsGeometry )
373389
#include "moc_testqgsgeometry.cxx"
374390

0 commit comments

Comments
 (0)
Please sign in to comment.