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