Skip to content

Commit 5c89fdf

Browse files
committedJan 22, 2015
[SERVER][FEATURE] Add DescribeLayer Method to WMS
*Styled Layer Descriptor profile of the Web Map Service* : DescribeLayer http://www.opengeospatial.org/standards/sld Defining a user-defined style requires information about the features being symbolized, or at least their feature/coverage type. Since user-defined styles can be applied to a named layer, there needs to be a mechanism by which a client can obtain feature/coverage-type information for a named layer. This is another example of bridging the gap between the WMS concepts of layers and styles and WFS/WCS concepts such as feature-type and coverage layer. To allow this, a WMS may optionally support the DescribeLayer request. DescribeLayer method has been thought to be a better approach than overloading the WMS capabilities document even more. For each named layer, the description should indicate if it is indeed based on feature data and if so it should indicate the WFS/WCS (by a URL prefix) and the feature/coverage types. Note that it is perfectly valid for a named layer not to be describable in this way.
1 parent 0bdebed commit 5c89fdf

10 files changed

+301
-17
lines changed
 

‎src/server/qgsserverprojectparser.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,48 @@ QString QgsServerProjectParser::serviceUrl() const
555555
return url;
556556
}
557557

558+
QString QgsServerProjectParser::wfsServiceUrl() const
559+
{
560+
QString url;
561+
562+
if ( !mXMLDoc )
563+
{
564+
return url;
565+
}
566+
567+
QDomElement propertiesElement = propertiesElem();
568+
if ( !propertiesElement.isNull() )
569+
{
570+
QDomElement wfsUrlElem = propertiesElement.firstChildElement( "WFSUrl" );
571+
if ( !wfsUrlElem.isNull() )
572+
{
573+
url = wfsUrlElem.text();
574+
}
575+
}
576+
return url;
577+
}
578+
579+
QString QgsServerProjectParser::wcsServiceUrl() const
580+
{
581+
QString url;
582+
583+
if ( !mXMLDoc )
584+
{
585+
return url;
586+
}
587+
588+
QDomElement propertiesElement = propertiesElem();
589+
if ( !propertiesElement.isNull() )
590+
{
591+
QDomElement wcsUrlElem = propertiesElement.firstChildElement( "WCSUrl" );
592+
if ( !wcsUrlElem.isNull() )
593+
{
594+
url = wcsUrlElem.text();
595+
}
596+
}
597+
return url;
598+
}
599+
558600
void QgsServerProjectParser::combineExtentAndCrsOfGroupChildren( QDomElement& groupElem, QDomDocument& doc, bool considerMapExtent ) const
559601
{
560602
QgsRectangle combinedBBox;
@@ -1126,6 +1168,32 @@ QStringList QgsServerProjectParser::wfsLayerNames() const
11261168
return layerNameList;
11271169
}
11281170

1171+
QStringList QgsServerProjectParser::wcsLayerNames() const
1172+
{
1173+
QStringList layerNameList;
1174+
1175+
QMap<QString, QgsMapLayer*> layerMap;
1176+
projectLayerMap( layerMap );
1177+
1178+
QgsMapLayer* currentLayer = 0;
1179+
QStringList wcsIdList = wcsLayers();
1180+
QStringList::const_iterator wcsIdIt = wcsIdList.constBegin();
1181+
for ( ; wcsIdIt != wcsIdList.constEnd(); ++wcsIdIt )
1182+
{
1183+
QMap<QString, QgsMapLayer*>::const_iterator layerMapIt = layerMap.find( *wcsIdIt );
1184+
if ( layerMapIt != layerMap.constEnd() )
1185+
{
1186+
currentLayer = layerMapIt.value();
1187+
if ( currentLayer )
1188+
{
1189+
layerNameList.append( mUseLayerIDs ? currentLayer->id() : currentLayer->name() );
1190+
}
1191+
}
1192+
}
1193+
1194+
return layerNameList;
1195+
}
1196+
11291197
QDomElement QgsServerProjectParser::firstComposerLegendElement() const
11301198
{
11311199
if ( !mXMLDoc )
@@ -1254,6 +1322,37 @@ QStringList QgsServerProjectParser::wfsLayers() const
12541322
return wfsList;
12551323
}
12561324

