Skip to content

Commit bc49b5e

Browse files
committedJul 2, 2017
[WFS provider] Do not be confuse by elements that have ref attribute when parsing DescribeFeatureType response; and fix support of (deprecated) ref='gml:XXXXProperty' attributes
1 parent 6e52f1b commit bc49b5e

File tree

2 files changed

+88
-3
lines changed

2 files changed

+88
-3
lines changed
 

‎src/providers/wfs/qgswfsprovider.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,7 +1279,12 @@ bool QgsWFSProvider::readAttributesFromSchema( QDomDocument& schemaDoc,
12791279
}
12801280
}
12811281

1282+
// attribute ref
1283+
QString ref = attributeElement.attribute( QStringLiteral( "ref" ) );
1284+
12821285
QRegExp gmlPT( "gml:(.*)PropertyType" );
1286+
QRegExp gmlRefProperty( "gml:(.*)Property" );
1287+
12831288
// gmgml: is Geomedia Web Server
12841289
if ( type == "gmgml:Polygon_Surface_MultiSurface_CompositeSurfacePropertyType" )
12851290
{
@@ -1294,15 +1299,25 @@ bool QgsWFSProvider::readAttributesFromSchema( QDomDocument& schemaDoc,
12941299
geomType = QGis::WKBMultiLineString;
12951300
}
12961301
//is it a geometry attribute?
1297-
//MH 090428: sometimes the <element> tags for geometry attributes have only attribute ref="gml:polygonProperty" and no name
12981302
// the GeometryAssociationType has been seen in #11785
1299-
else if ( type.indexOf( gmlPT ) == 0 || type == "gml:GeometryAssociationType" || name.isEmpty() )
1303+
else if ( type.indexOf( gmlPT ) == 0 || type == "gml:GeometryAssociationType" )
13001304
{
13011305
foundGeometryAttribute = true;
13021306
geometryAttribute = name;
13031307
geomType = geomTypeFromPropertyType( geometryAttribute, gmlPT.cap( 1 ) );
13041308
}
1305-
else //todo: distinguish between numerical and non-numerical types
1309+
//MH 090428: sometimes the <element> tags for geometry attributes have only attribute ref="gml:polygonProperty"
1310+
//Note: this was deprecated with GML3.
1311+
else if ( ref.indexOf( gmlRefProperty ) == 0 )
1312+
{
1313+
foundGeometryAttribute = true;
1314+
geometryAttribute = ref.mid( 4 ); // Strip gml: prefix
1315+
QString propertyType( gmlRefProperty.cap( 1 ) );
1316+
// Set the first character in upper case
1317+
propertyType = propertyType.left( 1 ).toUpper() + propertyType.mid( 1 );
1318+
geomType = geomTypeFromPropertyType( geometryAttribute, propertyType );
1319+
}
1320+
else if ( !name.isEmpty() ) //todo: distinguish between numerical and non-numerical types
13061321
{
13071322
QVariant::Type attributeType = QVariant::String; //string is default type
13081323
if ( type.contains( "double", Qt::CaseInsensitive ) || type.contains( "float", Qt::CaseInsensitive ) || type.contains( "decimal", Qt::CaseInsensitive ) )

‎tests/src/python/test_provider_wfs.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,14 @@ def setUpClass(cls):
118118
<xsd:element maxOccurs="1" minOccurs="0" name="name2" nillable="true" type="xsd:string"/>
119119
<xsd:element maxOccurs="1" minOccurs="0" name="num_char" nillable="true" type="xsd:string"/>
120120
<xsd:element maxOccurs="1" minOccurs="0" name="geometryProperty" nillable="true" type="gml:PolygonPropertyType"/>
121+
<!-- check that an element with ref without name doesn't confuse the DescribeFeatureType analyzer -->
122+
<xsd:element maxOccurs="0" minOccurs="0" ref="my:somethingElseType"/>
121123
</xsd:sequence>
122124
</xsd:extension>
123125
</xsd:complexContent>
124126
</xsd:complexType>
125127
<xsd:element name="typename" substitutionGroup="gml:_Feature" type="my:typenameType"/>
128+
<xsd:complexType name="somethingElseType"/>
126129
</xsd:schema>
127130
""".encode('UTF-8'))
128131

@@ -2483,6 +2486,73 @@ def testWFS20TransactionsEnabled(self):
24832486
self.assertNotEqual(vl.dataProvider().capabilities() & vl.dataProvider().EditingCapabilities, 0)
24842487
self.assertEqual(vl.wkbType(), QgsWKBTypes.Point)
24852488

2489+
def testDeprecatedGML2GeometryDeclaration(self):
2490+
"""Test ref="gml:pointProperty" """
2491+
2492+
endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_deprecated_gml2'
2493+
2494+
with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.0.0'), 'wb') as f:
2495+
f.write("""
2496+
<WFS_Capabilities version="1.0.0" xmlns="http://www.opengis.net/wfs" xmlns:ogc="http://www.opengis.net/ogc">
2497+
<FeatureTypeList>
2498+
<FeatureType>
2499+
<Name>my:typename</Name>
2500+
<Title>Title</Title>
2501+
<Abstract>Abstract</Abstract>
2502+
<SRS>EPSG:32631</SRS>
2503+
<!-- in WFS 1.0, LatLongBoundingBox is in SRS units, not necessarily lat/long... -->
2504+
<LatLongBoundingBox minx="400000" miny="5400000" maxx="450000" maxy="5500000"/>
2505+
</FeatureType>
2506+
</FeatureTypeList>
2507+
</WFS_Capabilities>""".encode('UTF-8'))
2508+
2509+
with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.0.0&TYPENAME=my:typename'), 'wb') as f:
2510+
f.write("""
2511+
<xsd:schema xmlns:my="http://my" xmlns:gml="http://www.opengis.net/gml" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://my">
2512+
<xsd:import namespace="http://www.opengis.net/gml"/>
2513+
<xsd:complexType name="typenameType">
2514+
<xsd:complexContent>
2515+
<xsd:extension base="gml:AbstractFeatureType">
2516+
<xsd:sequence>
2517+
<xsd:element maxOccurs="1" minOccurs="0" ref="gml:pointProperty"/>
2518+
<xsd:element maxOccurs="1" minOccurs="0" name="INTFIELD" nillable="true" type="xsd:int"/>
2519+
</xsd:sequence>
2520+
</xsd:extension>
2521+
</xsd:complexContent>
2522+
</xsd:complexType>
2523+
<xsd:element name="typename" substitutionGroup="gml:_Feature" type="my:typenameType"/>
2524+
</xsd:schema>
2525+
""".encode('UTF-8'))
2526+
2527+
vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename' version='1.0.0'", 'test', 'WFS')
2528+
assert vl.isValid()
2529+
self.assertEqual(vl.wkbType(), QgsWKBTypes.Point)
2530+
self.assertEqual(len(vl.fields()), 1)
2531+
2532+
with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.0.0&TYPENAME=my:typename&SRSNAME=EPSG:32631'), 'wb') as f:
2533+
f.write("""
2534+
<wfs:FeatureCollection
2535+
xmlns:wfs="http://www.opengis.net/wfs"
2536+
xmlns:gml="http://www.opengis.net/gml"
2537+
xmlns:my="http://my">
2538+
<gml:boundedBy><gml:null>unknown</gml:null></gml:boundedBy>
2539+
<gml:featureMember>
2540+
<my:typename fid="typename.0">
2541+
<gml:pointProperty>
2542+
<gml:Point srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"><gml:coordinates decimal="." cs="," ts=" ">426858,5427937</gml:coordinates></gml:Point>
2543+
</gml:pointProperty>
2544+
<my:INTFIELD>1</my:INTFIELD>
2545+
</my:typename>
2546+
</gml:featureMember>
2547+
</wfs:FeatureCollection>""".encode('UTF-8'))
2548+
2549+
values = [f['INTFIELD'] for f in vl.getFeatures()]
2550+
self.assertEqual(values, [1])
2551+
2552+
got_f = [f for f in vl.getFeatures()]
2553+
got = got_f[0].geometry().geometry()
2554+
self.assertEqual((got.x(), got.y()), (426858.0, 5427937.0))
2555+
24862556

24872557
if __name__ == '__main__':
24882558
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.