14#include <QCoreApplication>
26 if (sEnumName.isEmpty())
33 if (sEnumName.count(
'.') != 1 )
36 QStringList lstTypeParts = sEnumName.split(
'.' );
42 const QString& sParentFQN = lstTypeParts[0];
43#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
49 if (nParentId == QMetaType::UnknownType)
51 QString sFQN = sParentFQN +
"*";
60 if (nParentId == QMetaType::UnknownType)
62 QString sFQN =
"DTC::" + sParentFQN +
"*";
66 const QMetaObject *pMetaObject = QMetaType::metaObjectForType(nParentId);
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)
75 const QMetaObject *pMetaObject = metaType.metaObject();
78 if (pMetaObject ==
nullptr)
85 int nEnumIdx = pMetaObject->indexOfEnumerator( lstTypeParts[1].toUtf8() );
90 QMetaEnum metaEnum = pMetaObject->enumerator( nEnumIdx );
119 appendChild( createProcessingInstruction(
"xml-stylesheet",
120 R
"(type="text/xsl" href="/xslt/enum.xslt")" ));
127 QDomElement oTypeNode = createElement(
"xs:simpleType" );
128 QDomElement oRestrictNode = createElement(
"xs:restriction" );
130 oTypeNode .setAttribute(
"name", sEnumName );
131 oRestrictNode.setAttribute(
"base",
"xs:string" );
133 oTypeNode.appendChild( oRestrictNode );
135 for(
int nIdx = 0; nIdx < metaEnum.keyCount(); nIdx++)
137 QDomElement oEnum = createElement(
"xs:enumeration" );
139 oEnum.setAttribute(
"value", metaEnum.key( nIdx ));
145 QDomElement oAnn = createElement(
"xs:annotation" );
146 QDomElement oApp = createElement(
"xs:appinfo" );
147 QDomElement oEnumVal = createElement(
"EnumerationValue" );
148 QDomElement oEnumDesc = createElement(
"EnumerationDesc" );
151 oEnumVal.setAttribute(
"xmlns",
"http://schemas.microsoft.com/2003/10/Serialization/");
153 oEnum.appendChild( oAnn );
154 oAnn .appendChild( oApp );
155 oApp .appendChild( oEnumVal );
156 oApp .appendChild( oEnumDesc );
158 QString sFQNKey = sEnumName +
"." + metaEnum.key( nIdx );
160 oEnumVal .appendChild( createTextNode( QString::number( metaEnum.value( nIdx ))));
161 oEnumDesc.appendChild( createTextNode( QCoreApplication::translate(
"Enums",
162 sFQNKey.toUtf8() )));
164 oRestrictNode.appendChild( oEnum );
169 QDomElement oElementNode = createElement(
"xs:element" );
171 oElementNode.setAttribute(
"name" , sEnumName );
172 oElementNode.setAttribute(
"type" ,
"tns:" + sEnumName );
173 oElementNode.setAttribute(
"nillable",
"true" );
181 oRoot.appendChild( oTypeNode );
182 oRoot.appendChild( oElementNode );
184 appendChild( oRoot );
205 bool bIsArray =
false;
208 if (sTypeName.isEmpty())
215 if (sTypeName.startsWith(
"ArrayOf" ))
218 sTypeName = sTypeName.mid( 7 );
221 if (sTypeName.startsWith(
"MapOfString" ))
224 sTypeName = sTypeName.mid( 11 );
231#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
237 if (
id == QMetaType::UnknownType)
239 QString sFQN = sTypeName +
"*";
248 if (
id == QMetaType::UnknownType)
250 QString sFQN =
"DTC::" + sTypeName +
"*";
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)
261 int id = metaType.id();
268 if (!(bIsArray || bIsMap) && (
id < QMetaType::User))
275 bool bHandled =
false;
283 appendChild( createProcessingInstruction(
"xml-stylesheet",
284 R
"(type="text/xsl" href="/xslt/class.xslt")" ));
289 bHandled =
RenderArrayXSD( pRequest, sTypeName,
id >= QMetaType::User );
295 id >= QMetaType::User );
299#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
300 const QMetaObject *pMetaObject = QMetaType::metaObjectForType(
id);
302 const QMetaObject *pMetaObject = metaType.metaObject();
306 QObject* pClass = pMetaObject->newInstance();
307 if (pClass !=
nullptr)
308 bHandled =
RenderXSD( pRequest, pClass );
343 const QMetaObject *pMetaObject = pClass->metaObject();
348 QMap<QString, TypeInfo> typesToInclude;
354 QDomElement oTypeNode = createElement(
"xs:complexType" );
355 QDomElement oSeqNode = createElement(
"xs:sequence" );
357 oTypeNode.setAttribute(
"name", sClassName );
359 oTypeNode.appendChild( oSeqNode );
371 int nCount = pMetaObject->propertyCount();
373 for (
int nIdx=0; nIdx < nCount; ++nIdx )
375 QMetaProperty metaProperty = pMetaObject->property( nIdx );
377 if (metaProperty.isDesignable())
379 const char *pszPropName = metaProperty.name();
380 QString sPropName( pszPropName );
382 if ( sPropName.compare(
"objectName" ) == 0)
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();
396 LOG(VB_UPNP, LOG_DEBUG, QString(
"Type: %1").arg( sType ));
402 if (sType ==
"QObject*")
404 QVariant val = metaProperty.read( pClass );
405 const QObject *pObject = val.value< QObject* >();
407 sType = pObject->metaObject()->className();
410 else if ((sType ==
"QVariantList" ) || (sType ==
"QVariantMap"))
416 if (sContentType.startsWith(
'Q'))
417 sContentType = sContentType.mid( 1 );
419 sContentType.remove(
"DTC::" );
420 sContentType.remove( QChar(
'*') );
422 if (sType ==
"QVariantMap")
428 if (sContentName.isEmpty())
429 sContentName = sContentType;
431 sType =
"MapOfString" + sContentName;
435 sType =
"ArrayOf" + sContentType;
441 else if (sType ==
"QStringList")
443 sType =
"ArrayOfString";
446 else if (
IsEnum( metaProperty, sType ))
448 sCustomAttr =
"enum";
450 sType.remove(
"DTC::" );
454 if (sType.contains(
"::" ))
455 sType = sType.replace(
"::",
"." );
457 sType = sClassName +
"." + sType;
462 QString sNewPropName( metaProperty.name() );
465 oNode.setAttribute(
"nillable" ,
static_cast<int>(
true) );
470 typesToInclude.insert( sType,
info );
473 oNode.setAttribute(
"type" , (bCustomType ?
"tns:" :
"xs:") +
476 oNode.setAttribute(
"name" , sNewPropName );
477 oNode.setAttribute(
"minOccurs", 0 );
479 oSeqNode.appendChild( oNode );
489 QDomElement oElementNode = createElement(
"xs:element" );
491 oElementNode.setAttribute(
"type" ,
"tns:" + sClassName );
492 oElementNode.setAttribute(
"nillable",
"true" );
493 oElementNode.setAttribute(
"name" , sClassName );
499 appendChild( oRoot );
501 if (typesToInclude.count() > 0)
509 QString sBaseUri =
"http://" + pRequest->
GetLastHeader(
"host" ) +
512 QMap<QString, TypeInfo >::const_iterator it = typesToInclude.constBegin();
513 while( it != typesToInclude.constEnd())
515 QDomElement oIncNode = createElement(
"xs:include" );
516 QString sType = it.key();
518 sType.remove(
"DTC::" );
522 QString sValue = QString(
"%1?%2=%3" ).arg( sBaseUri,
526 if (!
info.sContentType.isEmpty())
527 sValue +=
"&name=" +
info.sContentType;
529 oIncNode.setAttribute(
"schemaLocation", sValue );
531 oRoot.appendChild( oIncNode );
536 oRoot.appendChild( oTypeNode );
537 oRoot.appendChild( oElementNode );
552bool Xsd::IsEnum(
const QMetaProperty &metaProperty,
const QString & )
554 return (metaProperty.isEnumType() || metaProperty.isFlagType() );
579 const QString &sClassName,
582 QString sArrayName =
"ArrayOf" + sClassName;
586 sType =
"tns:" + sClassName;
596 QDomElement oTypeNode = createElement(
"xs:complexType" );
597 QDomElement oSeqNode = createElement(
"xs:sequence" );
601 oTypeNode.setAttribute(
"name", sArrayName );
602 oTypeNode.appendChild( oSeqNode );
604 QDomElement oNode = createElement(
"xs:element" );
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" );
612 oSeqNode.appendChild( oNode );
618 QDomElement oElementNode = createElement(
"xs:element" );
620 oElementNode.setAttribute(
"type" ,
"tns:" + sArrayName );
621 oElementNode.setAttribute(
"nillable",
"true" );
622 oElementNode.setAttribute(
"name" , sArrayName );
628 appendChild( oRoot );
632 QDomElement oIncNode = createElement(
"xs:include" );
634 QString sBaseUri =
"http://" + pRequest->
GetLastHeader(
"host" ) +
637 oIncNode.setAttribute(
"schemaLocation", sBaseUri + sClassName );
639 oRoot.appendChild( oIncNode );
642 oRoot.appendChild( oTypeNode );
643 oRoot.appendChild( oElementNode );
690 const QString &sClassName,
693 QString sArrayName =
"MapOfString" + sClassName;
694 QString sMapItemName = pRequest->
m_mapParams[
"name" ];
697 if (sMapItemName.isEmpty())
698 sMapItemName = sClassName;
701 sType =
"tns:" + sMapItemName;
711 QDomElement oTypeNode = createElement(
"xs:complexType" );
712 QDomElement oSeqNode = createElement(
"xs:sequence" );
713 QDomElement oAnno = createElement(
"xs:annotation" );
714 QDomElement oAppInfo = createElement(
"xs:appinfo" );
716 QDomElement oNode = createElement(
"IsDictionary" );
717 oNode.setAttribute(
"xmlns",
"http://schemas.microsoft.com/2003/10/Serialization/" );
718 oNode.appendChild( createTextNode(
"true" ));
720 oTypeNode.appendChild( oAnno );
721 oAnno .appendChild( oAppInfo );
722 oAppInfo .appendChild( oNode );
730 oTypeNode.setAttribute(
"name", sArrayName );
731 oTypeNode.appendChild( oSeqNode );
737 QDomElement oInnerNode = createElement(
"xs:element" );
739 oInnerNode.setAttribute(
"name" , sClassName );
740 oInnerNode.setAttribute(
"maxOccurs" ,
"unbounded" );
741 oInnerNode.setAttribute(
"minOccurs" ,
"0" );
743 oSeqNode.appendChild( oInnerNode );
748 oNode = createElement(
"xs:complexType" );
750 oInnerNode.appendChild( oNode );
756 QDomElement oInnerSeq = createElement(
"xs:sequence" );
758 oNode.appendChild( oInnerSeq );
764 oNode = createElement(
"xs:element" );
766 oNode.setAttribute(
"type" ,
"xs:string" );
767 oNode.setAttribute(
"nillable" ,
"true" );
768 oNode.setAttribute(
"name" ,
"Key" );
770 oInnerSeq.appendChild( oNode );
776 oNode = createElement(
"xs:element" );
778 oNode.setAttribute(
"type" , sType );
779 oNode.setAttribute(
"nillable" ,
"true" );
780 oNode.setAttribute(
"name" ,
"Value" );
782 oInnerSeq.appendChild( oNode );
788 QDomElement oElementNode = createElement(
"xs:element" );
790 oElementNode.setAttribute(
"type" ,
"tns:" + sArrayName );
791 oElementNode.setAttribute(
"nillable",
"true" );
792 oElementNode.setAttribute(
"name" , sArrayName );
798 appendChild( oRoot );
802 QDomElement oIncNode = createElement(
"xs:include" );
806 oIncNode.setAttribute(
"schemaLocation", sBaseUri + sClassName );
808 oRoot.appendChild( oIncNode );
811 oRoot.appendChild( oTypeNode );
812 oRoot.appendChild( oElementNode );
834 QString sTargetNamespace =
"http://mythtv.org";
836 QDomElement oRoot = createElement(
"xs:schema" );
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" );
852 if (sType.startsWith(
"DTC::"))
855 if (sType ==
"QDateTime")
858 if (sType ==
"QDate")
861 if (sType ==
"QTime")
873 if (bCustomType || sType.startsWith(
"DTC::"))
875 QString sTypeName( sType );
877 sTypeName.remove(
"DTC::" );
878 sTypeName.remove( QChar(
'*') );
880 if (sType ==
"QStringList" )
881 return "ArrayOfString";
886 if (sType ==
"QDateTime")
889 if (sType ==
"QDate")
892 if (sType ==
"QTime")
899 return "unsignedInt";
901 if (sType ==
"qlonglong" )
904 if (sType ==
"long long" )
907 if (sType ==
"QFileInfo" )
910 if (sType.startsWith(
'Q'))
911 return sType.mid( 1 ).toLower();
913 return sType.toLower();
922 const QMetaObject *pMeta = pObject->metaObject();
927 nIdx = pMeta->indexOfClassInfo( sPropName.toUtf8() );
931 QString sMetadata = pMeta->classInfo( nIdx ).value();
932 QStringList sOptions = sMetadata.split(
';' );
934 QString sFullKey = sKey +
"=";
936 for (
const QString& option : std::as_const(sOptions))
938 if (option.startsWith( sFullKey ))
939 return option.mid( sFullKey.length() );
HttpResponseType m_eResponseType
QString GetLastHeader(const QString &sType) const
bool RenderArrayXSD(HTTPRequest *pRequest, const QString &sClassName, bool bCustomType)
bool GetEnumXSD(HTTPRequest *pRequest, const QString &sEnumName)
bool RenderXSD(HTTPRequest *pRequest, QObject *pClass)
static QString ConvertTypeToXSD(const QString &sType, bool bCustomType=false)
bool RenderMapXSD(HTTPRequest *pRequest, const QString &sClassName, bool bCustomType)
bool GetXSD(HTTPRequest *pRequest, QString sTypeName)
static QString ReadPropertyMetadata(QObject *pObject, const QString &sPropName, const QString &sKey)
static bool IsNillable(const QString &sType)
static bool IsEnum(const QMetaProperty &metaProperty, const QString &sType)
QDomElement CreateSchemaRoot()
#define LOG(_MASK_, _LEVEL_, _QSTRING_)