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