Skip to content

Commit 1d2686d

Browse files
committedMay 31, 2018
[WFS provider] Handle DescribeFeatureType responses that consist of a single <include> (fixes #18267)
Also handle another occurence of a buggy server only accepting TYPENAMES plural as parameter of DescribeFeatureType
1 parent 25ba361 commit 1d2686d

File tree

2 files changed

+102
-1
lines changed

2 files changed

+102
-1
lines changed
 

‎src/providers/wfs/qgswfsprovider.cpp

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,17 @@ bool QgsWFSProvider::describeFeatureType( QString &geometryAttribute, QgsFields
12141214
QgsDebugMsg( "Server does not accept TYPENAME parameter for DescribeFeatureType. Re-trying with TYPENAMES" );
12151215
bUsePlural = true;
12161216
}
1217+
// "http://services.cuzk.cz/wfs/inspire-cp-wfs.asp?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=cp:CadastralParcel" returns
1218+
// <!--Generated by Marushka, version 4.2.5.0, GEOVAP, spol. s r.o., 31.05.2018.-->
1219+
// <ExceptionReport xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="1.0.0" xml:lang="en-US" xmlns="http://www.opengis.net/ows/1.1">
1220+
// <Exception exceptionCode="OperationProcessingFailed" />
1221+
// </ExceptionReport>
1222+
else if ( i == 0 && response.indexOf( "<!--Generated by Marushka" ) >= 0 &&
1223+
response.indexOf( "OperationProcessingFailed" ) >= 0 )
1224+
{
1225+
QgsDebugMsg( "Server does not accept TYPENAME parameter for DescribeFeatureType. Re-trying with TYPENAMES" );
1226+
bUsePlural = true;
1227+
}
12171228
else
12181229
{
12191230
break;
@@ -1234,6 +1245,7 @@ bool QgsWFSProvider::describeFeatureType( QString &geometryAttribute, QgsFields
12341245
mShared->mURI.typeName(),
12351246
geometryAttribute, fields, geomType, errorMsg ) )
12361247
{
1248+
QgsDebugMsg( response );
12371249
QgsMessageLog::logMessage( tr( "Analysis of DescribeFeatureType response failed for url %1: %2" ).
12381250
arg( dataSourceUri(), errorMsg ), tr( "WFS" ) );
12391251
return false;
@@ -1306,11 +1318,21 @@ bool QgsWFSProvider::readAttributesFromSchema( QDomDocument &schemaDoc,
13061318
QDomElement iter = schemaElement.firstChildElement();
13071319
bool onlyIncludeOrImport = true;
13081320
bool foundImport = false;
1321+
int countInclude = 0;
1322+
QDomElement includeElement;
13091323
while ( !iter.isNull() )
13101324
{
13111325
if ( iter.tagName() == QLatin1String( "import" ) )
13121326
foundImport = true;
1313-
else if ( iter.tagName() != QLatin1String( "include" ) )
1327+
else if ( iter.tagName() == QLatin1String( "include" ) )
1328+
{
1329+
countInclude++;
1330+
if ( countInclude == 1 )
1331+
{
1332+
includeElement = iter;
1333+
}
1334+
}
1335+
else
13141336
{
13151337
onlyIncludeOrImport = false;
13161338
break;
@@ -1321,6 +1343,41 @@ bool QgsWFSProvider::readAttributesFromSchema( QDomDocument &schemaDoc,
13211343
{
13221344
errorMsg = tr( "It is probably a schema for Complex Features." );
13231345
}
1346+
// e.g http://services.cuzk.cz/wfs/inspire-CP-wfs.asp?SERVICE=WFS&VERSION=2.0.0&REQUEST=DescribeFeatureType
1347+
// which has a single <include schemaLocation="http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd"/>
1348+
// In that case, follow the link.
1349+
else if ( !foundImport && countInclude == 1 )
1350+
{
1351+
QString schemaLocation =
1352+
includeElement.attribute( QStringLiteral( "schemaLocation" ) );
1353+
QgsDebugMsg( QStringLiteral( "DescribeFeatureType response redirects to: %1" ).arg( schemaLocation ) );
1354+
1355+
QgsWFSDescribeFeatureType describeFeatureType( mShared->mURI );
1356+
if ( !describeFeatureType.sendGET( schemaLocation, true, false ) )
1357+
{
1358+
errorMsg = tr( "Cannot find schema indicated in DescribeFeatureType response." );
1359+
QgsMessageLog::logMessage( tr( "DescribeFeatureType network request failed for url %1: %2" ).
1360+
arg( schemaLocation, describeFeatureType.errorMessage() ), tr( "WFS" ) );
1361+
return false;
1362+
}
1363+
1364+
QByteArray response = describeFeatureType.response();
1365+
QDomDocument describeFeatureDocument;
1366+
if ( !describeFeatureDocument.setContent( response, true, &errorMsg ) )
1367+
{
1368+
QgsDebugMsg( response );
1369+
errorMsg = tr( "DescribeFeatureType XML parse failed for url %1: %2" ).
1370+
arg( schemaLocation, errorMsg );
1371+
}
1372+
1373+
return readAttributesFromSchema( describeFeatureDocument,
1374+
prefixedTypename,
1375+
geometryAttribute,
1376+
fields,
1377+
geomType,
1378+
errorMsg );
1379+
1380+
}
13241381
else
13251382
{
13261383
errorMsg = tr( "Cannot find element '%1'" ).arg( unprefixedTypename );

‎tests/src/python/test_provider_wfs.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3267,6 +3267,50 @@ def testWfs20DescribeFeatureTypePluralForm(self):
32673267
</xsd:complexType>
32683268
<xsd:element name="typename" substitutionGroup="gml:_Feature" type="my:typenameType"/>
32693269
</xsd:schema>
3270+
""".encode('UTF-8'))
3271+
3272+
# Create test layer
3273+
vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename'", 'test', 'WFS')
3274+
self.assertTrue(vl.isValid())
3275+
3276+
def testDescribeFeatureTypeWithSingleInclude(self):
3277+
"""Test DescribeFeatureType response which has a single <include> child node"""
3278+
3279+
endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_DescribeFeatureTypeWithSingleInclude'
3280+
3281+
with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), 'wb') as f:
3282+
f.write("""
3283+
<wfs:WFS_Capabilities version="2.0.0" xmlns="http://www.opengis.net/wfs/2.0" xmlns:wfs="http://www.opengis.net/wfs/2.0" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:gml="http://schemas.opengis.net/gml/3.2" xmlns:fes="http://www.opengis.net/fes/2.0">
3284+
<FeatureTypeList>
3285+
<FeatureType>
3286+
<Name>my:typename</Name>
3287+
<DefaultCRS>urn:ogc:def:crs:EPSG::4326</DefaultCRS>
3288+
</FeatureType>
3289+
</FeatureTypeList>
3290+
</wfs:WFS_Capabilities>""".encode('UTF-8'))
3291+
3292+
with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=my:typename'), 'wb') as f:
3293+
f.write(("""
3294+
<schema xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://my">
3295+
<include schemaLocation="%s"/>
3296+
</schema>
3297+
""" % ('http://' + endpoint + '?myschema.xsd')).encode('UTF-8'))
3298+
3299+
with open(sanitize(endpoint, '?myschema.xsd'), 'wb') as f:
3300+
f.write("""
3301+
<xsd:schema xmlns:my="http://my" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://my">
3302+
<xsd:import namespace="http://www.opengis.net/gml/3.2"/>
3303+
<xsd:complexType name="typenameType">
3304+
<xsd:complexContent>
3305+
<xsd:extension base="gml:AbstractFeatureType">
3306+
<xsd:sequence>
3307+
<xsd:element maxOccurs="1" minOccurs="0" name="geometryProperty" nillable="true" type="gml:PointPropertyType"/>
3308+
</xsd:sequence>
3309+
</xsd:extension>
3310+
</xsd:complexContent>
3311+
</xsd:complexType>
3312+
<xsd:element name="typename" substitutionGroup="gml:_Feature" type="my:typenameType"/>
3313+
</xsd:schema>
32703314
""".encode('UTF-8'))
32713315

32723316
# Create test layer

0 commit comments

Comments
 (0)
Please sign in to comment.