MythTV  master
xsd.cpp
Go to the documentation of this file.
1 // Program Name: xsd.cpp
3 // Created : Feb. 20, 2012
4 //
5 // Purpose : XSD Generation Class
6 //
7 // Copyright (c) 2012 David Blain <dblain@mythtv.org>
8 //
9 // Licensed under the GPL v2 or later, see COPYING for details
10 //
12 
13 #include <QCoreApplication>
14 
15 #include "mythlogging.h"
16 #include "xsd.h"
17 
18 #include "servicehost.h"
19 
21 //
23 
24 bool Xsd::GetEnumXSD( HTTPRequest *pRequest, const QString& sEnumName )
25 {
26  if (sEnumName.isEmpty())
27  return false;
28 
29  // ----------------------------------------------------------------------
30  // sEnumName needs to be in class.enum format
31  // ----------------------------------------------------------------------
32 
33  if (sEnumName.count('.') != 1 )
34  return false;
35 
36  QStringList lstTypeParts = sEnumName.split( '.' );
37 
38  // ----------------------------------------------------------------------
39  // Create Parent object so we can get to its metaObject
40  // ----------------------------------------------------------------------
41 
42  QString sParentFQN = lstTypeParts[0];
43  int nParentId = QMetaType::type( sParentFQN.toUtf8() );
44 
45  // ----------------------------------------------------------------------
46  // Check for things that were formerly registered as both 'Foo' and 'Foo*'
47  // ----------------------------------------------------------------------
48  if (nParentId == QMetaType::UnknownType)
49  {
50  QString sFQN = sParentFQN + "*";
51  nParentId = QMetaType::type( sFQN.toUtf8() );
52  }
53 
54  // ----------------------------------------------------------------------
55  // if a DataContract type, we need to prefix name with DTC::
56  // These types are all pointers to objects, so we also need to add "*"
57  // ----------------------------------------------------------------------
58 
59  if (nParentId == QMetaType::UnknownType)
60  {
61  QString sFQN = "DTC::" + sParentFQN + "*";
62  nParentId = QMetaType::type( sFQN.toUtf8() );
63  }
64 
65  const QMetaObject *pMetaObject = QMetaType::metaObjectForType(nParentId);
66  if (pMetaObject == nullptr)
67  return false;
68 
69  // ----------------------------------------------------------------------
70  // Now look up enum
71  // ----------------------------------------------------------------------
72 
73  int nEnumIdx = pMetaObject->indexOfEnumerator( lstTypeParts[1].toUtf8() );
74 
75  if (nEnumIdx < 0 )
76  return false;
77 
78  QMetaEnum metaEnum = pMetaObject->enumerator( nEnumIdx );
79 
80  // ----------------------------------------------------------------------
81  // render xsd for this enum
82  //
83  // <xs:simpleType name="RecordingInfo.RecordingDupMethodEnum">
84  // <xs:restriction base="xs:string">
85  // <xs:enumeration value="kDupCheckNone">
86  // <xs:annotation>
87  // <xs:appinfo>
88  // <EnumerationValue xmlns="http://schemas.microsoft.com/2003/10/Serialization/">1</EnumerationValue>
89  // </xs:appinfo>
90  // </xs:annotation>
91  // </xs:enumeration>
92  // <xs:enumeration value="kDupCheckSub">
93  // <xs:annotation>
94  // <xs:appinfo>
95  // <EnumerationValue xmlns="http://schemas.microsoft.com/2003/10/Serialization/">2</EnumerationValue>
96  // </xs:appinfo>
97  // </xs:annotation>
98  // </xs:enumeration>
99  // </xs:restriction>
100  // </xs:simpleType>
101  //
102  // <xs:element name="RecordingInfo.RecordingDupMethodEnum" type="tns:RecordingInfo.RecordingDupMethodEnum" nillable="true"/>
103  // ----------------------------------------------------------------------
104 
105  if (!pRequest->m_mapParams.contains( "raw" ))
106  {
107  appendChild( createProcessingInstruction( "xml-stylesheet",
108  R"(type="text/xsl" href="/xslt/enum.xslt")" ));
109  }
110 
111  // ----------------------------------------------------------------------
112  // Create xs:simpleType structure
113  // ----------------------------------------------------------------------
114 
115  QDomElement oTypeNode = createElement( "xs:simpleType" );
116  QDomElement oRestrictNode = createElement( "xs:restriction" );
117 
118  oTypeNode .setAttribute( "name", sEnumName );
119  oRestrictNode.setAttribute( "base", "xs:string" );
120 
121  oTypeNode.appendChild( oRestrictNode );
122 
123  for( int nIdx = 0; nIdx < metaEnum.keyCount(); nIdx++)
124  {
125  QDomElement oEnum = createElement( "xs:enumeration" );
126 
127  oEnum.setAttribute( "value", metaEnum.key( nIdx ));
128 
129  // ------------------------------------------------------------------
130  // Add appInfo to store numerical value & translated text
131  // ------------------------------------------------------------------
132 
133  QDomElement oAnn = createElement( "xs:annotation" );
134  QDomElement oApp = createElement( "xs:appinfo" );
135  QDomElement oEnumVal = createElement( "EnumerationValue" );
136  QDomElement oEnumDesc = createElement( "EnumerationDesc" );
137 
138  // The following namespace is needed for visual studio to generate negative enums correctly.
139  oEnumVal.setAttribute("xmlns", "http://schemas.microsoft.com/2003/10/Serialization/");
140 
141  oEnum.appendChild( oAnn );
142  oAnn .appendChild( oApp );
143  oApp .appendChild( oEnumVal );
144  oApp .appendChild( oEnumDesc );
145 
146  QString sFQNKey = sEnumName + "." + metaEnum.key( nIdx );
147 
148  oEnumVal .appendChild( createTextNode( QString::number( metaEnum.value( nIdx ))));
149  oEnumDesc.appendChild( createTextNode( QCoreApplication::translate("Enums",
150  sFQNKey.toUtf8() )));
151 
152  oRestrictNode.appendChild( oEnum );
153  }
154 
155  // ----------------------------------------------------------------------
156 
157  QDomElement oElementNode = createElement( "xs:element" );
158 
159  oElementNode.setAttribute( "name" , sEnumName );
160  oElementNode.setAttribute( "type" , "tns:" + sEnumName );
161  oElementNode.setAttribute( "nillable", "true" );
162 
163  // ----------------------------------------------------------------------
164  //
165  // ----------------------------------------------------------------------
166 
167  QDomElement oRoot = CreateSchemaRoot();
168 
169  oRoot.appendChild( oTypeNode );
170  oRoot.appendChild( oElementNode );
171 
172  appendChild( oRoot );
173 
174  // ----------------------------------------------------------------------
175  // Return xsd doc to caller
176  // ----------------------------------------------------------------------
177 
178  QTextStream os( &(pRequest->m_response) );
179 
180  pRequest->m_eResponseType = ResponseTypeXML;
181 
182  save( os, 0 );
183 
184  return true;
185 }
186 
188 //
190 
191 bool Xsd::GetXSD( HTTPRequest *pRequest, QString sTypeName )
192 {
193  bool bIsArray = false;
194  bool bIsMap = false;
195 
196  if (sTypeName.isEmpty())
197  return false;
198 
199  // ----------------------------------------------------------------------
200  // Is this a special type name?
201  // ----------------------------------------------------------------------
202 
203  if (sTypeName.startsWith( "ArrayOf" ))
204  {
205  bIsArray = true;
206  sTypeName = sTypeName.mid( 7 );
207  }
208 
209  if (sTypeName.startsWith( "MapOfString" ))
210  {
211  bIsMap = true;
212  sTypeName = sTypeName.mid( 11 );
213  }
214 
215  // ----------------------------------------------------------------------
216  // Check to see if one of the Qt Types we need to handle special
217  // ----------------------------------------------------------------------
218 
219  int id = QMetaType::type( sTypeName.toUtf8() );
220 
221  // ----------------------------------------------------------------------
222  // Check for things that were formerly registered as both 'Foo' and 'Foo*'
223  // ----------------------------------------------------------------------
224  if (id == QMetaType::UnknownType)
225  {
226  QString sFQN = sTypeName + "*";
227  id = QMetaType::type( sFQN.toUtf8() );
228  }
229 
230  // ----------------------------------------------------------------------
231  // if a DataContract type, we need to prefix name with DTC::
232  // These types are all pointers to objects, so we also need to add "*"
233  // ----------------------------------------------------------------------
234 
235  if (id == QMetaType::UnknownType)
236  {
237  QString sFQN = "DTC::" + sTypeName + "*";
238  id = QMetaType::type( sFQN.toUtf8() );
239  }
240 
241  // ----------------------------------------------------------------------
242  //
243  // ----------------------------------------------------------------------
244 
245  if (!(bIsArray || bIsMap) && (id < QMetaType::User))
246  return false;
247 
248  // ------------------------------------------------------------------
249  // Need to create an instance of the class to access it's metadata.
250  // ------------------------------------------------------------------
251 
252  bool bHandled = false;
253 
254  // --------------------------------------------------------------
255  // Render XSD
256  // --------------------------------------------------------------
257 
258  if (!pRequest->m_mapParams.contains( "raw" ))
259  {
260  appendChild( createProcessingInstruction( "xml-stylesheet",
261  R"(type="text/xsl" href="/xslt/class.xslt")" ));
262  }
263 
264  if (bIsArray)
265  {
266  bHandled = RenderArrayXSD( pRequest, sTypeName, id >= QMetaType::User );
267  }
268  else if (bIsMap)
269  {
270  bHandled = RenderMapXSD( pRequest,
271  sTypeName,
272  id >= QMetaType::User );
273  }
274  else
275  {
276  const QMetaObject *pMetaObject = QMetaType::metaObjectForType(id);
277  if (pMetaObject)
278  {
279  QObject* pClass = pMetaObject->newInstance();
280  if (pClass != nullptr)
281  bHandled = RenderXSD( pRequest, pClass );
282  delete pClass;
283  }
284  }
285 
286  return bHandled;
287 
288 }
289 
291 //
292 //<?xml version="1.0" encoding="UTF-8"?>
293 //<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
294 // xmlns:tns="http://mythtv.org"
295 // targetNamespace="http://mythtv.org"
296 // elementFormDefault="qualified"
297 // attributeFormDefault="unqualified">
298 // <xs:include schemaLocation="<path to dependant schema"/>
299 //
300 // <xs:complexType name="<className>">
301 // <xs:annotation>
302 // <xs:documentation>Comment describing your root element</xs:documentation>
303 // </xs:annotation>
304 // <xs:sequence>
305 // <xs:element minOccurs="0" name="<propName>" type="<propType>"/>
306 // <xs:element minOccurs="0" name="<childName>" nillable="true" type="tns:<ChildType>"/>
307 // </xs:sequence>
308 // </xs:complexType>
309 // <xs:element name="<className>" nillable="true" type="tns:<className>"/>
310 //
311 //</xs:schema>
313 
314 bool Xsd::RenderXSD( HTTPRequest *pRequest, QObject *pClass )
315 {
316  const QMetaObject *pMetaObject = pClass->metaObject();
317 
318  QString sClassName = ConvertTypeToXSD( pMetaObject->className(), true);
319  QDomElement oRoot = CreateSchemaRoot();
320 
321  QMap<QString, TypeInfo> typesToInclude;
322 
323  // ------------------------------------------------------------------
324  // Create xs:complexType structure
325  // ------------------------------------------------------------------
326 
327  QDomElement oTypeNode = createElement( "xs:complexType" );
328  QDomElement oSeqNode = createElement( "xs:sequence" );
329 
330  oTypeNode.setAttribute( "name", sClassName );
331 
332  oTypeNode.appendChild( oSeqNode );
333 
334  // -=>TODO: Add an xs:annotation node with class descriptions
335 
336  // ------------------------------------------------------------------
337  // Add all properties for this type
338  //
339  // <xs:element minOccurs="0" name="<propName>" type="<propType>"/>
340  // <xs:element minOccurs="0" name="<childName>" nillable="true"
341  // type="tns:<ChildType>"/>
342  // ------------------------------------------------------------------
343 
344  int nCount = pMetaObject->propertyCount();
345 
346  for (int nIdx=0; nIdx < nCount; ++nIdx )
347  {
348  QMetaProperty metaProperty = pMetaObject->property( nIdx );
349 
350  if (metaProperty.isDesignable( pClass ))
351  {
352  const char *pszPropName = metaProperty.name();
353  QString sPropName( pszPropName );
354 
355  if ( sPropName.compare( "objectName" ) == 0)
356  continue;
357 
358  // ----------------------------------------------------------
359  // Create xs:element for this property
360  // ----------------------------------------------------------
361 
362  QDomElement oNode = createElement( "xs:element" );
363  QString sType = metaProperty.typeName();
364  bool bCustomType = false;
365  QString sCustomAttr = "type";
366  QString sContentName = QString();
367  QString sContentType = QString();
368 
369  LOG(VB_UPNP, LOG_DEBUG, QString( "Type: %1").arg( sType ));
370 
371  // if this is a child object, sType will be QObject*
372  // which we can't use, so we need to read the
373  // properties value, and read it's metaObject data
374 
375  if (sType == "QObject*")
376  {
377  QVariant val = metaProperty.read( pClass );
378  const QObject *pObject = val.value< QObject* >();
379 
380  sType = pObject->metaObject()->className();
381  bCustomType = true;
382  }
383  else if ((sType == "QVariantList" ) || (sType == "QVariantMap"))
384  {
385  sContentType = ReadPropertyMetadata( pClass,
386  sPropName,
387  "type" );
388 
389  if (sContentType.at(0) == 'Q')
390  sContentType = sContentType.mid( 1 );
391 
392  sContentType.remove( "DTC::" );
393  sContentType.remove( QChar('*') );
394 
395  if (sType == "QVariantMap")
396  {
397  sContentName = ReadPropertyMetadata( pClass,
398  sPropName,
399  "name" );
400 
401  if (sContentName.isEmpty())
402  sContentName = sContentType;
403 
404  sType = "MapOfString" + sContentName;
405  }
406  else
407  sType = "ArrayOf" + sContentType;
408 
409  bCustomType = true;
410 
411  }
412  else if (sType == "QStringList")
413  {
414  sType = "ArrayOfString";
415  bCustomType = true;
416  }
417  else if (IsEnum( metaProperty, sType ))
418  {
419  sCustomAttr = "enum";
420 
421  sType.remove( "DTC::" );
422 
423  // if sType still contains "::", then no need to prefix with sClassName
424 
425  if (sType.contains( "::" ))
426  sType = sType.replace( "::", "." );
427  else
428  sType = sClassName + "." + sType;
429 
430  bCustomType = true;
431  }
432 
433  QString sNewPropName( metaProperty.name() );
434 
435  if (IsNillable( sType ))
436  oNode.setAttribute( "nillable" , static_cast<int>(true) );
437 
438  if (bCustomType)
439  {
440  TypeInfo info = { sCustomAttr, sContentType };
441  typesToInclude.insert( sType, info );
442  }
443 
444  oNode.setAttribute( "type" , (bCustomType ? "tns:" : "xs:") +
445  ConvertTypeToXSD( sType, bCustomType ));
446 
447  oNode.setAttribute( "name" , sNewPropName );
448  oNode.setAttribute( "minOccurs", 0 );
449 
450  oSeqNode.appendChild( oNode );
451  }
452  }
453 
454  // ------------------------------------------------------------------
455  // Create element for class
456  //
457  // <xs:element name="<className>" nillable="true" type="tns:<className>"/>
458  // ------------------------------------------------------------------
459 
460  QDomElement oElementNode = createElement( "xs:element" );
461 
462  oElementNode.setAttribute( "type" , "tns:" + sClassName );
463  oElementNode.setAttribute( "nillable", "true" );
464  oElementNode.setAttribute( "name" , sClassName );
465 
466  // ----------------------------------------------------------------------
467  // Build xml tree...
468  // ----------------------------------------------------------------------
469 
470  appendChild( oRoot );
471 
472  if (typesToInclude.count() > 0)
473  {
474  // ------------------------------------------------------------------
475  // Create all needed includes
476  //
477  // <xs:include schemaLocation="<path to dependant schema"/>
478  // ------------------------------------------------------------------
479 
480  QString sBaseUri = "http://" + pRequest->m_mapHeaders[ "host" ] +
481  pRequest->m_sResourceUrl;
482 
483  QMap<QString, TypeInfo >::const_iterator it = typesToInclude.constBegin();
484  while( it != typesToInclude.constEnd())
485  {
486  QDomElement oIncNode = createElement( "xs:include" );
487  QString sType = it.key();
488 
489  sType.remove( "DTC::" );
490 
491  TypeInfo info = it.value();
492 
493  QString sValue = QString( "%1?%2=%3" ).arg( sBaseUri )
494  .arg( info.sAttrName )
495  .arg( sType );
496 
497  if (!info.sContentType.isEmpty())
498  sValue += "&name=" + info.sContentType;
499 
500  oIncNode.setAttribute( "schemaLocation", sValue );
501 
502  oRoot.appendChild( oIncNode );
503  ++it;
504  }
505  }
506 
507  oRoot.appendChild( oTypeNode );
508  oRoot.appendChild( oElementNode );
509 
510  // ----------------------------------------------------------------------
511  // Return xsd doc to caller
512  // ----------------------------------------------------------------------
513 
514  QTextStream os( &(pRequest->m_response) );
515 
516  pRequest->m_eResponseType = ResponseTypeXML;
517 
518  save( os, 0 );
519 
520  return true;
521 }
522 
523 bool Xsd::IsEnum( const QMetaProperty &metaProperty, const QString &/*sType*/ )
524 {
525  return (metaProperty.isEnumType() || metaProperty.isFlagType() );
526 }
527 
529 //
530 // ArrayOf<Type>
531 //
532 //<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://mythtv.org" targetNamespace="http://mythtv.org" elementFormDefault="qualified" attributeFormDefault="unqualified">
533 // <xs:include schemaLocation="<type>.xsd"/>
534 //
535 // <xs:complexType name="ArrayOf<Type>">
536 // <xs:annotation>
537 // <xs:documentation>Comment describing your root element</xs:documentation>
538 // </xs:annotation>
539 // <xs:sequence>
540 // <xs:element minOccurs="0" maxOccurs="unbounded" name="<type>" nillable="true" type="tns:<Type>"/>
541 // </xs:sequence>
542 // </xs:complexType>
543 // <xs:element name="ArrayOf<Type>" nillable="true" type="tns:ArrayOf<Type>"/>
544 //
545 //</xs:schema>
546 //
548 
550  const QString &sClassName,
551  bool bCustomType )
552 {
553  QString sArrayName = "ArrayOf" + sClassName;
554  QString sType;
555 
556  if (bCustomType)
557  sType = "tns:" + sClassName;
558  else
559  sType = "xs:" + ConvertTypeToXSD( sClassName, false );
560 
561  QDomElement oRoot = CreateSchemaRoot();
562 
563  // ------------------------------------------------------------------
564  // Create xs:complexType structure
565  // ------------------------------------------------------------------
566 
567  QDomElement oTypeNode = createElement( "xs:complexType" );
568  QDomElement oSeqNode = createElement( "xs:sequence" );
569 
570  // -=>TODO: Add an xs:annotation node with class descriptions
571 
572  oTypeNode.setAttribute( "name", sArrayName );
573  oTypeNode.appendChild( oSeqNode );
574 
575  QDomElement oNode = createElement( "xs:element" );
576 
577  oNode.setAttribute( "type" , sType );
578  oNode.setAttribute( "nillable" , "true" );
579  oNode.setAttribute( "name" , sClassName );
580  oNode.setAttribute( "maxOccurs" , "unbounded" );
581  oNode.setAttribute( "minOccurs" , "0" );
582 
583  oSeqNode.appendChild( oNode );
584 
585  // ----------------------------------------------------------------------
586  //
587  // ----------------------------------------------------------------------
588 
589  QDomElement oElementNode = createElement( "xs:element" );
590 
591  oElementNode.setAttribute( "type" , "tns:" + sArrayName );
592  oElementNode.setAttribute( "nillable", "true" );
593  oElementNode.setAttribute( "name" , sArrayName );
594 
595  // ----------------------------------------------------------------------
596  // Build xml tree...
597  // ----------------------------------------------------------------------
598 
599  appendChild( oRoot );
600 
601  if (bCustomType)
602  {
603  QDomElement oIncNode = createElement( "xs:include" );
604 
605  QString sBaseUri = "http://" + pRequest->m_mapHeaders[ "host" ] +
606  pRequest->m_sResourceUrl + "?type=";
607 
608  oIncNode.setAttribute( "schemaLocation", sBaseUri + sClassName );
609 
610  oRoot.appendChild( oIncNode );
611  }
612 
613  oRoot.appendChild( oTypeNode );
614  oRoot.appendChild( oElementNode );
615 
616  // ----------------------------------------------------------------------
617  // Return xsd doc to caller
618  // ----------------------------------------------------------------------
619 
620  QTextStream os( &(pRequest->m_response) );
621 
622  pRequest->m_eResponseType = ResponseTypeXML;
623 
624  save( os, 0 );
625 
626  return true;
627 
628 }
629 
631 //
632 // MapOfString<Type>
633 //
634 //<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://mythtv.org" targetNamespace="http://mythtv.org" elementFormDefault="qualified" attributeFormDefault="unqualified">
635 // <xs:include schemaLocation="<type>.xsd"/>
636 //
637 //<xs:complexType name="MapOfString<Type>">
638 // <xs:annotation>
639 // <xs:appinfo>
640 // <IsDictionary xmlns="http://schemas.microsoft.com/2003/10/Serialization/">true</IsDictionary>
641 // </xs:appinfo>
642 // </xs:annotation>
643 // <xs:sequence>
644 // <xs:element minOccurs="0" maxOccurs="unbounded" name="KeyValueOfString<Type>">
645 // <xs:complexType>
646 // <xs:sequence>
647 // <xs:element name="Key" nillable="true" type="xs:string" />
648 // <xs:element name="Value" nillable="true" type="<Type>" />
649 // </xs:sequence>
650 // </xs:complexType>
651 // </xs:element>
652 // </xs:sequence>
653 //</xs:complexType>
654 //<xs:element name="MapOfString<Type>" nillable="true" type="tns:MapOfString<Type>" />
655 //
656 //</xs:schema>
657 //
659 
661  const QString &sClassName,
662  bool bCustomType )
663 {
664  QString sArrayName = "MapOfString" + sClassName;
665  QString sMapItemName = pRequest->m_mapParams[ "name" ];
666  QString sType;
667 
668  if (sMapItemName.isEmpty())
669  sMapItemName = sClassName;
670 
671  if (bCustomType)
672  sType = "tns:" + sMapItemName;
673  else
674  sType = "xs:" + ConvertTypeToXSD( sMapItemName, false );
675 
676  QDomElement oRoot = CreateSchemaRoot();
677 
678  // ------------------------------------------------------------------
679  // Create xs:complexType structure
680  // ------------------------------------------------------------------
681 
682  QDomElement oTypeNode = createElement( "xs:complexType" );
683  QDomElement oSeqNode = createElement( "xs:sequence" );
684  QDomElement oAnno = createElement( "xs:annotation" );
685  QDomElement oAppInfo = createElement( "xs:appinfo" );
686 
687  QDomElement oNode = createElement( "IsDictionary" );
688  oNode.setAttribute( "xmlns", "http://schemas.microsoft.com/2003/10/Serialization/" );
689  oNode.appendChild( createTextNode( "true" ));
690 
691  oTypeNode.appendChild( oAnno );
692  oAnno .appendChild( oAppInfo );
693  oAppInfo .appendChild( oNode );
694 
695  // -=>TODO: Add an xs:annotation node with class descriptions
696 
697  // ----------------------------------------------------------------------
698  // <xs:sequence>
699  // ----------------------------------------------------------------------
700 
701  oTypeNode.setAttribute( "name", sArrayName );
702  oTypeNode.appendChild( oSeqNode );
703 
704  // ----------------------------------------------------------------------
705  // <xs:element minOccurs="0" maxOccurs="unbounded" name="KeyValueOfString<Type>">
706  // ----------------------------------------------------------------------
707 
708  QDomElement oInnerNode = createElement( "xs:element" );
709 
710  oInnerNode.setAttribute( "name" , sClassName );
711  oInnerNode.setAttribute( "maxOccurs" , "unbounded" );
712  oInnerNode.setAttribute( "minOccurs" , "0" );
713 
714  oSeqNode.appendChild( oInnerNode );
715 
716  // ----------------------------------------------------------------------
717  // <xs:complexType>
718  // ----------------------------------------------------------------------
719  oNode = createElement( "xs:complexType" );
720 
721  oInnerNode.appendChild( oNode );
722 
723  // ----------------------------------------------------------------------
724  // <xs:sequence>
725  // ----------------------------------------------------------------------
726 
727  QDomElement oInnerSeq = createElement( "xs:sequence" );
728 
729  oNode.appendChild( oInnerSeq );
730 
731  // ----------------------------------------------------------------------
732  // <xs:element name="Key" nillable="true" type="xs:string" />
733  // ----------------------------------------------------------------------
734 
735  oNode = createElement( "xs:element" );
736 
737  oNode.setAttribute( "type" , "xs:string" );
738  oNode.setAttribute( "nillable" , "true" );
739  oNode.setAttribute( "name" , "Key" );
740 
741  oInnerSeq.appendChild( oNode );
742 
743  // ----------------------------------------------------------------------
744  // <xs:element name="Value" nillable="true" type="<Type>" />
745  // ----------------------------------------------------------------------
746 
747  oNode = createElement( "xs:element" );
748 
749  oNode.setAttribute( "type" , sType );
750  oNode.setAttribute( "nillable" , "true" );
751  oNode.setAttribute( "name" , "Value" );
752 
753  oInnerSeq.appendChild( oNode );
754 
755  // ----------------------------------------------------------------------
756  //<xs:element name="MapOfString<Type>" nillable="true" type="tns:MapOfString<Type>" />
757  // ----------------------------------------------------------------------
758 
759  QDomElement oElementNode = createElement( "xs:element" );
760 
761  oElementNode.setAttribute( "type" , "tns:" + sArrayName );
762  oElementNode.setAttribute( "nillable", "true" );
763  oElementNode.setAttribute( "name" , sArrayName );
764 
765  // ----------------------------------------------------------------------
766  // Build xml tree...
767  // ----------------------------------------------------------------------
768 
769  appendChild( oRoot );
770 
771  if (bCustomType)
772  {
773  QDomElement oIncNode = createElement( "xs:include" );
774 
775  QString sBaseUri = "http://" + pRequest->m_mapHeaders[ "host" ] + pRequest->m_sResourceUrl + "?type=";
776 
777  oIncNode.setAttribute( "schemaLocation", sBaseUri + sClassName );
778 
779  oRoot.appendChild( oIncNode );
780  }
781 
782  oRoot.appendChild( oTypeNode );
783  oRoot.appendChild( oElementNode );
784 
785  // ----------------------------------------------------------------------
786  // Return xsd doc to caller
787  // ----------------------------------------------------------------------
788 
789  QTextStream os( &(pRequest->m_response) );
790 
791  pRequest->m_eResponseType = ResponseTypeXML;
792 
793  save( os, 0 );
794 
795  return true;
796 
797 }
798 
800 //
802 
804 {
805  QString sTargetNamespace = "http://mythtv.org";
806 
807  QDomElement oRoot = createElement( "xs:schema" );
808 
809  oRoot.setAttribute( "xmlns:xs" , "http://www.w3.org/2001/XMLSchema");
810  oRoot.setAttribute( "xmlns:tns" , sTargetNamespace );
811  oRoot.setAttribute( "targetNamespace" , sTargetNamespace );
812  oRoot.setAttribute( "elementFormDefault" , "qualified" );
813  oRoot.setAttribute( "attributeFormDefault", "unqualified" );
814  return oRoot;
815 }
816 
818 //
820 
821 bool Xsd::IsNillable( const QString &sType )
822 {
823  if (sType.startsWith( "DTC::"))
824  return true;
825 
826  if (sType == "QDateTime")
827  return true;
828 
829  if (sType == "QDate")
830  return true;
831 
832  if (sType == "QTime")
833  return true;
834 
835  return false;
836 }
837 
839 //
841 
842 QString Xsd::ConvertTypeToXSD( const QString &sType, bool bCustomType )
843 {
844  if (bCustomType || sType.startsWith( "DTC::"))
845  {
846  QString sTypeName( sType );
847 
848  sTypeName.remove( "DTC::" );
849  sTypeName.remove( QChar('*') );
850 
851  if (sType == "QStringList" )
852  return "ArrayOfString";
853 
854  return sTypeName;
855  }
856 
857  if (sType == "QDateTime")
858  return "dateTime";
859 
860  if (sType == "QDate")
861  return "date";
862 
863  if (sType == "QTime")
864  return "time";
865 
866  if (sType == "bool")
867  return "boolean";
868 
869  if (sType == "uint")
870  return "unsignedInt";
871 
872  if (sType == "qlonglong" )
873  return "long";
874 
875  if (sType == "long long" )
876  return "long";
877 
878  if (sType == "QFileInfo" )
879  return "string"; // temp solution
880 
881  if (sType.at(0) == 'Q')
882  return sType.mid( 1 ).toLower();
883 
884  return sType.toLower();
885 }
886 
888 //
890 
891 QString Xsd::ReadPropertyMetadata( QObject *pObject, const QString& sPropName, const QString& sKey )
892 {
893  const QMetaObject *pMeta = pObject->metaObject();
894 
895  int nIdx = -1;
896 
897  if (pMeta)
898  nIdx = pMeta->indexOfClassInfo( sPropName.toUtf8() );
899 
900  if (nIdx >=0)
901  {
902  QString sMetadata = pMeta->classInfo( nIdx ).value();
903  QStringList sOptions = sMetadata.split( ';' );
904 
905  QString sFullKey = sKey + "=";
906 
907  for (int nIdx2 = 0; nIdx2 < sOptions.size(); ++nIdx2)
908  {
909  if (sOptions.at( nIdx2 ).startsWith( sFullKey ))
910  return sOptions.at( nIdx2 ).mid( sFullKey.length() );
911  }
912  }
913 
914  return QString();
915 }
HTTPRequest
Definition: httprequest.h:108
xsd.h
Xsd::IsNillable
static bool IsNillable(const QString &sType)
Definition: xsd.cpp:821
HTTPRequest::m_sResourceUrl
QString m_sResourceUrl
Definition: httprequest.h:126
arg
arg(title).arg(filename).arg(doDelete))
TypeInfo
Definition: xsd.h:72
Xsd::RenderXSD
bool RenderXSD(HTTPRequest *pRequest, QObject *pClass)
Definition: xsd.cpp:314
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
Xsd::RenderArrayXSD
bool RenderArrayXSD(HTTPRequest *pRequest, const QString &sClassName, bool bCustomType)
Definition: xsd.cpp:549
Xsd::CreateSchemaRoot
QDomElement CreateSchemaRoot()
Definition: xsd.cpp:803
appendChild
root appendChild(channel)
TypeInfo::sAttrName
QString sAttrName
Definition: xsd.h:72
mythlogging.h
HTTPRequest::m_mapParams
QStringMap m_mapParams
Definition: httprequest.h:129
Xsd::RenderMapXSD
bool RenderMapXSD(HTTPRequest *pRequest, const QString &sClassName, bool bCustomType)
Definition: xsd.cpp:660
Xsd::ReadPropertyMetadata
static QString ReadPropertyMetadata(QObject *pObject, const QString &sPropName, const QString &sKey)
Definition: xsd.cpp:891
ResponseTypeXML
@ ResponseTypeXML
Definition: httprequest.h:76
Xsd::GetXSD
bool GetXSD(HTTPRequest *pRequest, QString sTypeName)
Definition: xsd.cpp:191
Xsd::ConvertTypeToXSD
static QString ConvertTypeToXSD(const QString &sType, bool bCustomType=false)
Definition: xsd.cpp:842
Xsd::IsEnum
static bool IsEnum(const QMetaProperty &metaProperty, const QString &sType)
Definition: xsd.cpp:523
HTTPRequest::m_eResponseType
HttpResponseType m_eResponseType
Definition: httprequest.h:147
Xsd::GetEnumXSD
bool GetEnumXSD(HTTPRequest *pRequest, const QString &sEnumName)
Definition: xsd.cpp:24
TypeInfo::sContentType
QString sContentType
Definition: xsd.h:72
HTTPRequest::m_mapHeaders
QStringMap m_mapHeaders
Definition: httprequest.h:130
servicehost.h
HTTPRequest::m_response
QBuffer m_response
Definition: httprequest.h:155