QGIS API Documentation  3.37.0-Master (a5b4d9743e8)
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 "qgsrectangle.h"
20 #include "qgsproperty.h"
21 #include "qgscolorutils.h"
24 #include "qgsunittypes.h"
25 
26 Qgis::DistanceUnit QgsXmlUtils::readMapUnits( const QDomElement &element )
27 {
28  if ( "unknown" == element.text() )
29  {
31  }
32  else
33  {
34  const Qgis::DistanceUnit unit = QgsUnitTypes::decodeDistanceUnit( element.text() );
36  }
37 }
38 
39 QgsBox3D QgsXmlUtils::readBox3D( const QDomElement &element )
40 {
41  QgsBox3D aoi;
42 
43  const double xmin = element.attribute( QStringLiteral( "xmin" ) ).toDouble();
44  aoi.setXMinimum( xmin );
45 
46  const double ymin = element.attribute( QStringLiteral( "ymin" ) ).toDouble();
47  aoi.setYMinimum( ymin );
48 
49  const double zmin = element.attribute( QStringLiteral( "zmin" ) ).toDouble();
50  aoi.setZMinimum( zmin );
51 
52  const double xmax = element.attribute( QStringLiteral( "xmax" ) ).toDouble();
53  aoi.setXMaximum( xmax );
54 
55  const double ymax = element.attribute( QStringLiteral( "ymax" ) ).toDouble();
56  aoi.setYMaximum( ymax );
57 
58  const double zmax = element.attribute( QStringLiteral( "zmax" ) ).toDouble();
59  aoi.setZMaximum( zmax );
60 
61  return aoi;
62 }
63 
64 QgsRectangle QgsXmlUtils::readRectangle( const QDomElement &element )
65 {
66  QgsRectangle aoi;
67 
68  const QDomNode xminNode = element.namedItem( QStringLiteral( "xmin" ) );
69  const QDomNode yminNode = element.namedItem( QStringLiteral( "ymin" ) );
70  const QDomNode xmaxNode = element.namedItem( QStringLiteral( "xmax" ) );
71  const QDomNode ymaxNode = element.namedItem( QStringLiteral( "ymax" ) );
72 
73  QDomElement exElement = xminNode.toElement();
74  const double xmin = exElement.text().toDouble();
75  aoi.setXMinimum( xmin );
76 
77  exElement = yminNode.toElement();
78  const double ymin = exElement.text().toDouble();
79  aoi.setYMinimum( ymin );
80 
81  exElement = xmaxNode.toElement();
82  const double xmax = exElement.text().toDouble();
83  aoi.setXMaximum( xmax );
84 
85  exElement = ymaxNode.toElement();
86  const double ymax = exElement.text().toDouble();
87  aoi.setYMaximum( ymax );
88 
89  return aoi;
90 }
91 
92 
93 
94 QDomElement QgsXmlUtils::writeMapUnits( Qgis::DistanceUnit units, QDomDocument &doc )
95 {
96  QString unitsString = QgsUnitTypes::encodeUnit( units );
97  // maintain compatibility with old projects
98  if ( units == Qgis::DistanceUnit::Unknown )
99  unitsString = QStringLiteral( "unknown" );
100 
101  QDomElement unitsNode = doc.createElement( QStringLiteral( "units" ) );
102  unitsNode.appendChild( doc.createTextNode( unitsString ) );
103  return unitsNode;
104 }
105 
106 QDomElement QgsXmlUtils::writeBox3D( const QgsBox3D &box, QDomDocument &doc, const QString &elementName )
107 {
108  QDomElement elemExtent3D = doc.createElement( elementName );
109  elemExtent3D.setAttribute( QStringLiteral( "xMin" ), box.xMinimum() );
110  elemExtent3D.setAttribute( QStringLiteral( "yMin" ), box.yMinimum() );
111  elemExtent3D.setAttribute( QStringLiteral( "zMin" ), box.zMinimum() );
112  elemExtent3D.setAttribute( QStringLiteral( "xMax" ), box.xMaximum() );
113  elemExtent3D.setAttribute( QStringLiteral( "yMax" ), box.yMaximum() );
114  elemExtent3D.setAttribute( QStringLiteral( "zMax" ), box.zMaximum() );
115 
116  return elemExtent3D;
117 }
118 
119 QDomElement QgsXmlUtils::writeRectangle( const QgsRectangle &rect, QDomDocument &doc, const QString &elementName )
120 {
121  QDomElement xMin = doc.createElement( QStringLiteral( "xmin" ) );
122  QDomElement yMin = doc.createElement( QStringLiteral( "ymin" ) );
123  QDomElement xMax = doc.createElement( QStringLiteral( "xmax" ) );
124  QDomElement yMax = doc.createElement( QStringLiteral( "ymax" ) );
125 
126  const QDomText xMinText = doc.createTextNode( qgsDoubleToString( rect.xMinimum() ) );
127  const QDomText yMinText = doc.createTextNode( qgsDoubleToString( rect.yMinimum() ) );
128  const QDomText xMaxText = doc.createTextNode( qgsDoubleToString( rect.xMaximum() ) );
129  const QDomText yMaxText = doc.createTextNode( qgsDoubleToString( rect.yMaximum() ) );
130 
131  xMin.appendChild( xMinText );
132  yMin.appendChild( yMinText );
133  xMax.appendChild( xMaxText );
134  yMax.appendChild( yMaxText );
135 
136  QDomElement extentNode = doc.createElement( elementName );
137  extentNode.appendChild( xMin );
138  extentNode.appendChild( yMin );
139  extentNode.appendChild( xMax );
140  extentNode.appendChild( yMax );
141  return extentNode;
142 }
143 
144 QDomElement QgsXmlUtils::writeVariant( const QVariant &value, QDomDocument &doc )
145 {
146  QDomElement element = doc.createElement( QStringLiteral( "Option" ) );
147  switch ( value.type() )
148  {
149  case QVariant::Invalid:
150  {
151  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "invalid" ) );
152  break;
153  }
154 
155  case QVariant::Map:
156  {
157  const QVariantMap map = value.toMap();
158 
159  for ( auto option = map.constBegin(); option != map.constEnd(); ++option )
160  {
161  QDomElement optionElement = writeVariant( option.value(), doc );
162  optionElement.setAttribute( QStringLiteral( "name" ), option.key() );
163  element.appendChild( optionElement );
164  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "Map" ) );
165  }
166  break;
167  }
168 
169  case QVariant::List:
170  {
171  const QVariantList list = value.toList();
172 
173  const auto constList = list;
174  for ( const QVariant &value : constList )
175  {
176  const QDomElement valueElement = writeVariant( value, doc );
177  element.appendChild( valueElement );
178  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "List" ) );
179  }
180  break;
181  }
182 
183  case QVariant::StringList:
184  {
185  const QStringList list = value.toStringList();
186 
187  const auto constList = list;
188  for ( const QString &value : constList )
189  {
190  const QDomElement valueElement = writeVariant( value, doc );
191  element.appendChild( valueElement );
192  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "StringList" ) );
193  }
194  break;
195  }
196 
197  case QVariant::Int:
198  case QVariant::UInt:
199  case QVariant::Bool:
200  case QVariant::Double:
201  case QVariant::LongLong:
202  case QVariant::ULongLong:
203  case QVariant::String:
204  element.setAttribute( QStringLiteral( "type" ), QVariant::typeToName( value.type() ) );
205  element.setAttribute( QStringLiteral( "value" ), value.toString() );
206  break;
207 
208  case QVariant::Char:
209  element.setAttribute( QStringLiteral( "type" ), QVariant::typeToName( value.type() ) );
210  element.setAttribute( QStringLiteral( "value" ), QgsVariantUtils::isNull( value ) ? QString() : QString( value.toChar() ) );
211  break;
212 
213  case QVariant::Color:
214  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "color" ) );
215  element.setAttribute( QStringLiteral( "value" ), value.value< QColor >().isValid() ? QgsColorUtils::colorToString( value.value< QColor >() ) : QString() );
216  break;
217 
218  case QVariant::DateTime:
219  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "datetime" ) );
220  element.setAttribute( QStringLiteral( "value" ), value.value< QDateTime >().isValid() ? value.toDateTime().toString( Qt::ISODate ) : QString() );
221  break;
222 
223  case QVariant::Date:
224  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "date" ) );
225  element.setAttribute( QStringLiteral( "value" ), value.value< QDate >().isValid() ? value.toDate().toString( Qt::ISODate ) : QString() );
226  break;
227 
228  case QVariant::Time:
229  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "time" ) );
230  element.setAttribute( QStringLiteral( "value" ), value.value< QTime >().isValid() ? value.toTime().toString( Qt::ISODate ) : QString() );
231  break;
232 
233  case QVariant::UserType:
234  {
235  if ( value.userType() == QMetaType::type( "QgsProperty" ) )
236  {
237  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsProperty" ) );
238  const QDomElement propertyElem = QgsXmlUtils::writeVariant( value.value< QgsProperty >().toVariant(), doc );
239  element.appendChild( propertyElem );
240  break;
241  }
242  else if ( value.userType() == QMetaType::type( "QgsCoordinateReferenceSystem" ) )
243  {
244  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsCoordinateReferenceSystem" ) );
246  crs.writeXml( element, doc );
247  break;
248  }
249  else if ( value.userType() == QMetaType::type( "QgsGeometry" ) )
250  {
251  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsGeometry" ) );
252  const QgsGeometry geom = value.value< QgsGeometry >();
253  element.setAttribute( QStringLiteral( "value" ), geom.asWkt() );
254  break;
255  }
256  else if ( value.userType() == QMetaType::type( "QgsProcessingOutputLayerDefinition" ) )
257  {
258  const QDomElement valueElement = writeVariant( value.value< QgsProcessingOutputLayerDefinition >().toVariant(), doc );
259  element.appendChild( valueElement );
260  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsProcessingOutputLayerDefinition" ) );
261  break;
262  }
263  else if ( value.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
264  {
265  const QDomElement valueElement = writeVariant( value.value< QgsProcessingFeatureSourceDefinition >().toVariant(), doc );
266  element.appendChild( valueElement );
267  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsProcessingFeatureSourceDefinition" ) );
268  break;
269  }
270  else if ( value.userType() == QMetaType::type( "QgsRemappingSinkDefinition" ) )
271  {
272  const QDomElement valueElement = writeVariant( value.value< QgsRemappingSinkDefinition >().toVariant(), doc );
273  element.appendChild( valueElement );
274  element.setAttribute( QStringLiteral( "type" ), QStringLiteral( "QgsRemappingSinkDefinition" ) );
275  break;
276  }
277  Q_ASSERT_X( false, "QgsXmlUtils::writeVariant", QStringLiteral( "unsupported user variant type %1" ).arg( QMetaType::typeName( value.userType() ) ).toLocal8Bit() );
278  break;
279  }
280 
281  default:
282  Q_ASSERT_X( false, "QgsXmlUtils::writeVariant", QStringLiteral( "unsupported variant type %1" ).arg( QVariant::typeToName( value.type() ) ).toLocal8Bit() );
283  break;
284  }
285 
286  return element;
287 }
288 
289 QVariant QgsXmlUtils::readVariant( const QDomElement &element )
290 {
291  const QString type = element.attribute( QStringLiteral( "type" ) );
292 
293  if ( type == QLatin1String( "invalid" ) )
294  {
295  return QVariant();
296  }
297  else if ( type == QLatin1String( "int" ) )
298  {
299  return element.attribute( QStringLiteral( "value" ) ).toInt();
300  }
301  else if ( type == QLatin1String( "uint" ) )
302  {
303  return element.attribute( QStringLiteral( "value" ) ).toUInt();
304  }
305  else if ( type == QLatin1String( "qlonglong" ) )
306  {
307  return element.attribute( QStringLiteral( "value" ) ).toLongLong();
308  }
309  else if ( type == QLatin1String( "qulonglong" ) )
310  {
311  return element.attribute( QStringLiteral( "value" ) ).toULongLong();
312  }
313  else if ( type == QLatin1String( "double" ) )
314  {
315  return element.attribute( QStringLiteral( "value" ) ).toDouble();
316  }
317  else if ( type == QLatin1String( "QString" ) )
318  {
319  const QString res = element.attribute( QStringLiteral( "value" ) );
320  return res.isEmpty() ? QVariant() : res;
321  }
322  else if ( type == QLatin1String( "QChar" ) )
323  {
324  const QString res = element.attribute( QStringLiteral( "value" ) );
325  return res.isEmpty() ? QVariant() : res.at( 0 );
326  }
327  else if ( type == QLatin1String( "bool" ) )
328  {
329  return element.attribute( QStringLiteral( "value" ) ) == QLatin1String( "true" );
330  }
331  else if ( type == QLatin1String( "color" ) )
332  {
333  return element.attribute( QStringLiteral( "value" ) ).isEmpty() ? QVariant() : QgsColorUtils::colorFromString( element.attribute( QStringLiteral( "value" ) ) );
334  }
335  else if ( type == QLatin1String( "datetime" ) )
336  {
337  return element.attribute( QStringLiteral( "value" ) ).isEmpty() ? QVariant() : QDateTime::fromString( element.attribute( QStringLiteral( "value" ) ), Qt::ISODate );
338  }
339  else if ( type == QLatin1String( "date" ) )
340  {
341  return element.attribute( QStringLiteral( "value" ) ).isEmpty() ? QVariant() : QDate::fromString( element.attribute( QStringLiteral( "value" ) ), Qt::ISODate );
342  }
343  else if ( type == QLatin1String( "time" ) )
344  {
345  return element.attribute( QStringLiteral( "value" ) ).isEmpty() ? QVariant() : QTime::fromString( element.attribute( QStringLiteral( "value" ) ), Qt::ISODate );
346  }
347  else if ( type == QLatin1String( "Map" ) )
348  {
349  QVariantMap map;
350  const QDomNodeList options = element.childNodes();
351 
352  for ( int i = 0; i < options.count(); ++i )
353  {
354  const QDomElement elem = options.at( i ).toElement();
355  if ( elem.tagName() == QLatin1String( "Option" ) )
356  map.insert( elem.attribute( QStringLiteral( "name" ) ), readVariant( elem ) );
357  }
358  return map;
359  }
360  else if ( type == QLatin1String( "List" ) )
361  {
362  QVariantList list;
363  const QDomNodeList values = element.childNodes();
364  for ( int i = 0; i < values.count(); ++i )
365  {
366  const QDomElement elem = values.at( i ).toElement();
367  list.append( readVariant( elem ) );
368  }
369  return list;
370  }
371  else if ( type == QLatin1String( "StringList" ) )
372  {
373  QStringList list;
374  const QDomNodeList values = element.childNodes();
375  for ( int i = 0; i < values.count(); ++i )
376  {
377  const QDomElement elem = values.at( i ).toElement();
378  list.append( readVariant( elem ).toString() );
379  }
380  return list;
381  }
382  else if ( type == QLatin1String( "QgsProperty" ) )
383  {
384  const QDomNodeList values = element.childNodes();
385  if ( values.isEmpty() )
386  return QVariant();
387 
388  QgsProperty p;
389  if ( p.loadVariant( QgsXmlUtils::readVariant( values.at( 0 ).toElement() ) ) )
390  return p;
391 
392  return QVariant();
393  }
394  else if ( type == QLatin1String( "QgsCoordinateReferenceSystem" ) )
395  {
397  crs.readXml( element );
398  return crs.isValid() ? crs : QVariant();
399  }
400  else if ( type == QLatin1String( "QgsGeometry" ) )
401  {
402  const QgsGeometry g = QgsGeometry::fromWkt( element.attribute( "value" ) );
403  return !g.isNull() ? g : QVariant();
404  }
405  else if ( type == QLatin1String( "QgsProcessingOutputLayerDefinition" ) )
406  {
408  const QDomNodeList values = element.childNodes();
409  if ( values.isEmpty() )
410  return QVariant();
411 
412  if ( res.loadVariant( QgsXmlUtils::readVariant( values.at( 0 ).toElement() ).toMap() ) )
413  return res;
414 
415  return QVariant();
416  }
417  else if ( type == QLatin1String( "QgsProcessingFeatureSourceDefinition" ) )
418  {
420  const QDomNodeList values = element.childNodes();
421  if ( values.isEmpty() )
422  return QVariant();
423 
424  if ( res.loadVariant( QgsXmlUtils::readVariant( values.at( 0 ).toElement() ).toMap() ) )
425  return res;
426 
427  return QVariant();
428  }
429  else if ( type == QLatin1String( "QgsRemappingSinkDefinition" ) )
430  {
432  const QDomNodeList values = element.childNodes();
433  if ( values.isEmpty() )
434  return QVariant();
435 
436  if ( res.loadVariant( QgsXmlUtils::readVariant( values.at( 0 ).toElement() ).toMap() ) )
437  return QVariant::fromValue( res );
438 
439  return QVariant();
440  }
441  else
442  {
443  return QVariant();
444  }
445 }
DistanceUnit
Units of distance.
Definition: qgis.h:4090
@ Unknown
Unknown distance unit.
@ Degrees
Degrees, for planar geographic CRS distance measurements.
A 3-dimensional box composed of x, y, z coordinates.
Definition: qgsbox3d.h:43
double yMaximum() const
Returns the maximum y value.
Definition: qgsbox3d.h:197
void setZMinimum(double z)
Sets the minimum z value.
Definition: qgsbox3d.cpp:76
void setYMaximum(double y)
Sets the maximum y value.
Definition: qgsbox3d.cpp:71
void setZMaximum(double z)
Sets the maximum z value.
Definition: qgsbox3d.cpp:81
double xMinimum() const
Returns the minimum x value.
Definition: qgsbox3d.h:162
double zMaximum() const
Returns the maximum z value.
Definition: qgsbox3d.h:225
double xMaximum() const
Returns the maximum x value.
Definition: qgsbox3d.h:169
void setXMaximum(double x)
Sets the maximum x value.
Definition: qgsbox3d.cpp:61
void setYMinimum(double y)
Sets the minimum y value.
Definition: qgsbox3d.cpp:66
double zMinimum() const
Returns the minimum z value.
Definition: qgsbox3d.h:218
double yMinimum() const
Returns the minimum y value.
Definition: qgsbox3d.h:190
void setXMinimum(double x)
Sets the minimum x value.
Definition: qgsbox3d.cpp:56
static QColor colorFromString(const QString &string)
Decodes a string into a color value.
static QString colorToString(const QColor &color)
Encodes a color into a string value.
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
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:162
Q_GADGET bool isNull
Definition: qgsgeometry.h:164
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:228
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 xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:201
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:159
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:211
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:149
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:196
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:206
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:164
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:154
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 Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
static Q_INVOKABLE Qgis::DistanceUnit decodeDistanceUnit(const QString &string, bool *ok=nullptr)
Decodes a distance unit from a string.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
static QDomElement writeBox3D(const QgsBox3D &box, QDomDocument &doc, const QString &elementName=QStringLiteral("extent3D"))
Encodes a 3D box to a DOM element.
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
static QgsBox3D readBox3D(const QDomElement &element)
Decodes a DOM element to a 3D box.
Definition: qgsxmlutils.cpp:39
static QDomElement writeRectangle(const QgsRectangle &rect, QDomDocument &doc, const QString &elementName=QStringLiteral("extent"))
Encodes a rectangle to a DOM element.
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
static Qgis::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:64
static QDomElement writeMapUnits(Qgis::DistanceUnit units, QDomDocument &doc)
Encodes a distance unit to a DOM element.
Definition: qgsxmlutils.cpp:94
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:5089
const QgsCoordinateReferenceSystem & crs
const QString & typeName