QGIS API Documentation  3.21.0-Master (5b68dc587e)
qgsxmlutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsxmlutils.cpp
3  ---------------------
4  begin : December 2013
5  copyright : (C) 2013 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 #include "qgsxmlutils.h"
16 
17 #include <QDomElement>
18 
19 #include "qgslogger.h"
20 #include "qgsrectangle.h"
21 #include "qgsproperty.h"
22 #include "qgssymbollayerutils.h"
25 
27 {
28  if ( "unknown" == element.text() )
29  {
31  }
32  else
33  {
34  const QgsUnitTypes::DistanceUnit unit = QgsUnitTypes::decodeDistanceUnit( element.text() );
36  }
37 }
38 
39 QgsRectangle QgsXmlUtils::readRectangle( const QDomElement &element )
40 {
41  QgsRectangle aoi;
42 
43  const QDomNode xminNode = element.namedItem( QStringLiteral( "xmin" ) );
44  const QDomNode yminNode = element.namedItem( QStringLiteral( "ymin" ) );
45  const QDomNode xmaxNode = element.namedItem( QStringLiteral( "xmax" ) );
46  const QDomNode ymaxNode = element.namedItem( QStringLiteral( "ymax" ) );
47 
48  QDomElement exElement = xminNode.toElement();
49  const double xmin = exElement.text().toDouble();
50  aoi.setXMinimum( xmin );
51 
52  exElement = yminNode.toElement();
53  const double ymin = exElement.text().toDouble();
54  aoi.setYMinimum( ymin );
55 
56  exElement = xmaxNode.toElement();
57  const double xmax = exElement.text().toDouble();
58  aoi.setXMaximum( xmax );
59 
60  exElement = ymaxNode.toElement();
61  const double ymax = exElement.text().toDouble();
62  aoi.setYMaximum( ymax );
63 
64  return aoi;
65 }
66 
67 
68 
69 QDomElement QgsXmlUtils::writeMapUnits( QgsUnitTypes::DistanceUnit units, QDomDocument &doc )
70 {
71  QString unitsString = QgsUnitTypes::encodeUnit( units );
72  // maintain compatibility with old projects
73  if ( units == QgsUnitTypes::DistanceUnknownUnit )
74  unitsString = QStringLiteral( "unknown" );
75 
76  QDomElement unitsNode = doc.createElement( QStringLiteral( "units" ) );
77  unitsNode.appendChild( doc.createTextNode( unitsString ) );
78  return unitsNode;
79 }
80 
81 QDomElement QgsXmlUtils::writeRectangle( const QgsRectangle &rect, QDomDocument &doc, const QString &elementName )
82 {
83  QDomElement xMin = doc.createElement( QStringLiteral( "xmin" ) );
84  QDomElement yMin = doc.createElement( QStringLiteral( "ymin" ) );
85  QDomElement xMax = doc.createElement( QStringLiteral( "xmax" ) );
86  QDomElement yMax = doc.createElement( QStringLiteral( "ymax" ) );
87 
88  const QDomText xMinText = doc.createTextNode( qgsDoubleToString( rect.xMinimum() ) );
89  const QDomText yMinText = doc.createTextNode( qgsDoubleToString( rect.yMinimum() ) );
90  const QDomText xMaxText = doc.createTextNode( qgsDoubleToString( rect.xMaximum() ) );
91  const QDomText yMaxText = doc.createTextNode( qgsDoubleToString( rect.yMaximum() ) );
92 
93  xMin.appendChild( xMinText );
94  yMin.appendChild( yMinText );
95  xMax.appendChild( xMaxText );
96  yMax.appendChild( yMaxText );
97 
98  QDomElement extentNode = doc.createElement( elementName );
99  extentNode.appendChild( xMin );
100  extentNode.appendChild( yMin );
101  extentNode.appendChild( xMax );
102  extentNode.appendChild( yMax );
103  return extentNode;
104 }
105 
106 QDomElement QgsXmlUtils::writeVariant( const QVariant &value, QDomDocument &doc )
107 {
108  QDomElement element = doc.createElement( QStringLiteral( "Option" ) );
109  switch ( value.type() )
110  {
111  case QVariant::Invalid:
112  {
113  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "invalid" ) );
114  break;
115  }
116 
117  case QVariant::Map:
118  {
119  const QVariantMap map = value.toMap();
120 
121  for ( auto option = map.constBegin(); option != map.constEnd(); ++option )
122  {
123  QDomElement optionElement = writeVariant( option.value(), doc );
124  optionElement.setAttribute( QStringLiteral( "name" ), option.key() );
125  element.appendChild( optionElement );
126  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "Map" ) );
127  }
128  break;
129  }
130 
131  case QVariant::List:
132  {
133  const QVariantList list = value.toList();
134 
135  const auto constList = list;
136  for ( const QVariant &value : constList )
137  {
138  const QDomElement valueElement = writeVariant( value, doc );
139  element.appendChild( valueElement );
140  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "List" ) );
141  }
142  break;
143  }
144 
145  case QVariant::StringList:
146  {
147  const QStringList list = value.toStringList();
148 
149  const auto constList = list;
150  for ( const QString &value : constList )
151  {
152  const QDomElement valueElement = writeVariant( value, doc );
153  element.appendChild( valueElement );
154  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "StringList" ) );
155  }
156  break;
157  }
158 
159  case QVariant::Int:
160  case QVariant::UInt:
161  case QVariant::Bool:
162  case QVariant::Double:
163  case QVariant::LongLong:
164  case QVariant::ULongLong:
165  case QVariant::String:
166  element.setAttribute( QStringLiteral( "type" ), QVariant::typeToName( value.type() ) );
167  element.setAttribute( QStringLiteral( "value" ), value.toString() );
168  break;
169 
170  case QVariant::Char:
171  element.setAttribute( QStringLiteral( "type" ), QVariant::typeToName( value.type() ) );
172  element.setAttribute( QStringLiteral( "value" ), value.isNull() ? QString() : value.toString() );
173  break;
174 
175  case QVariant::Color:
176  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "color" ) );
177  element.setAttribute( QStringLiteral( "value" ), value.value< QColor >().isValid() ? QgsSymbolLayerUtils::encodeColor( value.value< QColor >() ) : QString() );
178  break;
179 
180  case QVariant::DateTime:
181  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "datetime" ) );
182  element.setAttribute( QStringLiteral( "value" ), value.value< QDateTime >().isValid() ? value.toDateTime().toString( Qt::ISODate ) : QString() );
183  break;
184 
185  case QVariant::Date:
186  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "date" ) );
187  element.setAttribute( QStringLiteral( "value" ), value.value< QDate >().isValid() ? value.toDate().toString( Qt::ISODate ) : QString() );
188  break;
189 
190  case QVariant::Time:
191  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "time" ) );
192  element.setAttribute( QStringLiteral( "value" ), value.value< QTime >().isValid() ? value.toTime().toString( Qt::ISODate ) : QString() );
193  break;
194 
195  case QVariant::UserType:
196  {
197  if ( value.canConvert< QgsProperty >() )
198  {
199  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsProperty" ) );
200  const QDomElement propertyElem = QgsXmlUtils::writeVariant( value.value< QgsProperty >().toVariant(), doc );
201  element.appendChild( propertyElem );
202  break;
203  }
204  else if ( value.canConvert< QgsCoordinateReferenceSystem >() )
205  {
206  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsCoordinateReferenceSystem" ) );
208  crs.writeXml( element, doc );
209  break;
210  }
211  else if ( value.canConvert< QgsGeometry >() )
212  {
213  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsGeometry" ) );
214  const QgsGeometry geom = value.value< QgsGeometry >();
215  element.setAttribute( QStringLiteral( "value" ), geom.asWkt() );
216  break;
217  }
218  else if ( value.canConvert< QgsProcessingOutputLayerDefinition >() )
219  {
220  const QDomElement valueElement = writeVariant( value.value< QgsProcessingOutputLayerDefinition >().toVariant(), doc );
221  element.appendChild( valueElement );
222  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsProcessingOutputLayerDefinition" ) );
223  break;
224  }
225  else if ( value.canConvert< QgsProcessingFeatureSourceDefinition >() )
226  {
227  const QDomElement valueElement = writeVariant( value.value< QgsProcessingFeatureSourceDefinition >().toVariant(), doc );
228  element.appendChild( valueElement );
229  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsProcessingFeatureSourceDefinition" ) );
230  break;
231  }
232  else if ( value.canConvert< QgsRemappingSinkDefinition >() )
233  {
234  const QDomElement valueElement = writeVariant( value.value< QgsRemappingSinkDefinition >().toVariant(), doc );
235  element.appendChild( valueElement );
236  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsRemappingSinkDefinition" ) );
237  break;
238  }
239  Q_ASSERT_X( false, "QgsXmlUtils::writeVariant", QStringLiteral( "unsupported user variant type %1" ).arg( QMetaType::typeName( value.userType() ) ).toLocal8Bit() );
240  break;
241  }
242 
243  default:
244  Q_ASSERT_X( false, "QgsXmlUtils::writeVariant", QStringLiteral( "unsupported variant type %1" ).arg( QVariant::typeToName( value.type() ) ).toLocal8Bit() );
245  break;
246  }
247 
248  return element;
249 }
250 
251 QVariant QgsXmlUtils::readVariant( const QDomElement &element )
252 {
253  const QString type = element.attribute( QStringLiteral( "type" ) );
254 
255  if ( type == QLatin1String( "invalid" ) )
256  {
257  return QVariant();
258  }
259  else if ( type == QLatin1String( "int" ) )
260  {
261  return element.attribute( QStringLiteral( "value" ) ).toInt();
262  }
263  else if ( type == QLatin1String( "uint" ) )
264  {
265  return element.attribute( QStringLiteral( "value" ) ).toUInt();
266  }
267  else if ( type == QLatin1String( "qlonglong" ) )
268  {
269  return element.attribute( QStringLiteral( "value" ) ).toLongLong();
270  }
271  else if ( type == QLatin1String( "qulonglong" ) )
272  {
273  return element.attribute( QStringLiteral( "value" ) ).toULongLong();
274  }
275  else if ( type == QLatin1String( "double" ) )
276  {
277  return element.attribute( QStringLiteral( "value" ) ).toDouble();
278  }
279  else if ( type == QLatin1String( "QString" ) )
280  {
281  return element.attribute( QStringLiteral( "value" ) );
282  }
283  else if ( type == QLatin1String( "QChar" ) )
284  {
285  const QString res = element.attribute( QStringLiteral( "value" ) );
286  return res.isEmpty() ? QChar() : res.at( 0 );
287  }
288  else if ( type == QLatin1String( "bool" ) )
289  {
290  return element.attribute( QStringLiteral( "value" ) ) == QLatin1String( "true" );
291  }
292  else if ( type == QLatin1String( "color" ) )
293  {
294  return element.attribute( QStringLiteral( "value" ) ).isEmpty() ? QColor() : QgsSymbolLayerUtils::decodeColor( element.attribute( QStringLiteral( "value" ) ) );
295  }
296  else if ( type == QLatin1String( "datetime" ) )
297  {
298  return element.attribute( QStringLiteral( "value" ) ).isEmpty() ? QDateTime() : QDateTime::fromString( element.attribute( QStringLiteral( "value" ) ), Qt::ISODate );
299  }
300  else if ( type == QLatin1String( "date" ) )
301  {
302  return element.attribute( QStringLiteral( "value" ) ).isEmpty() ? QDate() : QDate::fromString( element.attribute( QStringLiteral( "value" ) ), Qt::ISODate );
303  }
304  else if ( type == QLatin1String( "time" ) )
305  {
306  return element.attribute( QStringLiteral( "value" ) ).isEmpty() ? QTime() : QTime::fromString( element.attribute( QStringLiteral( "value" ) ), Qt::ISODate );
307  }
308  else if ( type == QLatin1String( "Map" ) )
309  {
310  QVariantMap map;
311  const QDomNodeList options = element.childNodes();
312 
313  for ( int i = 0; i < options.count(); ++i )
314  {
315  const QDomElement elem = options.at( i ).toElement();
316  if ( elem.tagName() == QLatin1String( "Option" ) )
317  map.insert( elem.attribute( QStringLiteral( "name" ) ), readVariant( elem ) );
318  }
319  return map;
320  }
321  else if ( type == QLatin1String( "List" ) )
322  {
323  QVariantList list;
324  const QDomNodeList values = element.childNodes();
325  for ( int i = 0; i < values.count(); ++i )
326  {
327  const QDomElement elem = values.at( i ).toElement();
328  list.append( readVariant( elem ) );
329  }
330  return list;
331  }
332  else if ( type == QLatin1String( "StringList" ) )
333  {
334  QStringList list;
335  const QDomNodeList values = element.childNodes();
336  for ( int i = 0; i < values.count(); ++i )
337  {
338  const QDomElement elem = values.at( i ).toElement();
339  list.append( readVariant( elem ).toString() );
340  }
341  return list;
342  }
343  else if ( type == QLatin1String( "QgsProperty" ) )
344  {
345  const QDomNodeList values = element.childNodes();
346  if ( values.isEmpty() )
347  return QVariant();
348 
349  QgsProperty p;
350  if ( p.loadVariant( QgsXmlUtils::readVariant( values.at( 0 ).toElement() ) ) )
351  return p;
352 
353  return QVariant();
354  }
355  else if ( type == QLatin1String( "QgsCoordinateReferenceSystem" ) )
356  {
358  crs.readXml( element );
359  return crs;
360  }
361  else if ( type == QLatin1String( "QgsGeometry" ) )
362  {
363  return QgsGeometry::fromWkt( element.attribute( "value" ) );
364  }
365  else if ( type == QLatin1String( "QgsProcessingOutputLayerDefinition" ) )
366  {
368  const QDomNodeList values = element.childNodes();
369  if ( values.isEmpty() )
370  return QVariant();
371 
372  if ( res.loadVariant( QgsXmlUtils::readVariant( values.at( 0 ).toElement() ).toMap() ) )
373  return res;
374 
375  return QVariant();
376  }
377  else if ( type == QLatin1String( "QgsProcessingFeatureSourceDefinition" ) )
378  {
380  const QDomNodeList values = element.childNodes();
381  if ( values.isEmpty() )
382  return QVariant();
383 
384  if ( res.loadVariant( QgsXmlUtils::readVariant( values.at( 0 ).toElement() ).toMap() ) )
385  return res;
386 
387  return QVariant();
388  }
389  else if ( type == QLatin1String( "QgsRemappingSinkDefinition" ) )
390  {
392  const QDomNodeList values = element.childNodes();
393  if ( values.isEmpty() )
394  return QVariant();
395 
396  if ( res.loadVariant( QgsXmlUtils::readVariant( values.at( 0 ).toElement() ).toMap() ) )
397  return QVariant::fromValue( res );
398 
399  return QVariant();
400  }
401  else
402  {
403  return QVariant();
404  }
405 }
This class represents a coordinate reference system (CRS).
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
static QgsGeometry fromWkt(const QString &wkt)
Creates a new geometry from a WKT string.
QString asWkt(int precision=17) const
Exports the geometry to WKT.
Encapsulates settings relating to a feature source input to a processing algorithm.
bool loadVariant(const QVariantMap &map)
Loads this source definition from a QVariantMap, wrapped in a QVariant.
QVariant toVariant() const
Saves this source definition to a QVariantMap, wrapped in a QVariant.
Encapsulates settings relating to a feature sink or output raster layer for a processing algorithm.
bool loadVariant(const QVariantMap &map)
Loads this output layer definition from a QVariantMap, wrapped in a QVariant.
QVariant toVariant() const
Saves this output layer definition to a QVariantMap, wrapped in a QVariant.
A store for object properties.
Definition: qgsproperty.h:232
QVariant toVariant() const
Saves this property to a QVariantMap, wrapped in a QVariant.
bool loadVariant(const QVariant &property)
Loads this property from a QVariantMap, wrapped in a QVariant.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
void setYMinimum(double y) SIP_HOLDGIL
Set the minimum y value.
Definition: qgsrectangle.h:161
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
Definition: qgsrectangle.h:156
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
Definition: qgsrectangle.h:151
void setYMaximum(double y) SIP_HOLDGIL
Set the maximum y value.
Definition: qgsrectangle.h:166
Defines the parameters used to remap features when creating a QgsRemappingProxyFeatureSink.
QVariant toVariant() const
Saves this remapping definition to a QVariantMap, wrapped in a QVariant.
bool loadVariant(const QVariantMap &map)
Loads this remapping definition from a QVariantMap, wrapped in a QVariant.
static QColor decodeColor(const QString &str)
static QString encodeColor(const QColor &color)
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:68
@ DistanceDegrees
Degrees, for planar geographic CRS distance measurements.
Definition: qgsunittypes.h:75
@ DistanceUnknownUnit
Unknown distance unit.
Definition: qgsunittypes.h:78
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
static Q_INVOKABLE QgsUnitTypes::DistanceUnit decodeDistanceUnit(const QString &string, bool *ok=nullptr)
Decodes a distance unit from a string.
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
static QDomElement writeRectangle(const QgsRectangle &rect, QDomDocument &doc, const QString &elementName=QStringLiteral("extent"))
Encodes a rectangle to a DOM element.
Definition: qgsxmlutils.cpp:81
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
static QDomElement writeMapUnits(QgsUnitTypes::DistanceUnit units, QDomDocument &doc)
Encodes a distance unit to a DOM element.
Definition: qgsxmlutils.cpp:69
static QgsUnitTypes::DistanceUnit readMapUnits(const QDomElement &element)
Decodes a distance unit from a DOM element.
Definition: qgsxmlutils.cpp:26
static QgsRectangle readRectangle(const QDomElement &element)
Definition: qgsxmlutils.cpp:39
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:1186
const QgsCoordinateReferenceSystem & crs
const QString & typeName