Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[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
  • Loading branch information
rouault committed May 31, 2018
1 parent 25ba361 commit 1d2686d
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 1 deletion.
59 changes: 58 additions & 1 deletion src/providers/wfs/qgswfsprovider.cpp
Expand Up @@ -1214,6 +1214,17 @@ bool QgsWFSProvider::describeFeatureType( QString &geometryAttribute, QgsFields
QgsDebugMsg( "Server does not accept TYPENAME parameter for DescribeFeatureType. Re-trying with TYPENAMES" );
bUsePlural = true;
}
// "http://services.cuzk.cz/wfs/inspire-cp-wfs.asp?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=cp:CadastralParcel" returns
// <!--Generated by Marushka, version 4.2.5.0, GEOVAP, spol. s r.o., 31.05.2018.-->
// <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">
// <Exception exceptionCode="OperationProcessingFailed" />
// </ExceptionReport>
else if ( i == 0 && response.indexOf( "<!--Generated by Marushka" ) >= 0 &&
response.indexOf( "OperationProcessingFailed" ) >= 0 )
{
QgsDebugMsg( "Server does not accept TYPENAME parameter for DescribeFeatureType. Re-trying with TYPENAMES" );
bUsePlural = true;
}
else
{
break;
Expand All @@ -1234,6 +1245,7 @@ bool QgsWFSProvider::describeFeatureType( QString &geometryAttribute, QgsFields
mShared->mURI.typeName(),
geometryAttribute, fields, geomType, errorMsg ) )
{
QgsDebugMsg( response );
QgsMessageLog::logMessage( tr( "Analysis of DescribeFeatureType response failed for url %1: %2" ).
arg( dataSourceUri(), errorMsg ), tr( "WFS" ) );
return false;
Expand Down Expand Up @@ -1306,11 +1318,21 @@ bool QgsWFSProvider::readAttributesFromSchema( QDomDocument &schemaDoc,
QDomElement iter = schemaElement.firstChildElement();
bool onlyIncludeOrImport = true;
bool foundImport = false;
int countInclude = 0;
QDomElement includeElement;
while ( !iter.isNull() )
{
if ( iter.tagName() == QLatin1String( "import" ) )
foundImport = true;
else if ( iter.tagName() != QLatin1String( "include" ) )
else if ( iter.tagName() == QLatin1String( "include" ) )
{
countInclude++;
if ( countInclude == 1 )
{
includeElement = iter;
}
}
else
{
onlyIncludeOrImport = false;
break;
Expand All @@ -1321,6 +1343,41 @@ bool QgsWFSProvider::readAttributesFromSchema( QDomDocument &schemaDoc,
{
errorMsg = tr( "It is probably a schema for Complex Features." );
}
// e.g http://services.cuzk.cz/wfs/inspire-CP-wfs.asp?SERVICE=WFS&VERSION=2.0.0&REQUEST=DescribeFeatureType
// which has a single <include schemaLocation="http://inspire.ec.europa.eu/schemas/cp/4.0/CadastralParcels.xsd"/>
// In that case, follow the link.
else if ( !foundImport && countInclude == 1 )
{
QString schemaLocation =
includeElement.attribute( QStringLiteral( "schemaLocation" ) );
QgsDebugMsg( QStringLiteral( "DescribeFeatureType response redirects to: %1" ).arg( schemaLocation ) );

QgsWFSDescribeFeatureType describeFeatureType( mShared->mURI );
if ( !describeFeatureType.sendGET( schemaLocation, true, false ) )
{
errorMsg = tr( "Cannot find schema indicated in DescribeFeatureType response." );
QgsMessageLog::logMessage( tr( "DescribeFeatureType network request failed for url %1: %2" ).
arg( schemaLocation, describeFeatureType.errorMessage() ), tr( "WFS" ) );
return false;
}

QByteArray response = describeFeatureType.response();
QDomDocument describeFeatureDocument;
if ( !describeFeatureDocument.setContent( response, true, &errorMsg ) )
{
QgsDebugMsg( response );
errorMsg = tr( "DescribeFeatureType XML parse failed for url %1: %2" ).
arg( schemaLocation, errorMsg );
}

return readAttributesFromSchema( describeFeatureDocument,
prefixedTypename,
geometryAttribute,
fields,
geomType,
errorMsg );

}
else
{
errorMsg = tr( "Cannot find element '%1'" ).arg( unprefixedTypename );
Expand Down
44 changes: 44 additions & 0 deletions tests/src/python/test_provider_wfs.py
Expand Up @@ -3267,6 +3267,50 @@ def testWfs20DescribeFeatureTypePluralForm(self):
</xsd:complexType>
<xsd:element name="typename" substitutionGroup="gml:_Feature" type="my:typenameType"/>
</xsd:schema>
""".encode('UTF-8'))

# Create test layer
vl = QgsVectorLayer("url='http://" + endpoint + "' typename='my:typename'", 'test', 'WFS')
self.assertTrue(vl.isValid())

def testDescribeFeatureTypeWithSingleInclude(self):
"""Test DescribeFeatureType response which has a single <include> child node"""

endpoint = self.__class__.basetestpath + '/fake_qgis_http_endpoint_DescribeFeatureTypeWithSingleInclude'

with open(sanitize(endpoint, '?SERVICE=WFS?REQUEST=GetCapabilities?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0'), 'wb') as f:
f.write("""
<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">
<FeatureTypeList>
<FeatureType>
<Name>my:typename</Name>
<DefaultCRS>urn:ogc:def:crs:EPSG::4326</DefaultCRS>
</FeatureType>
</FeatureTypeList>
</wfs:WFS_Capabilities>""".encode('UTF-8'))

with open(sanitize(endpoint, '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=2.0.0&TYPENAME=my:typename'), 'wb') as f:
f.write(("""
<schema xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://my">
<include schemaLocation="%s"/>
</schema>
""" % ('http://' + endpoint + '?myschema.xsd')).encode('UTF-8'))

with open(sanitize(endpoint, '?myschema.xsd'), 'wb') as f:
f.write("""
<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">
<xsd:import namespace="http://www.opengis.net/gml/3.2"/>
<xsd:complexType name="typenameType">
<xsd:complexContent>
<xsd:extension base="gml:AbstractFeatureType">
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="0" name="geometryProperty" nillable="true" type="gml:PointPropertyType"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="typename" substitutionGroup="gml:_Feature" type="my:typenameType"/>
</xsd:schema>
""".encode('UTF-8'))

# Create test layer
Expand Down

0 comments on commit 1d2686d

Please sign in to comment.