[mapguide-commits] r5441 - in trunk/MgDev:
Server/src/Services/Feature Server/src/Wfs Web/src/HttpHandler
svn_mapguide at osgeo.org
svn_mapguide at osgeo.org
Mon Dec 6 05:38:44 EST 2010
Author: liuar
Date: 2010-12-06 02:38:44 -0800 (Mon, 06 Dec 2010)
New Revision: 5441
Modified:
trunk/MgDev/Server/src/Services/Feature/FilterUtil.cpp
trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.cpp
trunk/MgDev/Server/src/Wfs/1.1.0.xml.awd
trunk/MgDev/Web/src/HttpHandler/HttpWfsDescribeFeatureType.cpp
trunk/MgDev/Web/src/HttpHandler/HttpWfsGetFeature.cpp
trunk/MgDev/Web/src/HttpHandler/WfsFeatureDefinitions.cpp
trunk/MgDev/Web/src/HttpHandler/WfsFeatureDefinitions.h
Log:
Ticket #1421: OGC WFS 1.1.0 Support
1. Test wfs:wfs-1.1.0-Basic-GetFeature-tc30.2
XPath 1.0 shall be used to address parts of an XML representation using ogc:PropertyName.
Support for the AbbreviatedRelativeLocationPath construct is required.
the position() function may appear in a predicate to refer to a child node by position relative to the context node.
For OGC WFS Certification, we just ignore the position() function.
2. Per OGC certification, if all feature types in DescribeFeatureType requests are in the same namespace, the response document should not using the xs:import format to include sub-schemas.
Modified: trunk/MgDev/Server/src/Services/Feature/FilterUtil.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/FilterUtil.cpp 2010-12-06 02:35:35 UTC (rev 5440)
+++ trunk/MgDev/Server/src/Services/Feature/FilterUtil.cpp 2010-12-06 10:38:44 UTC (rev 5441)
@@ -162,6 +162,17 @@
if(pos != STRING::npos)
{
m_propName = MgUtil::ReplaceString(m_propName,L":",L"_");
+
+ // For OGC WFS Certification, we just ignore the position() function.
+ // TODO: Test wfs:wfs-1.1.0-Basic-GetFeature-tc30.2
+ // XPath 1.0 shall be used to address parts of an XML representation using ogc:PropertyName.
+ // Support for the AbbreviatedRelativeLocationPath construct is required.
+ // the position() function may appear in a predicate to refer to a child node by position relative to the context node.
+ pos = m_propName.find(L"[");
+ if(pos != STRING::npos)
+ {
+ m_propName = m_propName.substr(0,pos);
+ }
}
// For other elemnts, there will be a namespace prefix like "sf:".
// The prefix should be removed before passing to FDO.
Modified: trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.cpp 2010-12-06 02:35:35 UTC (rev 5440)
+++ trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.cpp 2010-12-06 10:38:44 UTC (rev 5441)
@@ -1262,15 +1262,32 @@
else
{
STRING featureSourceHash;
+ bool bSchemaFound = false;
MgUtil::Int32ToString(StringHasher(featureSourceId->ToString().c_str()),featureSourceHash);
featureSourceHash = MG_FEATURE_SOURCE_HASH_PREFIX + featureSourceHash + schemaHash;
Ptr<MgFeatureSchema> schemaToAdd = new MgFeatureSchema(featureSourceHash, schemaFound->GetDescription());
- Ptr<MgClassDefinitionCollection> classes = schemaToAdd->GetClasses();
+
+ for(int i =0; i<dfsc->GetCount(); i++)
+ {
+ Ptr<MgFeatureSchema> fSchema = dfsc->GetItem(i);
+ if(fSchema->GetName() == schemaToAdd->GetName())
+ {
+ bSchemaFound = true;
+ Ptr<MgClassDefinitionCollection> classes = fSchema->GetClasses();
+ classes->Add(classFound);
+ break;
+ }
+ }
- classes->Add(classFound);
- dfsc->Add(schemaToAdd);
+ if(!bSchemaFound)
+ {
+ Ptr<MgClassDefinitionCollection> classes = schemaToAdd->GetClasses();
+
+ classes->Add(classFound);
+ dfsc->Add(schemaToAdd);
+ }
}
}
@@ -1906,7 +1923,7 @@
}
else if(L"text/xml; subtype=gml/3.1.1" == outputFormat)
{
- flags->SetSchemaLocation(L"http://www.opengis.net/gml", L"http://schemas.opengis.net/gml/3.1.1/feature.xsd");
+ flags->SetSchemaLocation(L"http://www.opengis.net/gml", L"http://schemas.opengis.net/gml/3.1.1/base/feature.xsd");
flags->SetGmlVersion(FdoGmlVersion_311);
}
else
@@ -1946,7 +1963,7 @@
}
else if(L"1.1.0" == wfsVersion)
{
- flags->SetSchemaLocation(L"http://www.opengis.net/wfs", L"http://schemas.opengis.net/wfs/1.1.0/WFS-basic.xsd");
+ flags->SetSchemaLocation(L"http://www.opengis.net/wfs", L"http://schemas.opengis.net/wfs/1.1.0/wfs.xsd");
}
else
{
Modified: trunk/MgDev/Server/src/Wfs/1.1.0.xml.awd
===================================================================
--- trunk/MgDev/Server/src/Wfs/1.1.0.xml.awd 2010-12-06 02:35:35 UTC (rev 5440)
+++ trunk/MgDev/Server/src/Wfs/1.1.0.xml.awd 2010-12-06 10:38:44 UTC (rev 5441)
@@ -71,7 +71,7 @@
<!-- TODO: these will need to come from the full Feature metadata store -->
<!-- for now, these are operating defaults. -->
<Define item="Feature.namespace">http://fdo.osgeo.org/schemas</Define>
- <Define item="Feature.Abstract">Abstract for this layer</Define>
+ <Define item="Feature.Abstract"></Define>
<Define item="Feature.DefaultSRS">urn:ogc:def:crs:EPSG::4326</Define>
<!--Define item="Feature.OtherSRS"></Define-->
<Define item="Feature.Bounds.north">90</Define>
@@ -129,13 +129,13 @@
<!-- SERVICE IDENTIFICATION SECTION -->
<!-- ================================================================== -->
<ows:ServiceIdentification>
- <ows:Title>&Service.Title;</ows:Title>
- <ows:Abstract>&Service.Abstract;</ows:Abstract>
+ <ows:Title>&Service.Title;</ows:Title>
+ <ows:Abstract>&Service.Abstract;</ows:Abstract>
<ows:Keywords>
<?Enum list="&Service.Keywords;" using="&Keywords.xml;"?>
</ows:Keywords>
- <ows:ServiceType>WFS</ows:ServiceType>
- <?Enum list="&SupportedVersions;" using="&ServiceTypeVersion.xml;" item="Version"?>
+ <ows:ServiceType>WFS</ows:ServiceType>
+ <?Enum list="&SupportedVersions;" using="&ServiceTypeVersion.xml;" item="Version"?>
<ows:Fees>&Service.Fees;</ows:Fees>
<ows:AccessConstraints>&Service.AccessConstraints;</ows:AccessConstraints>
</ows:ServiceIdentification>
Modified: trunk/MgDev/Web/src/HttpHandler/HttpWfsDescribeFeatureType.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpWfsDescribeFeatureType.cpp 2010-12-06 02:35:35 UTC (rev 5440)
+++ trunk/MgDev/Web/src/HttpHandler/HttpWfsDescribeFeatureType.cpp 2010-12-06 10:38:44 UTC (rev 5441)
@@ -84,16 +84,20 @@
featureTypeList = MgStringCollection::ParseCollection(sFeatureTypes, L",");
}
- // Determine required output format
- CPSZ pszOutputFormat = Wfs.RequestParameter(MgHttpResourceStrings::reqWfsOutputFormat.c_str());
- STRING sOutputFormat = pszOutputFormat? pszOutputFormat : _("");
-
Ptr<MgResourceService> pResourceService = (MgResourceService*)(CreateService(MgServiceType::ResourceService));
Ptr<MgFeatureService> pFeatureService = (MgFeatureService*)(CreateService(MgServiceType::FeatureService));
// Retrieve feature definitions
- MgWfsFeatureDefinitions oFeatureTypes(pResourceService,pFeatureService,featureTypeList);
- Wfs.SetFeatureDefinitions(&oFeatureTypes);
+ auto_ptr<MgWfsFeatureDefinitions> pFeatureTypes;
+ if(NULL == featureTypeList)
+ {
+ pFeatureTypes.reset(new MgWfsFeatureDefinitions(pResourceService,pFeatureService));
+ }
+ else
+ {
+ pFeatureTypes.reset(new MgWfsFeatureDefinitions(pResourceService,pFeatureService,featureTypeList));
+ }
+ Wfs.SetFeatureDefinitions(pFeatureTypes.get());
// In order to validate request we have to invoke the ProcessRequest
if(!Wfs.ProcessRequest(this))
@@ -106,44 +110,84 @@
return;
}
- // This is a comma-sep a list. If empty, == all.
- // If it's just one feature (no comma sep found) let's do
- // a single response, else let's recursively enumerate the features.
- if(sFeatureTypes.length() > 0 && sFeatureTypes.find(_(",")) == STRING::npos) {
- // TODO: assumes that this is GML type.
- //STRING sOutputFormat = origReqParams->GetParameterValue(_("OUTPUTFORMAT"));
+ // Determine required output format
+ // This part must behind the Wfs.ProcessRequest, where parameters have been validated.
+ CPSZ pszOutputFormat = Wfs.RequestParameter(MgHttpResourceStrings::reqWfsOutputFormat.c_str());
+ STRING sOutputFormat = pszOutputFormat? pszOutputFormat : _("");
+ if(sOutputFormat.empty())
+ {
+ sOutputFormat = Wfs.GetDefaultDescribeFeatureTypeOutputFormat(STRING(Wfs.RequestParameter(MgHttpResourceStrings::reqWfsVersion.c_str())));
+ }
- STRING::size_type iPos = sFeatureTypes.find(_(":")); //NOXLATE
- if(iPos != STRING::npos) {
- STRING sPrefix = sFeatureTypes.substr(0,iPos);
- STRING sClass = sFeatureTypes.substr(iPos+1);
- STRING sSchemaHash;
- STRING sResource; // TODO: look for this in arg, since POST may put it there to save us trouble.
+ if(pFeatureTypes->InSameNamespace())
+ {
+ STRING sPrefix = L"";
+ STRING sUrl = L"";
+ STRING sResource = L""; // TODO: look for this in arg, since POST may put it there to save us trouble.
+ STRING sSchemaHash = L"";
+ Ptr<MgResourceIdentifier> idResource;
+ Ptr<MgStringCollection> pFeatureClasses = new MgStringCollection();
- if(oFeatureTypes.PrefixToFeatureSource(sPrefix, sResource, sSchemaHash)) {
- MgResourceIdentifier idResource(sResource);
- Ptr<MgStringCollection> pFeatureClasses = new MgStringCollection();
- pFeatureClasses->Add(((sSchemaHash.size()==0) ? sClass : sSchemaHash + _(":") + sClass)); //NOXLATE
+ while(pFeatureTypes->ReadNext())
+ {
+ STRING sClassFullName = pFeatureTypes->GetClassFullName();
+
+ if(!sFeatureTypes.empty() && STRING::npos == sFeatureTypes.find(sClassFullName))
+ {
+ continue;
+ }
- Ptr<MgByteReader> response = pFeatureService->DescribeWfsFeatureType(&idResource, pFeatureClasses, sPrefix, oFeatureTypes.GetNamespaceUrl());
+ STRING::size_type iPos = sClassFullName.find(_(":")); //NOXLATE
+ if(iPos != STRING::npos)
+ {
+ if(sPrefix.empty())
+ {
+ sPrefix = sClassFullName.substr(0,iPos);
+ }
- // Set the result
- hResult->SetResultObject(response, response->GetMimeType());
+ STRING sClass = sClassFullName.substr(iPos+1);
+
+ sUrl = pFeatureTypes->GetNamespaceUrl();
+
+ if(NULL == idResource)
+ {
+ if(pFeatureTypes->PrefixToFeatureSource(sPrefix, sResource, sSchemaHash)) {
+ idResource = new MgResourceIdentifier(sResource);
+ }
+ else
+ {
+ // Badly formed feature type? Throw an exception.
+ GenerateTypeNameException(hResult,sFeatureTypes);
+ return;
+ }
+ }
+
+ pFeatureClasses->Add(((sSchemaHash.size()==0) ? sClass : sSchemaHash + _(":") + sClass)); //NOXLATE
}
- else
+ else {
// Badly formed feature type? Throw an exception.
GenerateTypeNameException(hResult,sFeatureTypes);
+ return;
+ }
}
- else {
+
+ if(pFeatureClasses->GetCount() == 0)
+ {
// Badly formed feature type? Throw an exception.
GenerateTypeNameException(hResult,sFeatureTypes);
+ return;
}
+
+ Ptr<MgByteReader> response = pFeatureService->DescribeWfsFeatureType(idResource, pFeatureClasses, sPrefix, sUrl);
+
+ // Set the result
+ hResult->SetResultObject(response, sOutputFormat);
}
else {
// There's more than one feature, so we need to enumerate
// them and have each get imported.
//
- if(!oFeatureTypes.SubsetFeatureList(sFeatureTypes.c_str()))
+ if(!pFeatureTypes->SubsetFeatureList(sFeatureTypes.c_str()))
GenerateTypeNameException(hResult,sFeatureTypes);
else {
Modified: trunk/MgDev/Web/src/HttpHandler/HttpWfsGetFeature.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpWfsGetFeature.cpp 2010-12-06 02:35:35 UTC (rev 5440)
+++ trunk/MgDev/Web/src/HttpHandler/HttpWfsGetFeature.cpp 2010-12-06 10:38:44 UTC (rev 5441)
@@ -195,6 +195,9 @@
for(int i = 0; i < featureTypeList->GetCount(); i++)
{
+ // Enum to the proper feature type
+ oFeatureTypes.ReadNext();
+
// Check to see if we've already retrieved the maximum
// number of features
if(maxFeatures > 0 && numFeaturesRetrieved >= maxFeatures)
Modified: trunk/MgDev/Web/src/HttpHandler/WfsFeatureDefinitions.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/WfsFeatureDefinitions.cpp 2010-12-06 02:35:35 UTC (rev 5440)
+++ trunk/MgDev/Web/src/HttpHandler/WfsFeatureDefinitions.cpp 2010-12-06 10:38:44 UTC (rev 5441)
@@ -134,6 +134,70 @@
return m_bOk;
}
+
+
+bool MgWfsFeatureDefinitions::ReadNext()
+{
+ // Let's only do work if we enter with
+ // any expectation of success.
+ m_bOk = this->Next();
+
+ // Clear previous feature type's members
+ m_sCurrentPrefix = _("");
+ m_sCurrentClassName = _("");
+ m_sCurrentUrl = _("");
+
+ if(m_bOk)
+ {
+ MgXmlSynchronizeOnElement oFeatureClass(*m_pXmlInput,_("FeatureClass"));
+ if(oFeatureClass.AtBegin()) {
+ // Spin through all of the things in our feature class...
+ while(!oFeatureClass.AtEnd()) {
+ // ... which should just be a sequence of <Define> elements
+ MgXmlSynchronizeOnElement oDefine(*m_pXmlInput,_("Define"));
+ MgXmlBeginElement* pBegin;
+ if(oDefine.AtBegin(&pBegin)) {
+ STRING sName;
+ pBegin->GetAttribute(_("item"),sName);
+
+ // Done with the begin element; advance into its contents.
+ m_pXmlInput->Next(); pBegin = NULL;
+
+ // Spin through and slurp out the entire contents of the
+ // definition.
+ STRING sValue;
+ while(!oDefine.AtEnd()) {
+ sValue += m_pXmlInput->Current().Contents();
+ m_pXmlInput->Next();
+ }
+
+ // Whatever we find, let's add it to that great dictionary out there.
+ if(L"Feature.Prefix" == sName)
+ {
+ m_sCurrentPrefix = sValue;
+ }
+ else if(L"Feature.FullName" == sName)
+ {
+ m_sCurrentClassName = sValue;
+ }
+ else if(L"Feature.Url" == sName)
+ {
+ m_sCurrentUrl = sValue;
+ }
+ }
+ }
+ }
+
+ }
+
+ return m_bOk;
+}
+void MgWfsFeatureDefinitions::Reset()
+{
+ m_pXmlInput->Reset();
+ m_bOk = m_pXmlInput->Next();
+}
+
void MgWfsFeatureDefinitions::GenerateDefinitions(MgUtilDictionary& Dictionary)
{
STRING sClass;
@@ -165,6 +229,32 @@
Dictionary.AddDefinition(sName,sValue);
}
}
+
+ //// OGC Certification
+ //// Feature type sf:EntitéGénérique causes schema invalid
+ //// Using Url encoding sf%3aEntit%c3%a9G%c3%a9n%c3%a9rique instead
+ //if(NULL != Dictionary[L"Feature.FullName"])
+ //{
+ // string strFullName = MgUtil::WideCharToMultiByte(Dictionary[L"Feature.FullName"]);
+ // string strUrlEncodedName;
+ // MgUtil::EscapeUrl(strFullName.c_str(), strUrlEncodedName);
+ // STRING sValue = MgUtil::MultiByteToWideChar(strUrlEncodedName);
+ // Dictionary.AddDefinition(L"Feature.UrlEncodedName",sValue);
+ //}
+ //
+ //// OGC Certification
+ //// DescribeFeatureType response with multiple schemas should include schema attribute in import elements
+ //// <import namespace="http://fdo.osgeo.org/schemas/feature/ns183299621" schemaLocation="http://xxx.xxx.xxx.xxx/mapguide/mapagent/mapagent.fcgi?request=DescribeFeatureType&service=WFS&version=1.1.0&typeName=ns183299621%3aHydrographicPolygons">
+ //if(NULL != Dictionary[L"Feature.Url"])
+ //{
+ // Dictionary.AddDefinition(L"Feature.namespace",Dictionary[L"Feature.Url"]);
+ //}
+ //else
+ //{
+ // STRING value = L"http://fdo.osgeo.org/schemas/feature/";
+ // value += Dictionary[L"Feature.Prefix"];
+ // Dictionary.AddDefinition(L"Feature.namespace",value);
+ //}
}
}
@@ -463,6 +553,19 @@
sHashSchemaName = _("sn")+ sHashSchemaName;
}
+ // For OGC certification
+ // Hash prefix is not accepted by OGC certification
+ if(sPrefix.find(_("ns")) != 0 && pSchemas->GetCount() == 1)
+ {
+ MgUtil::Int32ToString(StringHasher(sSchemaName.c_str()),sHashSchemaName);
+ sHashSchemaName = _("sn")+ sHashSchemaName;
+ m_sPrefixSchemaMapping = sPrefix + _(":") + sHashSchemaName;
+
+ // Let's clear the sHashSchemaName then the newPrefix will not be changed.
+ sHashSchemaName = _("");
+ }
+ // End of OGC certification
+
STRING newPrefix = sPrefix + sHashSchemaName;
// TODO: STALE?
// And what OGC wants to call a Name is really the internal
@@ -604,6 +707,19 @@
if(iPosNs != STRING::npos)
sSchemaName = sPrefix.substr(iPosNs); // get the value in case we have it
}
+
+ // For OGC certification
+ // convert prefix to Hash schema.
+ if(sPrefix.find(_("ns")) != 0 && sSchemaName.empty() && !m_sPrefixSchemaMapping.empty())
+ {
+ STRING::size_type iPosColon = m_sPrefixSchemaMapping.find(_(":")); //NOXLATE
+ if(iPosColon != STRING::npos)
+ {
+ sSchemaName = m_sPrefixSchemaMapping.substr(iPosColon+1);
+ }
+ }
+ // End of OGC certification
+
STRING::size_type iPos = m_sSourcesAndClasses.find(sKey);
if(iPos == STRING::npos && iPosNs != STRING::npos)
{
@@ -649,19 +765,53 @@
STRING MgWfsFeatureDefinitions::GetNamespaceUrl()
{
- STRING sKey = _("<Define item='Feature.Url'>");
- STRING::size_type iPos = m_sSourcesAndClasses.find(sKey);
- STRING url = _("");
+ return m_sCurrentUrl;
+}
- if(iPos != STRING::npos)
+STRING MgWfsFeatureDefinitions::GetNamespacePrefix()
+{
+ return m_sCurrentPrefix;
+}
+
+STRING MgWfsFeatureDefinitions::GetClassFullName()
+{
+ return m_sCurrentClassName;
+}
+
+bool MgWfsFeatureDefinitions::InSameNamespace()
+{
+ this->Reset();
+
+ bool bSameNamespace = true;
+ STRING sNamespace = L"";
+
+ while(this->ReadNext())
{
- iPos += sKey.length(); // advance us past the key
- STRING::size_type iEnd = m_sSourcesAndClasses.find(_("</Define>"),iPos); // NOXLATE
- url = m_sSourcesAndClasses.substr(iPos,iEnd-iPos);
+ if(NULL != m_pFeatureTypes && !m_pFeatureTypes->Contains(this->GetClassFullName()))
+ continue;
+
+ // If the FeatureDefinition has namespaceURL defined, we can use the namespaceURL directly.
+ // Otherwise, the namespace would be "http://fdo.osgeo.org/schemas/feature/" + Prefix
+ STRING sCurrentNamespace = this->GetNamespaceUrl();
+ if(sCurrentNamespace.empty())
+ {
+ sCurrentNamespace = L"http://fdo.osgeo.org/schemas/feature/" + this->GetNamespacePrefix();
+ }
+
+ // Set current namespace to sNamespace as a criterion if sNamespace is empty.
+ // then Compare the current namespaces with the criterion
+ if(sNamespace.empty())
+ {
+ sNamespace = sCurrentNamespace;
+ }
+ else if(sNamespace != sCurrentNamespace)
+ {
+ bSameNamespace = false;
+ break;
+ }
}
- return url;
+ this->Reset();
+ return bSameNamespace;
}
-
-
Modified: trunk/MgDev/Web/src/HttpHandler/WfsFeatureDefinitions.h
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/WfsFeatureDefinitions.h 2010-12-06 02:35:35 UTC (rev 5440)
+++ trunk/MgDev/Web/src/HttpHandler/WfsFeatureDefinitions.h 2010-12-06 10:38:44 UTC (rev 5441)
@@ -28,8 +28,16 @@
MgWfsFeatureDefinitions(MgResourceService* pResourceService,MgFeatureService* pFeatureService,MgStringCollection* pFeatureTypes);
~MgWfsFeatureDefinitions();
+ // NOTE: This method doesn't move the cursor of m_pXmlInput
bool Next();
+ // NOTE: Read to the next feature type
+ bool ReadNext();
+
+ // Resets the enumerator.
+ void Reset();
+
+
// Used by the enumerator to create dictionary entries
// for the features in question.
void GenerateDefinitions(MgUtilDictionary& Dictionary);
@@ -55,6 +63,13 @@
bool PrefixToFeatureSource(STRING sPrefix, REFSTRING sFeatureSource, REFSTRING sSchemaName);
STRING GetNamespaceUrl();
+
+ STRING GetNamespacePrefix();
+
+ STRING GetClassFullName();
+
+ // Return true if all typenames have the same namespace
+ bool InSameNamespace();
private:
bool SkipElement(MgXmlParser& Input,CPSZ pszElementName);
bool GetElementContents(MgXmlParser& Input,CPSZ pszElementName,STRING& sValue);
@@ -74,6 +89,15 @@
STRING m_sSourcesAndClasses;
STRING m_sSubsetOfTypes;
+
+ STRING m_sCurrentPrefix;
+ STRING m_sCurrentUrl;
+ STRING m_sCurrentClassName;
+
+ // Prefix:Schema
+ //Mapping for prefix and schema, just used for OGC certification
+ STRING m_sPrefixSchemaMapping;
+
bool m_bOk;
More information about the mapguide-commits
mailing list