Skip to content

Commit

Permalink
[QGIS-Server] FIX 10489 QGIS Server getcapabilites response is not WM…
Browse files Browse the repository at this point in the history
…S compliant

To be fully compliant with WMS 1.3.0 standard, I propose to add :
* SLD namespace for GetLegendGraphic element
* schemaExtension.xsd distributed with QGIS-Server for GetStyles and GetPrint
* GetSchemaExtension to retrieve schemaExtension.xsd like MapServer

The solution was inspired by
 http://demo.mapserver.org/cgi-bin/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities
And the standard description
Styled Layer Descriptor profile of the Web Map Service Implementation Specification
http://portal.opengeospatial.org/files/?artifact_id=22364
  • Loading branch information
rldhont committed Dec 4, 2014
1 parent 0fa40a6 commit c2b5da3
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 37 deletions.
1 change: 1 addition & 0 deletions src/server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ INSTALL(TARGETS
INSTALL(FILES
admin.sld
wms_metadata.xml
schemaExtension.xsd
DESTINATION ${QGIS_CGIBIN_DIR}
)

8 changes: 7 additions & 1 deletion src/server/qgshttprequesthandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,12 +268,18 @@ void QgsHttpRequestHandler::setGetCapabilitiesResponse( const QDomDocument& doc
setHttpResponse( &ba, "text/xml" );
}

void QgsHttpRequestHandler::setGetStyleResponse( const QDomDocument& doc )
void QgsHttpRequestHandler::setXmlResponse( const QDomDocument& doc )
{
QByteArray ba = doc.toByteArray();
setHttpResponse( &ba, "text/xml" );
}

void QgsHttpRequestHandler::setXmlResponse( const QDomDocument& doc, const QString& mimeType )
{
QByteArray ba = doc.toByteArray();
setHttpResponse( &ba, mimeType );
}

void QgsHttpRequestHandler::setGetFeatureInfoResponse( const QDomDocument& infoDoc, const QString& infoFormat )
{
QByteArray ba;
Expand Down
3 changes: 2 additions & 1 deletion src/server/qgshttprequesthandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ class QgsHttpRequestHandler: public QgsRequestHandler
virtual void setGetCapabilitiesResponse( const QDomDocument& doc );
virtual void setGetFeatureInfoResponse( const QDomDocument& infoDoc, const QString& infoFormat );
virtual void setServiceException( QgsMapServiceException ex );
virtual void setGetStyleResponse( const QDomDocument& doc );
virtual void setXmlResponse( const QDomDocument& doc );
virtual void setXmlResponse( const QDomDocument& doc, const QString& mimeType );
virtual void setGetPrintResponse( QByteArray* ba );
virtual bool startGetFeatureResponse( QByteArray* ba, const QString& infoFormat );
virtual void setGetFeatureResponse( QByteArray* ba );
Expand Down
3 changes: 2 additions & 1 deletion src/server/qgsrequesthandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ class QgsRequestHandler
virtual void setGetCapabilitiesResponse( const QDomDocument& doc ) = 0;
virtual void setGetFeatureInfoResponse( const QDomDocument& infoDoc, const QString& infoFormat ) = 0;
virtual void setServiceException( QgsMapServiceException ex ) = 0;
virtual void setGetStyleResponse( const QDomDocument& doc ) = 0;
virtual void setXmlResponse( const QDomDocument& doc ) = 0;
virtual void setXmlResponse( const QDomDocument& doc, const QString& mimeType ) = 0;
virtual void setGetPrintResponse( QByteArray* b ) = 0;
virtual bool startGetFeatureResponse( QByteArray* ba, const QString& infoFormat ) = 0;
virtual void setGetFeatureResponse( QByteArray* ba ) = 0;
Expand Down
8 changes: 7 additions & 1 deletion src/server/qgssoaprequesthandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ void QgsSOAPRequestHandler::setGetFeatureInfoResponse( const QDomDocument& infoD
setHttpResponse( &ba, "text/xml" );
}

void QgsSOAPRequestHandler::setGetStyleResponse( const QDomDocument& infoDoc )
void QgsSOAPRequestHandler::setXmlResponse( const QDomDocument& infoDoc )
{
QDomDocument featureInfoResponseDoc;

Expand All @@ -415,6 +415,12 @@ void QgsSOAPRequestHandler::setGetStyleResponse( const QDomDocument& infoDoc )
setHttpResponse( &ba, "text/xml" );
}

void QgsSOAPRequestHandler::setXmlResponse( const QDomDocument& infoDoc, const QString& mimeType )
{
Q_UNUSED( mimeType );
setXmlResponse( infoDoc );
}

void QgsSOAPRequestHandler::setGetPrintResponse( QByteArray* ba ) const
{
Q_UNUSED( ba );
Expand Down
3 changes: 2 additions & 1 deletion src/server/qgssoaprequesthandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ class QgsSOAPRequestHandler: public QgsHttpRequestHandler
void setGetCapabilitiesResponse( const QDomDocument& doc );
void setGetFeatureInfoResponse( const QDomDocument& infoDoc, const QString& infoFormat );
void setServiceException( const QgsMapServiceException& ex );
void setGetStyleResponse( const QDomDocument& doc );
void setXmlResponse( const QDomDocument& doc );
void setXmlResponse( const QDomDocument& doc, const QString& mimeType );
void setGetPrintResponse( QByteArray* ba ) const;
private:
/**Parses the xml of a getMap request and fills the parameters into the map. Returns 0 in case of success*/
Expand Down
115 changes: 83 additions & 32 deletions src/server/qgswmsserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
#include "qgslogger.h"
#include "qgsmessagelog.h"
#include "qgsmapserviceexception.h"
#include "qgssldconfigparser.h"
#include "qgssymbolv2.h"
Expand Down Expand Up @@ -199,7 +200,20 @@ void QgsWMSServer::executeRequest()
try
{
QDomDocument doc = getContext();
mRequestHandler->setGetStyleResponse( doc );
mRequestHandler->setXmlResponse( doc );
}
catch ( QgsMapServiceException& ex )
{
mRequestHandler->setServiceException( ex );
}
}
//GetSchemaExtension
else if ( request.compare( "GetSchemaExtension", Qt::CaseInsensitive ) == 0 )
{
try
{
QDomDocument doc = getSchemaExtension();
mRequestHandler->setXmlResponse( doc );
}
catch ( QgsMapServiceException& ex )
{
Expand All @@ -212,7 +226,7 @@ void QgsWMSServer::executeRequest()
try
{
QDomDocument doc = getStyle();
mRequestHandler->setGetStyleResponse( doc );
mRequestHandler->setXmlResponse( doc );
}
catch ( QgsMapServiceException& ex )
{
Expand All @@ -222,23 +236,17 @@ void QgsWMSServer::executeRequest()
//GetStyles
else if ( request.compare( "GetStyles", Qt::CaseInsensitive ) == 0 )
{
// GetStyles is only defined for WMS1.1.1/SLD1.0
if ( version != "1.1.1" )
{
mRequestHandler->setServiceException( QgsMapServiceException( "OperationNotSupported", "GetStyles method is only available in WMS version 1.1.1" ) );
}
else
{
try
{
QDomDocument doc = getStyles();
mRequestHandler->setGetStyleResponse( doc );
}
catch ( QgsMapServiceException& ex )
{
mRequestHandler->setServiceException( ex );
}
}
// GetStyles is defined for WMS1.1.1/SLD1.0
// and in qgis-server WMS1.3.0 extension
try
{
QDomDocument doc = getStyles();
mRequestHandler->setXmlResponse( doc );
}
catch ( QgsMapServiceException& ex )
{
mRequestHandler->setServiceException( ex );
}
}
//GetLegendGraphic
else if ( request.compare( "GetLegendGraphic", Qt::CaseInsensitive ) == 0 ||
Expand Down Expand Up @@ -313,6 +321,13 @@ QDomDocument QgsWMSServer::getCapabilities( QString version, bool fullProjectInf
QDomDocument doc;
QDomElement wmsCapabilitiesElement;

//Prepare url
QString hrefString = mConfigParser->serviceUrl();
if ( hrefString.isEmpty() )
{
hrefString = serviceUrl();
}

if ( version == "1.1.1" )
{
doc = QDomDocument( "WMT_MS_Capabilities SYSTEM 'http://schemas.opengis.net/wms/1.1.1/WMS_MS_Capabilities.dtd'" ); //WMS 1.1.1 needs DOCTYPE "SYSTEM http://schemas.opengis.net/wms/1.1.1/WMS_MS_Capabilities.dtd"
Expand All @@ -324,8 +339,16 @@ QDomDocument QgsWMSServer::getCapabilities( QString version, bool fullProjectInf
addXMLDeclaration( doc );
wmsCapabilitiesElement = doc.createElement( "WMS_Capabilities"/*wms:WMS_Capabilities*/ );
wmsCapabilitiesElement.setAttribute( "xmlns", "http://www.opengis.net/wms" );
wmsCapabilitiesElement.setAttribute( "xmlns:sld", "http://www.opengis.net/sld" );
wmsCapabilitiesElement.setAttribute( "xmlns:qgs", "http://www.qgis.org/wms" );
wmsCapabilitiesElement.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
wmsCapabilitiesElement.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/wms http://qgis.org/wms_1_3_0.xsd" );
QString schemaLocation = "http://www.opengis.net/wms";
schemaLocation += " http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd";
schemaLocation += " http://www.opengis.net/sld";
schemaLocation += " http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd";
schemaLocation += " http://www.qgis.org/wms";
schemaLocation += " "+ hrefString +"SERVICE=WMS&REQUEST=GetSchemaExtension";
wmsCapabilitiesElement.setAttribute( "xsi:schemaLocation", schemaLocation );
}
wmsCapabilitiesElement.setAttribute( "version", version );
doc.appendChild( wmsCapabilitiesElement );
Expand Down Expand Up @@ -355,14 +378,6 @@ QDomDocument QgsWMSServer::getCapabilities( QString version, bool fullProjectInf
elem.appendChild( dcpTypeElement );
requestElement.appendChild( elem );

//Prepare url
QString hrefString = mConfigParser->serviceUrl();
if ( hrefString.isEmpty() )
{
hrefString = serviceUrl();
}


// SOAP platform
//only give this information if it is not a WMS request to be in sync with the WMS capabilities schema
QMap<QString, QString>::const_iterator service_it = mParameters.find( "SERVICE" );
Expand Down Expand Up @@ -411,19 +426,19 @@ QDomDocument QgsWMSServer::getCapabilities( QString version, bool fullProjectInf
requestElement.appendChild( elem );

//wms:GetLegendGraphic
elem = doc.createElement( "GetLegendGraphic"/*wms:GetLegendGraphic*/ );
elem = doc.createElement( ( version == "1.1.1" ? "GetLegendGraphic" : "sld:GetLegendGraphic" )/*wms:GetLegendGraphic*/ );
appendFormats( doc, elem, QStringList() << "image/jpeg" << "image/png" );
elem.appendChild( dcpTypeElement.cloneNode().toElement() ); // this is the same as for 'GetCapabilities'
requestElement.appendChild( elem );

//wms:GetStyles
elem = doc.createElement( "GetStyles"/*wms:GetStyles*/ );
elem = doc.createElement( ( version == "1.1.1" ? "GetStyles" : "qgs:GetStyles" )/*wms:GetStyles*/ );
appendFormats( doc, elem, QStringList() << "text/xml" );
elem.appendChild( dcpTypeElement.cloneNode().toElement() ); //this is the same as for 'GetCapabilities'
requestElement.appendChild( elem );

//wms:GetPrint
elem = doc.createElement( "GetPrint"/*wms:GetPrint*/ );
elem = doc.createElement( ( version == "1.1.1" ? "GetPrint" : "qgs:GetPrint" ) /*wms:GetPrint*/ );
appendFormats( doc, elem, QStringList() << "svg" << "png" << "pdf" );
elem.appendChild( dcpTypeElement.cloneNode().toElement() ); //this is the same as for 'GetCapabilities'
requestElement.appendChild( elem );
Expand Down Expand Up @@ -956,6 +971,42 @@ void QgsWMSServer::legendParameters( double& boxSpace, double& layerSpace, doubl
}
}

QDomDocument QgsWMSServer::getSchemaExtension()
{
QDomDocument xsdDoc;

QFileInfo xsdFileInfo( "schemaExtension.xsd" );
if ( !xsdFileInfo.exists() )
{
QgsMessageLog::logMessage( "Error, xsd file 'schemaExtension.xsd' does not exist", "Server", QgsMessageLog::CRITICAL );
return xsdDoc;
}

QString xsdFilePath = xsdFileInfo.absoluteFilePath();
QFile xsdFile( xsdFilePath );
if ( !xsdFile.exists() )
{
QgsMessageLog::logMessage( "Error, xsd file 'schemaExtension.xsd' does not exist", "Server", QgsMessageLog::CRITICAL );
return xsdDoc;
}

if ( !xsdFile.open( QIODevice::ReadOnly ) )
{
QgsMessageLog::logMessage( "Error, cannot open xsd file 'schemaExtension.xsd' does not exist", "Server", QgsMessageLog::CRITICAL );
return xsdDoc;
}

QString errorMsg;
int line, column;
if ( !xsdDoc.setContent( &xsdFile, true, &errorMsg, &line, &column ) )
{
QgsMessageLog::logMessage( "Error parsing file 'schemaExtension.xsd" +
QString( "': parse error %1 at row %2, column %3" ).arg( errorMsg ).arg( line ).arg( column ), "Server", QgsMessageLog::CRITICAL );
return xsdDoc;
}
return xsdDoc;
}

QDomDocument QgsWMSServer::getStyle()
{
QDomDocument doc;
Expand All @@ -975,7 +1026,7 @@ QDomDocument QgsWMSServer::getStyle()
return mConfigParser->getStyle( styleName, layerName );
}

// GetStyles is only defined for WMS1.1.1/SLD1.0
// GetStyles is defined for WMS1.1.1/SLD1.0 and in WMS 1.3.0 SLD Extension
QDomDocument QgsWMSServer::getStyles()
{
QDomDocument doc;
Expand Down
3 changes: 3 additions & 0 deletions src/server/qgswmsserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ class QgsWMSServer: public QgsOWSServer

/**Sets configuration parser for administration settings. Does not take ownership*/
void setAdminConfigParser( QgsWMSConfigParser* parser ) { mConfigParser = parser; }

/**Returns the schemaExtension for WMS 1.3.0 capabilities*/
QDomDocument getSchemaExtension();

private:
/**Don't use the default constructor*/
Expand Down
6 changes: 6 additions & 0 deletions src/server/schemaExtension.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:wms="http://www.opengis.net/wms" xmlns:qgs="http://www.qgis.org/wms" targetNamespace="http://www.qgis.org/wms" elementFormDefault="qualified" version="1.0.0">
<import namespace="http://www.opengis.net/wms" schemaLocation="http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd"/>
<element name="GetPrint" type="wms:OperationType" substitutionGroup="wms:_ExtendedOperation" />
<element name="GetStyles" type="wms:OperationType" substitutionGroup="wms:_ExtendedOperation" />
</schema>

0 comments on commit c2b5da3

Please sign in to comment.