24 #include <QNetworkRequest> 25 #include <QNetworkReply> 26 #include <QProgressDialog> 34 const QString
GML_NAMESPACE = QStringLiteral(
"http://www.opengis.net/gml" );
45 for (
int i = 0; i < mFields.size(); i++ )
47 if ( mFields[i].name() == name )
return i;
54 : mSkipLevel( std::numeric_limits<int>::max() )
56 mGeometryTypes << QStringLiteral(
"Point" ) << QStringLiteral(
"MultiPoint" )
57 << QStringLiteral(
"LineString" ) << QStringLiteral(
"MultiLineString" )
58 << QStringLiteral(
"Polygon" ) << QStringLiteral(
"MultiPolygon" );
61 QString QgsGmlSchema::readAttribute(
const QString &attributeName,
const XML_Char **attr )
const 66 if ( attributeName.compare( attr[i] ) == 0 )
68 return QString( attr[i + 1] );
81 if ( !dom.setContent( xml,
false, &errorMsg, &errorLine, &errorColumn ) )
87 QDomElement docElem = dom.documentElement();
89 QList<QDomElement> elementElements = domElements( docElem, QStringLiteral(
"element" ) );
93 Q_FOREACH (
const QDomElement &elementElement, elementElements )
95 QString name = elementElement.attribute( QStringLiteral(
"name" ) );
96 QString type = elementElement.attribute( QStringLiteral(
"type" ) );
98 QString gmlBaseType = xsdComplexTypeGmlBaseType( docElem, stripNS( type ) );
105 if ( gmlBaseType == QLatin1String(
"AbstractFeatureType" ) )
109 xsdFeatureClass( docElem, stripNS( type ), featureClass );
110 mFeatureClassMap.insert( name, featureClass );
118 bool QgsGmlSchema::xsdFeatureClass(
const QDomElement &element,
const QString &typeName,
QgsGmlFeatureClass &featureClass )
121 QDomElement complexTypeElement = domElement( element, QStringLiteral(
"complexType" ), QStringLiteral(
"name" ), typeName );
122 if ( complexTypeElement.isNull() )
return false;
125 QDomElement extrest = domElement( complexTypeElement, QStringLiteral(
"complexContent.extension" ) );
126 if ( extrest.isNull() )
128 extrest = domElement( complexTypeElement, QStringLiteral(
"complexContent.restriction" ) );
130 if ( extrest.isNull() )
return false;
132 QString extrestName = extrest.attribute( QStringLiteral(
"base" ) );
133 if ( extrestName == QLatin1String(
"gml:AbstractFeatureType" ) )
142 if ( !xsdFeatureClass( element, stripNS( extrestName ), featureClass ) )
return false;
146 QStringList geometryPropertyTypes;
147 Q_FOREACH (
const QString &geom, mGeometryTypes )
149 geometryPropertyTypes << geom +
"PropertyType";
152 QStringList geometryAliases;
153 geometryAliases << QStringLiteral(
"location" ) << QStringLiteral(
"centerOf" ) << QStringLiteral(
"position" ) << QStringLiteral(
"extentOf" )
154 << QStringLiteral(
"coverage" ) << QStringLiteral(
"edgeOf" ) << QStringLiteral(
"centerLineOf" ) << QStringLiteral(
"multiLocation" )
155 << QStringLiteral(
"multiCenterOf" ) << QStringLiteral(
"multiPosition" ) << QStringLiteral(
"multiCenterLineOf" )
156 << QStringLiteral(
"multiEdgeOf" ) << QStringLiteral(
"multiCoverage" ) << QStringLiteral(
"multiExtentOf" );
159 QList<QDomElement> sequenceElements = domElements( extrest, QStringLiteral(
"sequence.element" ) );
160 Q_FOREACH (
const QDomElement &sequenceElement, sequenceElements )
162 QString fieldName = sequenceElement.attribute( QStringLiteral(
"name" ) );
163 QString fieldTypeName = stripNS( sequenceElement.attribute( QStringLiteral(
"type" ) ) );
164 QString ref = sequenceElement.attribute( QStringLiteral(
"ref" ) );
167 if ( !ref.isEmpty() )
169 if ( ref.startsWith( QLatin1String(
"gml:" ) ) )
171 if ( geometryAliases.contains( stripNS( ref ) ) )
177 QgsDebugMsg( QString(
"Unknown referenced GML element: %1" ).arg( ref ) );
183 QgsDebugMsg( QString(
"field %1.%2 is referencing %3 - not supported" ).arg( typeName, fieldName ) );
188 if ( fieldName.isEmpty() )
190 QgsDebugMsg( QString(
"field in %1 without name" ).arg( typeName ) );
195 if ( fieldTypeName.isEmpty() )
198 QDomElement sequenceElementRestriction = domElement( sequenceElement, QStringLiteral(
"simpleType.restriction" ) );
199 fieldTypeName = stripNS( sequenceElementRestriction.attribute( QStringLiteral(
"base" ) ) );
202 QVariant::Type fieldType = QVariant::String;
203 if ( fieldTypeName.isEmpty() )
205 QgsDebugMsg( QString(
"Cannot get %1.%2 field type" ).arg( typeName, fieldName ) );
209 if ( geometryPropertyTypes.contains( fieldTypeName ) )
216 if ( fieldTypeName == QLatin1String(
"decimal" ) )
218 fieldType = QVariant::Double;
220 else if ( fieldTypeName == QLatin1String(
"integer" ) )
222 fieldType = QVariant::Int;
226 QgsField field( fieldName, fieldType, fieldTypeName );
227 featureClass.
fields().append( field );
233 QString QgsGmlSchema::xsdComplexTypeGmlBaseType(
const QDomElement &element,
const QString &name )
236 QDomElement complexTypeElement = domElement( element, QStringLiteral(
"complexType" ), QStringLiteral(
"name" ), name );
237 if ( complexTypeElement.isNull() )
return QLatin1String(
"" );
239 QDomElement extrest = domElement( complexTypeElement, QStringLiteral(
"complexContent.extension" ) );
240 if ( extrest.isNull() )
242 extrest = domElement( complexTypeElement, QStringLiteral(
"complexContent.restriction" ) );
244 if ( extrest.isNull() )
return QLatin1String(
"" );
246 QString extrestName = extrest.attribute( QStringLiteral(
"base" ) );
247 if ( extrestName.startsWith( QLatin1String(
"gml:" ) ) )
250 return stripNS( extrestName );
253 return xsdComplexTypeGmlBaseType( element, stripNS( extrestName ) );
256 QString QgsGmlSchema::stripNS(
const QString &name )
258 return name.contains(
':' ) ? name.section(
':', 1 ) : name;
261 QList<QDomElement> QgsGmlSchema::domElements(
const QDomElement &element,
const QString &path )
263 QList<QDomElement> list;
265 QStringList names = path.split(
'.' );
266 if ( names.isEmpty() )
return list;
267 QString name = names.value( 0 );
270 QDomNode n1 = element.firstChild();
271 while ( !n1.isNull() )
273 QDomElement el = n1.toElement();
276 QString tagName = stripNS( el.tagName() );
277 if ( tagName == name )
279 if ( names.isEmpty() )
285 list.append( domElements( el, names.join( QStringLiteral(
"." ) ) ) );
289 n1 = n1.nextSibling();
295 QDomElement QgsGmlSchema::domElement(
const QDomElement &element,
const QString &path )
297 return domElements( element, path ).value( 0 );
300 QList<QDomElement> QgsGmlSchema::domElements( QList<QDomElement> &elements,
const QString &attr,
const QString &attrVal )
302 QList<QDomElement> list;
303 Q_FOREACH (
const QDomElement &el, elements )
305 if ( el.attribute( attr ) == attrVal )
313 QDomElement QgsGmlSchema::domElement(
const QDomElement &element,
const QString &path,
const QString &attr,
const QString &attrVal )
315 QList<QDomElement> list = domElements( element, path );
316 return domElements( list, attr, attrVal ).value( 0 );
322 mSkipLevel = std::numeric_limits<int>::max();
323 XML_Parser p = XML_ParserCreateNS(
nullptr,
NS_SEPARATOR );
324 XML_SetUserData( p,
this );
325 XML_SetElementHandler( p, QgsGmlSchema::start, QgsGmlSchema::end );
326 XML_SetCharacterDataHandler( p, QgsGmlSchema::chars );
328 int res = XML_Parse( p, data.constData(), data.size(), atEnd );
332 QString err = QString( XML_ErrorString( XML_GetErrorCode( p ) ) );
333 QgsDebugMsg( QString(
"XML_Parse returned %1 error %2" ).arg( res ).arg( err ) );
334 mError =
QgsError( err, QStringLiteral(
"GML schema" ) );
335 mError.
append( tr(
"Cannot guess schema" ) );
341 void QgsGmlSchema::startElement(
const XML_Char *el,
const XML_Char **attr )
346 QString elementName = QString::fromUtf8( el );
347 QgsDebugMsgLevel( QString(
"-> %1 %2 %3" ).arg( mLevel ).arg( elementName, mLevel >= mSkipLevel ?
"skip" :
"" ), 5 );
349 if ( mLevel >= mSkipLevel )
355 mParsePathStack.append( elementName );
356 QString path = mParsePathStack.join( QStringLiteral(
"." ) );
358 QStringList splitName = elementName.split(
NS_SEPARATOR );
359 QString localName = splitName.last();
360 QString ns = splitName.size() > 1 ? splitName.first() : QLatin1String(
"" );
363 ParseMode parseMode = modeStackTop();
366 if ( ns ==
GML_NAMESPACE && localName == QLatin1String(
"boundedBy" ) )
369 mSkipLevel = mLevel + 1;
371 else if ( localName.compare( QLatin1String(
"featureMembers" ), Qt::CaseInsensitive ) == 0 )
373 mParseModeStack.push( QgsGmlSchema::FeatureMembers );
380 else if ( localName.endsWith( QLatin1String(
"member" ), Qt::CaseInsensitive ) )
382 mParseModeStack.push( QgsGmlSchema::FeatureMember );
385 else if ( elementName.endsWith( QLatin1String(
"_layer" ) ) )
393 else if ( elementName.endsWith( QLatin1String(
"_feature" ) )
394 || parseMode == QgsGmlSchema::FeatureMember
395 || parseMode == QgsGmlSchema::FeatureMembers
396 || localName.compare( QLatin1String(
"feature" ), Qt::CaseInsensitive ) == 0 )
399 if ( mFeatureClassMap.count( localName ) == 0 )
403 mCurrentFeatureName = localName;
404 mParseModeStack.push( QgsGmlSchema::Feature );
406 else if ( parseMode == QgsGmlSchema::Attribute && ns ==
GML_NAMESPACE && mGeometryTypes.indexOf( localName ) >= 0 )
409 QStringList &
geometryAttributes = mFeatureClassMap[mCurrentFeatureName].geometryAttributes();
410 if ( geometryAttributes.count( mAttributeName ) == 0 )
412 geometryAttributes.append( mAttributeName );
414 mSkipLevel = mLevel + 1;
416 else if ( parseMode == QgsGmlSchema::Feature )
425 QString name = readAttribute( QStringLiteral(
"name" ), attr );
427 if ( localName.compare( QLatin1String(
"attribute" ), Qt::CaseInsensitive ) == 0
430 QString value = readAttribute( QStringLiteral(
"value" ), attr );
432 addAttribute( name, value );
436 mAttributeName = localName;
437 mParseModeStack.push( QgsGmlSchema::Attribute );
443 void QgsGmlSchema::endElement(
const XML_Char *el )
445 QString elementName = QString::fromUtf8( el );
446 QgsDebugMsgLevel( QString(
"<- %1 %2" ).arg( mLevel ).arg( elementName ), 5 );
448 if ( mLevel >= mSkipLevel )
457 mSkipLevel = std::numeric_limits<int>::max();
460 QStringList splitName = elementName.split(
NS_SEPARATOR );
461 QString localName = splitName.last();
462 QString ns = splitName.size() > 1 ? splitName.first() : QLatin1String(
"" );
464 QgsGmlSchema::ParseMode parseMode = modeStackTop();
466 if ( parseMode == QgsGmlSchema::FeatureMembers )
470 else if ( parseMode == QgsGmlSchema::Attribute && localName == mAttributeName )
476 if ( mFeatureClassMap[mCurrentFeatureName].
geometryAttributes().count( mAttributeName ) == 0 )
478 addAttribute( mAttributeName, mStringCash );
481 else if ( ns ==
GML_NAMESPACE && localName == QLatin1String(
"boundedBy" ) )
485 else if ( localName.endsWith( QLatin1String(
"member" ), Qt::CaseInsensitive ) )
489 mParsePathStack.removeLast();
493 void QgsGmlSchema::characters(
const XML_Char *chars,
int len )
496 if ( mLevel >= mSkipLevel )
503 if ( modeStackTop() == QgsGmlSchema::Attribute )
505 mStringCash.append( QString::fromUtf8( chars, len ) );
509 void QgsGmlSchema::addAttribute(
const QString &name,
const QString &value )
514 QVariant::Type type = QVariant::String;
517 type = QVariant::Int;
521 value.toDouble( &ok );
524 type = QVariant::Double;
529 QList<QgsField> &
fields = mFeatureClassMap[mCurrentFeatureName].fields();
530 int fieldIndex = mFeatureClassMap[mCurrentFeatureName].fieldIndex( name );
531 if ( fieldIndex == -1 )
534 fields.append( field );
538 QgsField &field = fields[fieldIndex];
540 if ( ( field.
type() == QVariant::Int && ( type == QVariant::String || type == QVariant::Double ) ) ||
541 ( field.
type() == QVariant::Double && type == QVariant::String ) )
550 return mFeatureClassMap.keys();
555 if ( mFeatureClassMap.count( typeName ) == 0 )
return QList<QgsField>();
556 return mFeatureClassMap[typeName].fields();
561 if ( mFeatureClassMap.count( typeName ) == 0 )
return QStringList();
562 return mFeatureClassMap[typeName].geometryAttributes();
bool guessSchema(const QByteArray &data)
Guess GML schema from data if XSD does not exist.
const QString GML_NAMESPACE
QList< QgsField > & fields()
#define QgsDebugMsgLevel(str, level)
QList< QgsField > fields(const QString &typeName)
Gets fields for type/class name parsed from GML or XSD.
void append(const QString &message, const QString &tag)
Append new error message.
Encapsulate a field in an attribute table or data source.
Description of feature class in GML.
void setType(QVariant::Type type)
Set variant type.
QgsError is container for error messages (report).
QStringList & geometryAttributes()
QgsGmlFeatureClass()=default
Constructor for QgsGmlFeatureClass.
QStringList typeNames() const
Gets list of dot separated paths to feature classes parsed from GML or XSD.
int fieldIndex(const QString &name)
bool parseXSD(const QByteArray &xml)
Gets fields info from XSD.
QStringList geometryAttributes(const QString &typeName)
Gets list of geometry attributes for type/class name.