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