1325+
QStringList QgsServerProjectParser::wcsLayers() const
1326+
{
1327+
QStringList wcsList;
1328+
if ( !mXMLDoc )
1329+
{
1330+
return wcsList;
1331+
}
1332+
1333+
QDomElement qgisElem = mXMLDoc->documentElement();
1334+
if ( qgisElem.isNull() )
1335+
{
1336+
return wcsList;
1337+
}
1338+
QDomElement propertiesElem = qgisElem.firstChildElement( "properties" );
1339+
if ( propertiesElem.isNull() )
1340+
{
1341+
return wcsList;
1342+
}
1343+
QDomElement wcsLayersElem = propertiesElem.firstChildElement( "WCSLayers" );
1344+
if ( wcsLayersElem.isNull() )
1345+
{
1346+
return wcsList;
1347+
}
1348+
QDomNodeList valueList = wcsLayersElem.elementsByTagName( "value" );
1349+
for ( int i = 0; i < valueList.size(); ++i )
1350+
{
1351+
wcsList << valueList.at( i ).toElement().text();
1352+
}
1353+
return wcsList;
1354+
}
1355+
12571356
void QgsServerProjectParser::addJoinLayersForElement( const QDomElement& layerElem, bool useCache ) const
12581357
{
12591358
QDomElement vectorJoinsElem = layerElem.firstChildElement( "vectorjoins" );

‎src/server/qgsserverprojectparser.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class QgsServerProjectParser
9191
void layerFromLegendLayer( const QDomElement& legendLayerElem, QMap< int, QgsMapLayer*>& layers, bool useCache = true ) const;
9292

9393
QStringList wfsLayerNames() const;
94+
QStringList wcsLayerNames() const;
9495

9596
QDomElement firstComposerLegendElement() const;
9697

@@ -103,8 +104,11 @@ class QgsServerProjectParser
103104
QString layerName( const QDomElement& layerElem ) const;
104105

105106
QString serviceUrl() const;
107+
QString wfsServiceUrl() const;
108+
QString wcsServiceUrl() const;
106109

107110
QStringList wfsLayers() const;
111+
QStringList wcsLayers() const;
108112

109113
void addJoinLayersForElement( const QDomElement& layerElem, bool useCache = true ) const;
110114

‎src/server/qgssldconfigparser.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,15 @@ QDomDocument QgsSLDConfigParser::getStyles( QStringList& layerList ) const
482482
return styleDoc;
483483
}
484484

485+
QDomDocument QgsSLDConfigParser::describeLayer( QStringList& layerList, const QString& hrefString ) const
486+
{
487+
if ( mFallbackParser )
488+
{
489+
return mFallbackParser->describeLayer( layerList, hrefString );
490+
}
491+
return QDomDocument();
492+
}
493+
485494
QgsMapRenderer::OutputUnits QgsSLDConfigParser::outputUnits() const
486495
{
487496
return mOutputUnits;

‎src/server/qgssldconfigparser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ class QgsSLDConfigParser : public QgsWMSConfigParser
5151

5252
/**Returns the xml fragment of layers styles*/
5353
QDomDocument getStyles( QStringList& layerList ) const override;
54+
55+
/**Returns the xml fragment of layers styles description*/
56+
QDomDocument describeLayer( QStringList& layerList, const QString& hrefString ) const override;
5457

5558
/**Returns if output are MM or PIXEL*/
5659
QgsMapRenderer::OutputUnits outputUnits() const override;

‎src/server/qgswfsprojectparser.cpp

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,7 @@ QString QgsWFSProjectParser::serviceUrl() const
4343

4444
QString QgsWFSProjectParser::wfsServiceUrl() const
4545
{
46-
QString url;
47-
48-
if ( !mProjectParser->xmlDocument() )
49-
{
50-
return url;
51-
}
52-
53-
QDomElement propertiesElem = mProjectParser->propertiesElem();
54-
if ( !propertiesElem.isNull() )
55-
{
56-
QDomElement wfsUrlElem = propertiesElem.firstChildElement( "WFSUrl" );
57-
if ( !wfsUrlElem.isNull() )
58-
{
59-
url = wfsUrlElem.text();
60-
}
61-
}
62-
return url;
46+
return mProjectParser->wfsServiceUrl();
6347
}
6448

6549
void QgsWFSProjectParser::featureTypeList( QDomElement& parentElement, QDomDocument& doc ) const

‎src/server/qgswmsconfigparser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ class QgsWMSConfigParser
5050

5151
/**Returns the xml fragment of layers styles*/
5252
virtual QDomDocument getStyles( QStringList& layerList ) const = 0;
53+
54+
/**Returns the xml fragment of layers styles description*/
55+
virtual QDomDocument describeLayer( QStringList& layerList, const QString& hrefString ) const = 0;
5356

5457
/**Returns if output are MM or PIXEL*/
5558
virtual QgsMapRenderer::OutputUnits outputUnits() const = 0;

‎src/server/qgswmsprojectparser.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,6 +1674,108 @@ QDomDocument QgsWMSProjectParser::getStyles( QStringList& layerList ) const
16741674
return myDocument;
16751675
}
16761676

