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