13 #include <QCoreApplication>
27 if (sEnumName.isEmpty())
34 if (sEnumName.count(
'.') != 1 )
37 QStringList lstTypeParts = sEnumName.split(
'.' );
43 const QString& sParentFQN = lstTypeParts[0];
44 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
50 if (nParentId == QMetaType::UnknownType)
52 QString sFQN = sParentFQN +
"*";
61 if (nParentId == QMetaType::UnknownType)
63 QString sFQN =
"DTC::" + sParentFQN +
"*";
67 const QMetaObject *pMetaObject = QMetaType::metaObjectForType(nParentId);
69 QMetaType metaType = QMetaType::fromName( sParentFQN.toUtf8() );
70 if (metaType.id() == QMetaType::UnknownType)
71 metaType = QMetaType::fromName( sParentFQN.toUtf8() +
"*" );
72 if (metaType.id() == QMetaType::UnknownType)
73 metaType = QMetaType::fromName(
"DTC::" + sParentFQN.toUtf8() +
"*" );
74 if (metaType.id() == QMetaType::UnknownType)
76 const QMetaObject *pMetaObject = metaType.metaObject();
79 if (pMetaObject ==
nullptr)
86 int nEnumIdx = pMetaObject->indexOfEnumerator( lstTypeParts[1].toUtf8() );
91 QMetaEnum metaEnum = pMetaObject->enumerator( nEnumIdx );
120 appendChild( createProcessingInstruction(
"xml-stylesheet",
121 R
"(type="text/xsl" href="/xslt/enum.xslt")" ));
128 QDomElement oTypeNode = createElement(
"xs:simpleType" );
129 QDomElement oRestrictNode = createElement(
"xs:restriction" );
131 oTypeNode .setAttribute(
"name", sEnumName );
132 oRestrictNode.setAttribute(
"base",
"xs:string" );
134 oTypeNode.appendChild( oRestrictNode );
136 for(
int nIdx = 0; nIdx < metaEnum.keyCount(); nIdx++)
138 QDomElement oEnum = createElement(
"xs:enumeration" );
140 oEnum.setAttribute(
"value", metaEnum.key( nIdx ));
146 QDomElement oAnn = createElement(
"xs:annotation" );
147 QDomElement oApp = createElement(
"xs:appinfo" );
148 QDomElement oEnumVal = createElement(
"EnumerationValue" );
149 QDomElement oEnumDesc = createElement(
"EnumerationDesc" );
152 oEnumVal.setAttribute(
"xmlns",
"http://schemas.microsoft.com/2003/10/Serialization/");
154 oEnum.appendChild( oAnn );
155 oAnn .appendChild( oApp );
156 oApp .appendChild( oEnumVal );
157 oApp .appendChild( oEnumDesc );
159 QString sFQNKey = sEnumName +
"." + metaEnum.key( nIdx );
161 oEnumVal .appendChild( createTextNode( QString::number( metaEnum.value( nIdx ))));
162 oEnumDesc.appendChild( createTextNode( QCoreApplication::translate(
"Enums",
163 sFQNKey.toUtf8() )));
165 oRestrictNode.appendChild( oEnum );
170 QDomElement oElementNode = createElement(
"xs:element" );
172 oElementNode.setAttribute(
"name" , sEnumName );
173 oElementNode.setAttribute(
"type" ,
"tns:" + sEnumName );
174 oElementNode.setAttribute(
"nillable",
"true" );
182 oRoot.appendChild( oTypeNode );
183 oRoot.appendChild( oElementNode );
185 appendChild( oRoot );
206 bool bIsArray =
false;
209 if (sTypeName.isEmpty())
216 if (sTypeName.startsWith(
"ArrayOf" ))
219 sTypeName = sTypeName.mid( 7 );
222 if (sTypeName.startsWith(
"MapOfString" ))
225 sTypeName = sTypeName.mid( 11 );
232 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
238 if (
id == QMetaType::UnknownType)
240 QString sFQN = sTypeName +
"*";
249 if (
id == QMetaType::UnknownType)
251 QString sFQN =
"DTC::" + sTypeName +
"*";
255 QMetaType metaType = QMetaType::fromName( sTypeName.toUtf8() );
256 if (metaType.id() == QMetaType::UnknownType)
257 metaType = QMetaType::fromName( sTypeName.toUtf8() +
"*" );
258 if (metaType.id() == QMetaType::UnknownType)
259 metaType = QMetaType::fromName(
"DTC::" + sTypeName.toUtf8() +
"*" );
260 if (metaType.id() == QMetaType::UnknownType)
262 int id = metaType.id();
269 if (!(bIsArray || bIsMap) && (
id < QMetaType::User))
276 bool bHandled =
false;
284 appendChild( createProcessingInstruction(
"xml-stylesheet",
285 R
"(type="text/xsl" href="/xslt/class.xslt")" ));
290 bHandled =
RenderArrayXSD( pRequest, sTypeName,
id >= QMetaType::User );
296 id >= QMetaType::User );
300 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
301 const QMetaObject *pMetaObject = QMetaType::metaObjectForType(
id);
303 const QMetaObject *pMetaObject = metaType.metaObject();
307 QObject* pClass = pMetaObject->newInstance();
308 if (pClass !=
nullptr)
309 bHandled =
RenderXSD( pRequest, pClass );
344 const QMetaObject *pMetaObject = pClass->metaObject();
349 QMap<QString, TypeInfo> typesToInclude;
355 QDomElement oTypeNode = createElement(
"xs:complexType" );
356 QDomElement oSeqNode = createElement(
"xs:sequence" );
358 oTypeNode.setAttribute(
"name", sClassName );
360 oTypeNode.appendChild( oSeqNode );
372 int nCount = pMetaObject->propertyCount();
374 for (
int nIdx=0; nIdx < nCount; ++nIdx )
376 QMetaProperty metaProperty = pMetaObject->property( nIdx );
378 if (metaProperty.isDesignable())
380 const char *pszPropName = metaProperty.name();
381 QString sPropName( pszPropName );
383 if ( sPropName.compare(
"objectName" ) == 0)
390 QDomElement oNode = createElement(
"xs:element" );
391 QString sType = metaProperty.typeName();
392 bool bCustomType =
false;
393 QString sCustomAttr =
"type";
394 QString sContentName = QString();
395 QString sContentType = QString();
397 LOG(VB_UPNP, LOG_DEBUG, QString(
"Type: %1").arg( sType ));
403 if (sType ==
"QObject*")
405 QVariant val = metaProperty.read( pClass );
406 const QObject *pObject = val.value< QObject* >();
408 sType = pObject->metaObject()->className();
411 else if ((sType ==
"QVariantList" ) || (sType ==
"QVariantMap"))
417 if (sContentType.startsWith(
'Q'))
418 sContentType = sContentType.mid( 1 );
420 sContentType.remove(
"DTC::" );
421 sContentType.remove( QChar(
'*') );
423 if (sType ==
"QVariantMap")
429 if (sContentName.isEmpty())
430 sContentName = sContentType;
432 sType =
"MapOfString" + sContentName;
436 sType =
"ArrayOf" + sContentType;
442 else if (sType ==
"QStringList")
444 sType =
"ArrayOfString";
447 else if (
IsEnum( metaProperty, sType ))
449 sCustomAttr =
"enum";
451 sType.remove(
"DTC::" );
455 if (sType.contains(
"::" ))
456 sType = sType.replace(
"::",
"." );
458 sType = sClassName +
"." + sType;
463 QString sNewPropName( metaProperty.name() );
466 oNode.setAttribute(
"nillable" ,
static_cast<int>(
true) );
471 typesToInclude.insert( sType,
info );
474 oNode.setAttribute(
"type" , (bCustomType ?
"tns:" :
"xs:") +
477 oNode.setAttribute(
"name" , sNewPropName );
478 oNode.setAttribute(
"minOccurs", 0 );
480 oSeqNode.appendChild( oNode );
490 QDomElement oElementNode = createElement(
"xs:element" );
492 oElementNode.setAttribute(
"type" ,
"tns:" + sClassName );
493 oElementNode.setAttribute(
"nillable",
"true" );
494 oElementNode.setAttribute(
"name" , sClassName );
500 appendChild( oRoot );
502 if (typesToInclude.count() > 0)
510 QString sBaseUri =
"http://" + pRequest->
GetLastHeader(
"host" ) +
513 QMap<QString, TypeInfo >::const_iterator it = typesToInclude.constBegin();
514 while( it != typesToInclude.constEnd())
516 QDomElement oIncNode = createElement(
"xs:include" );
517 QString sType = it.key();
519 sType.remove(
"DTC::" );
523 QString sValue = QString(
"%1?%2=%3" ).arg( sBaseUri,
527 if (!
info.sContentType.isEmpty())
528 sValue +=
"&name=" +
info.sContentType;
530 oIncNode.setAttribute(
"schemaLocation", sValue );
532 oRoot.appendChild( oIncNode );
537 oRoot.appendChild( oTypeNode );
538 oRoot.appendChild( oElementNode );
553 bool Xsd::IsEnum(
const QMetaProperty &metaProperty,
const QString & )
555 return (metaProperty.isEnumType() || metaProperty.isFlagType() );
580 const QString &sClassName,
583 QString sArrayName =
"ArrayOf" + sClassName;
587 sType =
"tns:" + sClassName;
597 QDomElement oTypeNode = createElement(
"xs:complexType" );
598 QDomElement oSeqNode = createElement(
"xs:sequence" );
602 oTypeNode.setAttribute(
"name", sArrayName );
603 oTypeNode.appendChild( oSeqNode );
605 QDomElement oNode = createElement(
"xs:element" );
607 oNode.setAttribute(
"type" , sType );
608 oNode.setAttribute(
"nillable" ,
"true" );
609 oNode.setAttribute(
"name" , sClassName );
610 oNode.setAttribute(
"maxOccurs" ,
"unbounded" );
611 oNode.setAttribute(
"minOccurs" ,
"0" );
613 oSeqNode.appendChild( oNode );
619 QDomElement oElementNode = createElement(
"xs:element" );
621 oElementNode.setAttribute(
"type" ,
"tns:" + sArrayName );
622 oElementNode.setAttribute(
"nillable",
"true" );
623 oElementNode.setAttribute(
"name" , sArrayName );
629 appendChild( oRoot );
633 QDomElement oIncNode = createElement(
"xs:include" );
635 QString sBaseUri =
"http://" + pRequest->
GetLastHeader(
"host" ) +
638 oIncNode.setAttribute(
"schemaLocation", sBaseUri + sClassName );
640 oRoot.appendChild( oIncNode );
643 oRoot.appendChild( oTypeNode );
644 oRoot.appendChild( oElementNode );
691 const QString &sClassName,
694 QString sArrayName =
"MapOfString" + sClassName;
695 QString sMapItemName = pRequest->
m_mapParams[
"name" ];
698 if (sMapItemName.isEmpty())
699 sMapItemName = sClassName;
702 sType =
"tns:" + sMapItemName;
712 QDomElement oTypeNode = createElement(
"xs:complexType" );
713 QDomElement oSeqNode = createElement(
"xs:sequence" );
714 QDomElement oAnno = createElement(
"xs:annotation" );
715 QDomElement oAppInfo = createElement(
"xs:appinfo" );
717 QDomElement oNode = createElement(
"IsDictionary" );
718 oNode.setAttribute(
"xmlns",
"http://schemas.microsoft.com/2003/10/Serialization/" );
719 oNode.appendChild( createTextNode(
"true" ));
721 oTypeNode.appendChild( oAnno );
722 oAnno .appendChild( oAppInfo );
723 oAppInfo .appendChild( oNode );
731 oTypeNode.setAttribute(
"name", sArrayName );
732 oTypeNode.appendChild( oSeqNode );
738 QDomElement oInnerNode = createElement(
"xs:element" );
740 oInnerNode.setAttribute(
"name" , sClassName );
741 oInnerNode.setAttribute(
"maxOccurs" ,
"unbounded" );
742 oInnerNode.setAttribute(
"minOccurs" ,
"0" );
744 oSeqNode.appendChild( oInnerNode );
749 oNode = createElement(
"xs:complexType" );
751 oInnerNode.appendChild( oNode );
757 QDomElement oInnerSeq = createElement(
"xs:sequence" );
759 oNode.appendChild( oInnerSeq );
765 oNode = createElement(
"xs:element" );
767 oNode.setAttribute(
"type" ,
"xs:string" );
768 oNode.setAttribute(
"nillable" ,
"true" );
769 oNode.setAttribute(
"name" ,
"Key" );
771 oInnerSeq.appendChild( oNode );
777 oNode = createElement(
"xs:element" );
779 oNode.setAttribute(
"type" , sType );
780 oNode.setAttribute(
"nillable" ,
"true" );
781 oNode.setAttribute(
"name" ,
"Value" );
783 oInnerSeq.appendChild( oNode );
789 QDomElement oElementNode = createElement(
"xs:element" );
791 oElementNode.setAttribute(
"type" ,
"tns:" + sArrayName );
792 oElementNode.setAttribute(
"nillable",
"true" );
793 oElementNode.setAttribute(
"name" , sArrayName );
799 appendChild( oRoot );
803 QDomElement oIncNode = createElement(
"xs:include" );
807 oIncNode.setAttribute(
"schemaLocation", sBaseUri + sClassName );
809 oRoot.appendChild( oIncNode );
812 oRoot.appendChild( oTypeNode );
813 oRoot.appendChild( oElementNode );
835 QString sTargetNamespace =
"http://mythtv.org";
837 QDomElement oRoot = createElement(
"xs:schema" );
839 oRoot.setAttribute(
"xmlns:xs" ,
"http://www.w3.org/2001/XMLSchema");
840 oRoot.setAttribute(
"xmlns:tns" , sTargetNamespace );
841 oRoot.setAttribute(
"targetNamespace" , sTargetNamespace );
842 oRoot.setAttribute(
"elementFormDefault" ,
"qualified" );
843 oRoot.setAttribute(
"attributeFormDefault",
"unqualified" );
853 if (sType.startsWith(
"DTC::"))
856 if (sType ==
"QDateTime")
859 if (sType ==
"QDate")
862 if (sType ==
"QTime")
874 if (bCustomType || sType.startsWith(
"DTC::"))
876 QString sTypeName( sType );
878 sTypeName.remove(
"DTC::" );
879 sTypeName.remove( QChar(
'*') );
881 if (sType ==
"QStringList" )
882 return "ArrayOfString";
887 if (sType ==
"QDateTime")
890 if (sType ==
"QDate")
893 if (sType ==
"QTime")
900 return "unsignedInt";
902 if (sType ==
"qlonglong" )
905 if (sType ==
"long long" )
908 if (sType ==
"QFileInfo" )
911 if (sType.startsWith(
'Q'))
912 return sType.mid( 1 ).toLower();
914 return sType.toLower();
923 const QMetaObject *pMeta = pObject->metaObject();
928 nIdx = pMeta->indexOfClassInfo( sPropName.toUtf8() );
932 QString sMetadata = pMeta->classInfo( nIdx ).value();
933 QStringList sOptions = sMetadata.split(
';' );
935 QString sFullKey = sKey +
"=";
937 for (
const QString& option : std::as_const(sOptions))
939 if (option.startsWith( sFullKey ))
940 return option.mid( sFullKey.length() );