1677+
QDomDocument QgsWMSProjectParser::describeLayer( QStringList& layerList, const QString& hrefString ) const
1678+
{
1679+
QDomDocument myDocument = QDomDocument();
1680+
1681+
QDomNode header = myDocument.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" );
1682+
myDocument.appendChild( header );
1683+
1684+
// Create the root element
1685+
QDomElement root = myDocument.createElementNS( "http://www.opengis.net/sld", "DescribeLayerResponse" );
1686+
root.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/DescribeLayer.xsd" );
1687+
root.setAttribute( "xmlns:ows", "http://www.opengis.net/ows" );
1688+
root.setAttribute( "xmlns:se", "http://www.opengis.net/se" );
1689+
root.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
1690+
root.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
1691+
myDocument.appendChild( root );
1692+
1693+
// store the Version element
1694+
QDomElement versionNode = myDocument.createElement( "Version" );
1695+
versionNode.appendChild( myDocument.createTextNode( "1.1.0" ) );
1696+
root.appendChild( versionNode );
1697+
1698+
//Prepare url
1699+
QString wfsHrefString = mProjectParser->wfsServiceUrl();
1700+
if ( wfsHrefString.isEmpty() )
1701+
{
1702+
wfsHrefString = hrefString;
1703+
}
1704+
QString wcsHrefString = mProjectParser->wcsServiceUrl();
1705+
if ( wcsHrefString.isEmpty() )
1706+
{
1707+
wcsHrefString = hrefString;
1708+
}
1709+
1710+
//WFS layers
1711+
QStringList wfsLayers = wfsLayerNames();
1712+
//WCS layers
1713+
QStringList wcsLayers = mProjectParser->wcsLayerNames();
1714+
1715+
for ( int i = 0; i < layerList.size(); i++ )
1716+
{
1717+
QString layerName;
1718+
layerName = layerList.at( i );
1719+
// don't use a cache - we may be changing styles
1720+
QList<QgsMapLayer*> currentLayerList = mapLayerFromStyle( layerName, "", false );
1721+
if ( currentLayerList.size() < 1 )
1722+
{
1723+
throw QgsMapServiceException( "InvalidParameterValue", QString( "The layer '%1' is not found" ).arg( layerName ) );
1724+
}
1725+
for ( int j = 0; j < currentLayerList.size(); j++ )
1726+
{
1727+
QgsMapLayer* currentLayer = currentLayerList.at( j );
1728+
QString layerTypeName = mProjectParser->useLayerIDs() ? currentLayer->id() : currentLayer->name();
1729+
1730+
// Create the NamedLayer element
1731+
QDomElement layerNode = myDocument.createElement( "LayerDescription" );
1732+
root.appendChild( layerNode );
1733+
1734+
// store the owsType element
1735+
QDomElement typeNode = myDocument.createElement( "owsType" );
1736+
// store the se:OnlineResource element
1737+
QDomElement oResNode = myDocument.createElement( "se:OnlineResource" );
1738+
oResNode.setAttribute( "xlink:type", "simple" );
1739+
// store the TypeName element
1740+
QDomElement nameNode = myDocument.createElement( "TypeName" );
1741+
if ( currentLayer->type() == QgsMapLayer::VectorLayer )
1742+
{
1743+
typeNode.appendChild( myDocument.createTextNode( "wfs" ) );
1744+
1745+
if ( wfsLayers.indexOf( layerTypeName ) != -1 )
1746+
{
1747+
oResNode.setAttribute( "xlink:href", wfsHrefString );
1748+
}
1749+
1750+
// store the se:FeatureTypeName element
1751+
QDomElement typeNameNode = myDocument.createElement( "se:FeatureTypeName" );
1752+
typeNameNode.appendChild( myDocument.createTextNode( layerTypeName ) );
1753+
nameNode.appendChild( typeNameNode );
1754+
}
1755+
else if ( currentLayer->type() == QgsMapLayer::RasterLayer )
1756+
{
1757+
typeNode.appendChild( myDocument.createTextNode( "wcs" ) );
1758+
1759+
if ( wcsLayers.indexOf( layerTypeName ) != -1 )
1760+
{
1761+
oResNode.setAttribute( "xlink:href", wcsHrefString );
1762+
}
1763+
1764+
// store the se:CoverageTypeName element
1765+
QDomElement typeNameNode = myDocument.createElement( "se:CoverageTypeName" );
1766+
typeNameNode.appendChild( myDocument.createTextNode( layerTypeName ) );
1767+
nameNode.appendChild( typeNameNode );
1768+
}
1769+
layerNode.appendChild( typeNode );
1770+
layerNode.appendChild( oResNode );
1771+
layerNode.appendChild( nameNode );
1772+
1773+
}
1774+
}
1775+
1776+
return myDocument;
1777+
}
1778+
16771779
QgsMapRenderer::OutputUnits QgsWMSProjectParser::outputUnits() const
16781780
{
16791781
return QgsMapRenderer::Millimeters;

‎src/server/qgswmsprojectparser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ class QgsWMSProjectParser : public QgsWMSConfigParser
7979
/**Returns the xml fragment of layers styles*/
8080
QDomDocument getStyles( QStringList& layerList ) const override;
8181

82+
/**Returns the xml fragment of layers styles description*/
83+
QDomDocument describeLayer( QStringList& layerList, const QString& hrefString ) const override;
84+
8285
/**Returns if output are MM or PIXEL*/
8386
QgsMapRenderer::OutputUnits outputUnits() const override;
8487

0 commit comments

Comments
 (0)
Please sign in to comment.