MythTV  master
mythxmlserialiser.cpp
Go to the documentation of this file.
1 // Qt
2 #include <QMetaProperty>
3 #include <QSequentialIterable>
4 
5 // MythTV
6 #include "mythdate.h"
7 #include "http/mythhttpdata.h"
9 
10 MythXMLSerialiser::MythXMLSerialiser(const QString& Name, const QVariant& Value)
11 {
12  m_writer.setDevice(&m_buffer);
13  m_writer.writeStartDocument("1.0");
14  QString name = Name;
15  if (name.startsWith("V2"))
16  name.remove(0,2);
17  AddObject(name, Value);
18  m_writer.writeEndDocument();
19 }
20 
21 void MythXMLSerialiser::AddObject(const QString& Name, const QVariant& Value)
22 {
23  m_writer.writeStartElement(Name);
24  if (m_first)
25  {
26  m_writer.writeAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
27  m_writer.writeAttribute("serializerVersion", XML_SERIALIZER_VERSION);
28  m_first = false;
29  }
30  auto * object = Value.value<QObject*>();
31  AddValue(object ? GetContentName(Name, object->metaObject()) : Name, Value);
32  m_writer.writeEndElement();
33 }
34 
35 void MythXMLSerialiser::AddValue(const QString& Name, const QVariant& Value)
36 {
37  if (Value.isNull() || !Value.isValid())
38  {
39  m_writer.writeAttribute("xsi:nil", "true");
40  return;
41  }
42 
43  auto * object = Value.value<QObject*>();
44  if (object)
45  {
46  QVariant isNull = object->property("isNull");
47  if (isNull.value<bool>())
48  return;
49  AddQObject(object);
50  return;
51  }
52 
53  switch (
54 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
55  static_cast<QMetaType::Type>(Value.type())
56 #else
57  static_cast<QMetaType::Type>(Value.typeId())
58 #endif
59  )
60  {
61  case QMetaType::QStringList: AddStringList(Value); break;
62  case QMetaType::QVariantList: AddList(Name, Value); break;
63  case QMetaType::QVariantMap: AddMap(Name, Value.toMap()); break;
64  case QMetaType::QDateTime:
65  {
66  QDateTime dt(Value.toDateTime());
67  if (dt.isNull())
68  m_writer.writeAttribute("xsi:nil", "true");
69  else
70  m_writer.writeCharacters(MythDate::toString(dt, MythDate::ISODate));
71  }
72  break;
73  case QMetaType::Double:
74  m_writer.writeCharacters(QString::number(Value.toDouble(),'f',6));
75  break;
76  case QMetaType::Float:
77  m_writer.writeCharacters(QString::number(Value.toFloat(),'f',6));
78  break;
79  default:
80  m_writer.writeCharacters(Value.toString());
81  }
82 }
83 
84 void MythXMLSerialiser::AddQObject(const QObject* Object)
85 {
86  if (!Object)
87  return;
88 
89  const auto * meta = Object->metaObject();
90  if (int index = meta->indexOfClassInfo("Version"); index >= 0)
91  m_writer.writeAttribute("version", meta->classInfo(index).value());
92 
93  int count = meta->propertyCount();
94  for (int index = 0; index < count; ++index )
95  {
96  QMetaProperty metaproperty = meta->property(index);
97  if (
98 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
99  metaproperty.isUser(Object)
100 #else
101  metaproperty.isUser()
102 #endif
103  )
104  {
105  const char *rawname = metaproperty.name();
106  QString name(rawname);
107  if (name.compare("objectName") == 0)
108  continue;
109  QVariant value(Object->property(rawname));
110  m_writer.writeStartElement(name);
111  AddProperty(name, value, meta, &metaproperty);
112  m_writer.writeEndElement();
113  }
114  }
115 }
116 
117 void MythXMLSerialiser::AddProperty(const QString& Name, const QVariant& Value,
118  const QMetaObject* MetaObject, const QMetaProperty *MetaProperty)
119 {
120  // Enum ?
121  if (MetaProperty && (MetaProperty->isEnumType() || MetaProperty->isFlagType()))
122  {
123  QMetaEnum metaEnum = MetaProperty->enumerator();
124  QString value = MetaProperty->isFlagType() ? metaEnum.valueToKeys(Value.toInt()).constData() :
125  metaEnum.valueToKey(Value.toInt());
126  // If couldn't convert to enum name, return raw value
127  m_writer.writeCharacters(value.isEmpty() ? Value.toString() : value);
128  return;
129  }
130 
131  AddValue(GetContentName(Name, MetaObject), Value);
132 }
133 
134 void MythXMLSerialiser::AddStringList(const QVariant& Values)
135 {
136  auto values = Values.value<QSequentialIterable>();
137  for (const auto & value : values)
138  {
139  m_writer.writeStartElement("String");
140  m_writer.writeCharacters(value.toString());
141  m_writer.writeEndElement();
142  }
143 }
144 
145 void MythXMLSerialiser::AddList(const QString& Name, const QVariant& Values)
146 {
147  auto values = Values.value<QSequentialIterable>();
148  for (const auto & value : values)
149  {
150  m_writer.writeStartElement(Name);
151  AddValue(Name, value);
152  m_writer.writeEndElement();
153  }
154 }
155 
156 void MythXMLSerialiser::AddMap(const QString& Name, const QVariantMap& Map)
157 {
158  QString itemname = GetItemName(Name);
159  for (auto it = Map.cbegin(); it != Map.cend(); ++it)
160  {
161  m_writer.writeStartElement(itemname);
162  m_writer.writeStartElement("Key");
163  m_writer.writeCharacters(it.key());
164  m_writer.writeEndElement();
165  m_writer.writeStartElement("Value");
166  AddValue(itemname, it.value());
167  m_writer.writeEndElement();
168  m_writer.writeEndElement();
169  }
170 }
171 
172 QString MythXMLSerialiser::GetItemName(const QString& Name)
173 {
174  QString name = Name.startsWith("Q") ? Name.mid(1) : Name;
175  if (name.startsWith("V2"))
176  name.remove(0,2);
177  name.remove(QChar('*'));
178  return name;
179 }
180 
182 QString MythXMLSerialiser::GetContentName(const QString& Name, const QMetaObject* MetaObject)
183 {
184  // Try to read Name or TypeName from classinfo metadata.
185  if (int index = MetaObject ? MetaObject->indexOfClassInfo(Name.toLatin1()) : -1; index >= 0)
186  {
187  QStringList infos = QString(MetaObject->classInfo(index).value()).split(';', Qt::SkipEmptyParts);
188  QString type; // fallback
189  foreach (const QString &info, infos)
190  {
191  if (info.startsWith(QStringLiteral("name=")))
192  if (auto name = info.mid(5).trimmed(); !name.isEmpty())
193  return GetItemName(name);
194  if (info.startsWith(QStringLiteral("type=")))
195  type = info.mid(5).trimmed();
196  }
197  if (!type.isEmpty())
198  return GetItemName(type);
199  }
200 
201  // Neither found, so lets use the type name (slightly modified).
202  return GetItemName(Name);
203 }
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:84
MythXMLSerialiser::AddValue
void AddValue(const QString &Name, const QVariant &Value)
Definition: mythxmlserialiser.cpp:35
MythXMLSerialiser::GetContentName
static QString GetContentName(const QString &Name, const QMetaObject *MetaObject)
FIXME We shouldn't be doing this on the fly.
Definition: mythxmlserialiser.cpp:182
MythXMLSerialiser::AddObject
void AddObject(const QString &Name, const QVariant &Value)
Definition: mythxmlserialiser.cpp:21
MythSerialiser::m_buffer
QBuffer m_buffer
Definition: mythserialiser.h:22
mythhttpdata.h
mythxmlserialiser.h
mythdate.h
MythXMLSerialiser::AddQObject
void AddQObject(const QObject *Object)
Definition: mythxmlserialiser.cpp:84
MythXMLSerialiser::GetItemName
static QString GetItemName(const QString &Name)
Definition: mythxmlserialiser.cpp:172
MythXMLSerialiser::AddMap
void AddMap(const QString &Name, const QVariantMap &Map)
Definition: mythxmlserialiser.cpp:156
MythXMLSerialiser::m_writer
QXmlStreamWriter m_writer
Definition: mythxmlserialiser.h:31
MythXMLSerialiser::AddList
void AddList(const QString &Name, const QVariant &Values)
Definition: mythxmlserialiser.cpp:145
Name
Definition: channelsettings.cpp:71
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
MythXMLSerialiser::AddProperty
void AddProperty(const QString &Name, const QVariant &Value, const QMetaObject *MetaObject, const QMetaProperty *MetaProperty)
Definition: mythxmlserialiser.cpp:117
XML_SERIALIZER_VERSION
#define XML_SERIALIZER_VERSION
Definition: mythxmlserialiser.h:10
MythXMLSerialiser::m_first
bool m_first
Definition: mythxmlserialiser.h:32
MythXMLSerialiser::AddStringList
void AddStringList(const QVariant &Values)
Definition: mythxmlserialiser.cpp:134
MythXMLSerialiser::MythXMLSerialiser
MythXMLSerialiser(const QString &Name, const QVariant &Value)
Definition: mythxmlserialiser.cpp:10