MythTV master
xmlSerializer.cpp
Go to the documentation of this file.
1
2// Program Name: xmlSerializer.cpp
3// Created : Dec. 30, 2009
4//
5// Purpose : Serialization Implementation for XML
6//
7// Copyright (c) 2005 David Blain <dblain@mythtv.org>
8//
9// Licensed under the GPL v2 or later, see LICENSE for details
10//
12
13#include "xmlSerializer.h"
15
16#include <utility>
17
18#include <QMetaClassInfo>
19
20// --------------------------------------------------------------------------
21// This version should be bumped if the serializer code is changed in a way
22// that changes the schema layout of the rendered XML.
23// --------------------------------------------------------------------------
24
25static constexpr const char* XML_SERIALIZER_VERSION { "1.1" };
26
28//
30
31XmlSerializer::XmlSerializer( QIODevice *pDevice, QString sRequestName )
32 : m_pXmlWriter(new QXmlStreamWriter( pDevice )),
33 m_sRequestName(std::move(sRequestName))
34{
35}
36
38//
40
42{
43 if (m_pXmlWriter != nullptr)
44 {
45 delete m_pXmlWriter;
46 m_pXmlWriter = nullptr;
47 }
48}
49
51//
53
55{
56 return "text/xml";
57}
58
60//
62
63void XmlSerializer::BeginSerialize( QString &/*sName*/ )
64{
65 m_pXmlWriter->writeStartDocument( "1.0" );
66// m_pXmlWriter->writeStartElement( m_sRequestName + "Response" );
67}
68
70//
72
74{
75 m_pXmlWriter->writeEndDocument();
76}
77
79//
81
82void XmlSerializer::BeginObject( const QString &sName, const QObject *pObject )
83{
84 m_pXmlWriter->writeStartElement( sName );
85
86 if (m_bIsRoot)
87 {
88 m_pXmlWriter->writeAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
89
90 m_bIsRoot = false;
91 }
92
93 const QMetaObject *pMeta = pObject->metaObject();
94
95 int nIdx = -1;
96
97 if (pMeta)
98 nIdx = pMeta->indexOfClassInfo( "version" );
99
100 if (nIdx >=0)
101 m_pXmlWriter->writeAttribute( "version", pMeta->classInfo( nIdx ).value() );
102
103 m_pXmlWriter->writeAttribute( "serializerVersion", XML_SERIALIZER_VERSION );
104
105}
106
108//
110
111void XmlSerializer::EndObject ( const QString &/*sName*/, const QObject */*pObject*/ )
112{
113 m_pXmlWriter->writeEndElement();
114}
115
117//
119
120void XmlSerializer::AddProperty( const QString &sName,
121 const QVariant &vValue,
122 const QMetaObject *pMetaParent,
123 const QMetaProperty *pMetaProp )
124{
125 m_pXmlWriter->writeStartElement( sName );
126
127 if ((pMetaProp != nullptr) &&
128 (pMetaProp->isEnumType() || pMetaProp->isFlagType()))
129 {
130 RenderEnum ( sName, vValue, pMetaProp );
131 }
132 else
133 {
134 RenderValue( GetContentName( sName, pMetaParent, pMetaProp ), vValue );
135 }
136
137 m_pXmlWriter->writeEndElement();
138}
139
141//
143
144void XmlSerializer::RenderEnum( const QString &/*sName*/ ,
145 const QVariant &vValue,
146 const QMetaProperty *pMetaProp )
147{
148 QString sValue;
149 QMetaEnum metaEnum = pMetaProp->enumerator();
150
151 if (pMetaProp->isFlagType())
152 sValue = metaEnum.valueToKeys( vValue.toInt() );
153 else
154 sValue = metaEnum.valueToKey ( vValue.toInt() );
155
156 // If couldn't convert to enum name, return raw value
157
158 if (sValue.isEmpty())
159 sValue = vValue.toString();
160
161 m_pXmlWriter->writeCharacters( sValue );
162
163}
164
166//
168
169void XmlSerializer::RenderValue( const QString &sName, const QVariant &vValue )
170{
171
172 // -----------------------------------------------------------------------
173 // See if this value is actually a QObject
174 // -----------------------------------------------------------------------
175
176 if ( vValue.canConvert< QObject* >())
177 {
178 const QObject *pObject = vValue.value< QObject* >();
179
180 SerializeObjectProperties( pObject );
181 return;
182 }
183
184 // -----------------------------------------------------------------------
185 // Handle QVariant special cases...
186 // -----------------------------------------------------------------------
187
188#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
189 auto type = static_cast<QMetaType::Type>(vValue.type());
190#else
191 auto type = vValue.typeId();
192#endif
193 switch( type )
194 {
195 case QMetaType::QVariantList:
196 {
197 RenderList( sName, vValue.toList() );
198 break;
199 }
200
201 case QMetaType::QStringList:
202 {
203 RenderStringList( sName, vValue.toStringList() );
204 break;
205 }
206
207 case QMetaType::QVariantMap:
208 {
209 RenderMap( sName, vValue.toMap() );
210 break;
211 }
212
213 case QMetaType::QDateTime:
214 {
215 QDateTime dt( vValue.toDateTime() );
216
217 if (dt.isNull())
218 m_pXmlWriter->writeAttribute( "xsi:nil", "true" );
219
220 m_pXmlWriter->writeCharacters(
222
223 break;
224 }
225
226 default:
227 {
228 m_pXmlWriter->writeCharacters( vValue.toString() );
229 break;
230 }
231 }
232
233}
234
236//
238
239void XmlSerializer::RenderList( const QString &sName, const QVariantList &list )
240{
241// QString sItemName;
242
243 QListIterator< QVariant > it( list );
244
245 while (it.hasNext())
246 {
247 QVariant vValue = it.next();
248
249// if (sItemName.isEmpty())
250// sItemName = GetItemName( QMetaType::typeName( vValue.userType() ) );
251
252 m_pXmlWriter->writeStartElement( sName );
253 RenderValue( sName, vValue );
254 m_pXmlWriter->writeEndElement();
255 }
256}
257
259//
261
262void XmlSerializer::RenderStringList( const QString &/*sName*/, const QStringList &list )
263{
264 QListIterator< QString > it( list );
265
266 while (it.hasNext())
267 {
268 m_pXmlWriter->writeStartElement( "String" );
269 m_pXmlWriter->writeCharacters ( it.next() );
270 m_pXmlWriter->writeEndElement();
271 }
272}
273
275//
277
278void XmlSerializer::RenderMap( const QString &sName, const QVariantMap &map )
279{
280
281 QMapIterator< QString, QVariant > it( map );
282
283 QString sItemName = GetItemName( sName );
284
285 while (it.hasNext())
286 {
287 it.next();
288
289 m_pXmlWriter->writeStartElement( sItemName );
290
291 m_pXmlWriter->writeStartElement( "Key" );
292 m_pXmlWriter->writeCharacters( it.key() );
293 m_pXmlWriter->writeEndElement();
294
295 m_pXmlWriter->writeStartElement( "Value" );
296 RenderValue( sItemName, it.value() );
297 m_pXmlWriter->writeEndElement();
298
299/*
300 m_pXmlWriter->writeAttribute ( "key", it.key() );
301 RenderValue( sItemName, it.value() );
302 //m_pXmlWriter->writeCharacters ( it.value().toString() );
303*/
304 m_pXmlWriter->writeEndElement();
305 }
306}
307
309// -=>TODO: There should be a better way to handle this...
310// boy do I miss C#'s Custom Attributes... maybe leverage MOC somehow
312
313QString XmlSerializer::GetItemName( const QString &sName )
314{
315 QString sTypeName( sName );
316
317 if ((sName.length() > 0) && (sName.at(0) == 'Q'))
318 sTypeName = sName.mid( 1 );
319
320 sTypeName.remove( "DTC::" );
321 sTypeName.remove( QChar('*') );
322
323 return sTypeName;
324}
325
327//
329
330QString XmlSerializer::GetContentName( const QString &sName,
331 const QMetaObject *pMetaObject,
332 const QMetaProperty */*pMetaProp*/ )
333{
334 // Try to read Name or TypeName from classinfo metadata.
335
336 int nClassIdx = -1;
337
338 if ( pMetaObject )
339 nClassIdx = pMetaObject->indexOfClassInfo( sName.toLatin1() );
340
341 if (nClassIdx >=0 )
342 {
343 QString sOptionData = pMetaObject->classInfo( nClassIdx ).value();
344 QStringList sOptions = sOptionData.split( ';' );
345
346 QString sNameOption = FindOptionValue( sOptions, "name" );
347
348 if (sNameOption.isEmpty())
349 sNameOption = FindOptionValue( sOptions, "type" );
350
351 if (!sNameOption.isEmpty())
352 return GetItemName( sNameOption );
353 }
354
355 // Neither found, so lets use the type name (slightly modified).
356
357 QString sTypeName( sName );
358
359 if ((sName.length() > 0) && (sName.at(0) == 'Q'))
360 sTypeName = sName.mid( 1 );
361
362 sTypeName.remove( "DTC::" );
363 sTypeName.remove( QChar('*') );
364
365 return sTypeName;
366}
367
369//
371
372QString XmlSerializer::FindOptionValue( const QStringList &sOptions, const QString &sName )
373{
374 QString sKey = sName + "=";
375
376 auto hasKey = [&sKey](const QString& o) { return o.startsWith( sKey ); };
377 auto it = std::find_if(sOptions.cbegin(), sOptions.cend(), hasKey);
378 if (it != sOptions.cend())
379 return (*it).mid( sKey.length() );
380
381 return {};
382}
void SerializeObjectProperties(const QObject *pObject)
Definition: serializer.cpp:103
void AddProperty(const QString &sName, const QVariant &vValue, const QMetaObject *pMetaParent, const QMetaProperty *pMetaProp) override
static QString GetContentName(const QString &sName, const QMetaObject *pMetaObject, const QMetaProperty *pMetaProp)
QXmlStreamWriter * m_pXmlWriter
Definition: xmlSerializer.h:37
void RenderEnum(const QString &sName, const QVariant &vValue, const QMetaProperty *pMetaProp)
void RenderMap(const QString &sName, const QVariantMap &map)
void EndObject(const QString &sName, const QObject *pObject) override
QString GetContentType() override
static QString FindOptionValue(const QStringList &sOptions, const QString &sName)
void RenderValue(const QString &sName, const QVariant &vValue)
static QString GetItemName(const QString &sName)
void BeginSerialize(QString &sName) override
virtual ~XmlSerializer()
void EndSerialize() override
XmlSerializer(QIODevice *pDevice, QString sRequestName)
void RenderStringList(const QString &sName, const QStringList &list)
void RenderList(const QString &sName, const QVariantList &list)
void BeginObject(const QString &sName, const QObject *pObject) override
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
STL namespace.
static constexpr const char * XML_SERIALIZER_VERSION