13#include <QCoreApplication>
211 bool bIsArray =
false;
214 if (sTypeName.isEmpty())
215 return Error(pRequest, QString(
"XSD request on empty name" ));
222 if (sTypeName.startsWith(
"ArrayOf" ))
225 sTypeName = sTypeName.mid( 7 );
228 if (sTypeName.startsWith(
"MapOfString" ))
231 sTypeName = sTypeName.mid( 11 );
238#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
244 if (
id == QMetaType::UnknownType)
246 QString sFQN = sTypeName +
"*";
255 if (
id == QMetaType::UnknownType)
257 QString sFQN =
"V2" + sTypeName;
260 if (
id == QMetaType::UnknownType)
262 QString sFQN =
"V2" + sTypeName +
"*";
268 QMetaType metaType = QMetaType::fromName( sTypeName.toUtf8() );
269 if (metaType.id() == QMetaType::UnknownType)
270 metaType = QMetaType::fromName( sTypeName.toUtf8() +
"*" );
271 if (metaType.id() == QMetaType::UnknownType)
272 metaType = QMetaType::fromName(
"V2" + sTypeName.toUtf8() +
"*" );
276 int id = metaType.id();
283 if (!(bIsArray || bIsMap) && (
id < QMetaType::User))
284 return Error(pRequest,QString(
"XSD request on unsupported type %1").arg(sTypeName));
294 if (!pRequest->m_queries.contains(
"raw" ))
296 appendChild( createProcessingInstruction(
"xml-stylesheet",
297 R
"(type="text/xsl" href="/xslt/class.xslt")" ));
308 id >= QMetaType::User );
312#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
313 const QMetaObject *pMetaObject = QMetaType::metaObjectForType(
id);
315 const QMetaObject *pMetaObject = metaType.metaObject();
319 QObject* pClass = pMetaObject->newInstance();
320 if (pClass !=
nullptr)
359 const QMetaObject *pMetaObject = pClass->metaObject();
364 QMap<QString, TypeInfo> typesToInclude;
370 QDomElement oTypeNode = createElement(
"xs:complexType" );
371 QDomElement oSeqNode = createElement(
"xs:sequence" );
373 oTypeNode.setAttribute(
"name", sClassName );
375 oTypeNode.appendChild( oSeqNode );
387 int nCount = pMetaObject->propertyCount();
389 for (
int nIdx=0; nIdx < nCount; ++nIdx )
391 QMetaProperty metaProperty = pMetaObject->property( nIdx );
393 if (metaProperty.isDesignable())
395 const char *pszPropName = metaProperty.name();
396 QString sPropName( pszPropName );
398 if ( sPropName.compare(
"objectName" ) == 0)
405 QDomElement oNode = createElement(
"xs:element" );
406 QString sType = metaProperty.typeName();
407 bool bCustomType =
false;
408 QString sCustomAttr =
"type";
409 QString sContentName = QString();
410 QString sContentType = QString();
412 LOG(VB_UPNP, LOG_DEBUG, QString(
"Type: %1").arg( sType ));
418 if (sType ==
"QObject*")
420 QVariant val = metaProperty.read( pClass );
421 const QObject *pObject = val.value< QObject* >();
423 sType = pObject->metaObject()->className();
426 else if ((sType ==
"QVariantList" ) || (sType ==
"QVariantMap"))
432 if (sContentType.startsWith(
'Q'))
433 sContentType = sContentType.mid( 1 );
435 if (sContentType.startsWith(
"V2"))
436 sContentType.remove(0,2);
437 sContentType.remove( QChar(
'*'));
439 if (sType ==
"QVariantMap")
445 if (sContentName.isEmpty())
446 sContentName = sContentType;
448 sType =
"MapOfString" + sContentName;
452 sType =
"ArrayOf" + sContentType;
458 else if (sType ==
"QStringList")
460 sType =
"ArrayOfString";
463 else if (
IsEnum( metaProperty, sType ))
479 QString sNewPropName( metaProperty.name() );
482 oNode.setAttribute(
"nillable" ,
static_cast<int>(
true) );
487 typesToInclude.insert( sType,
info );
490 oNode.setAttribute(
"type" , (bCustomType ?
"tns:" :
"xs:") +
493 oNode.setAttribute(
"name" , sNewPropName );
494 oNode.setAttribute(
"minOccurs", 0 );
496 oSeqNode.appendChild( oNode );
506 QDomElement oElementNode = createElement(
"xs:element" );
508 oElementNode.setAttribute(
"type" ,
"tns:" + sClassName );
509 oElementNode.setAttribute(
"nillable",
"true" );
510 oElementNode.setAttribute(
"name" , sClassName );
516 appendChild( oRoot );
518 if (typesToInclude.count() > 0)
528 QString sBaseUri(
"http://" +
529 pRequest->m_headers->value(
"host") +
530 pRequest->m_path +
"xsd");
531 QMap<QString, TypeInfo >::const_iterator it = typesToInclude.constBegin();
532 while( it != typesToInclude.constEnd())
534 QDomElement oIncNode = createElement(
"xs:include" );
535 QString sType = it.key();
537 if (sType.startsWith(
"V2"))
542 QString sValue = QString(
"%1?%2=%3" ).arg( sBaseUri,
546 if (!
info.sContentType.isEmpty())
547 sValue +=
"&name=" +
info.sContentType;
549 oIncNode.setAttribute(
"schemaLocation", sValue );
551 oRoot.appendChild( oIncNode );
556 oRoot.appendChild( oTypeNode );
557 oRoot.appendChild( oElementNode );
574 return (metaProperty.isEnumType() || metaProperty.isFlagType() );
599 const QString &sClassName,
602 QString sArrayName =
"ArrayOf" + sClassName;
606 sType =
"tns:" + sClassName;
616 QDomElement oTypeNode = createElement(
"xs:complexType" );
617 QDomElement oSeqNode = createElement(
"xs:sequence" );
621 oTypeNode.setAttribute(
"name", sArrayName );
622 oTypeNode.appendChild( oSeqNode );
624 QDomElement oNode = createElement(
"xs:element" );
626 oNode.setAttribute(
"type" , sType );
627 oNode.setAttribute(
"nillable" ,
"true" );
628 oNode.setAttribute(
"name" , sClassName );
629 oNode.setAttribute(
"maxOccurs" ,
"unbounded" );
630 oNode.setAttribute(
"minOccurs" ,
"0" );
632 oSeqNode.appendChild( oNode );
638 QDomElement oElementNode = createElement(
"xs:element" );
640 oElementNode.setAttribute(
"type" ,
"tns:" + sArrayName );
641 oElementNode.setAttribute(
"nillable",
"true" );
642 oElementNode.setAttribute(
"name" , sArrayName );
648 appendChild( oRoot );
652 QDomElement oIncNode = createElement(
"xs:include" );
656 QString sBaseUri(
"http://" +
657 pRequest->m_headers->value(
"host") +
658 pRequest->m_path +
"xsd" +
"?type=");
660 oIncNode.setAttribute(
"schemaLocation", sBaseUri + sClassName );
662 oRoot.appendChild( oIncNode );
665 oRoot.appendChild( oTypeNode );
666 oRoot.appendChild( oElementNode );
713 const QString &sClassName,
716 QString sArrayName =
"MapOfString" + sClassName;
718 QString sMapItemName = pRequest->m_queries.value(
"name");
722 if (sMapItemName.isEmpty())
723 sMapItemName = sClassName;
726 sType =
"tns:" + sMapItemName;
736 QDomElement oTypeNode = createElement(
"xs:complexType" );
737 QDomElement oSeqNode = createElement(
"xs:sequence" );
738 QDomElement oAnno = createElement(
"xs:annotation" );
739 QDomElement oAppInfo = createElement(
"xs:appinfo" );
741 QDomElement oNode = createElement(
"IsDictionary" );
742 oNode.setAttribute(
"xmlns",
"http://schemas.microsoft.com/2003/10/Serialization/" );
743 oNode.appendChild( createTextNode(
"true" ));
745 oTypeNode.appendChild( oAnno );
746 oAnno .appendChild( oAppInfo );
747 oAppInfo .appendChild( oNode );
755 oTypeNode.setAttribute(
"name", sArrayName );
756 oTypeNode.appendChild( oSeqNode );
762 QDomElement oInnerNode = createElement(
"xs:element" );
764 oInnerNode.setAttribute(
"name" , sClassName );
765 oInnerNode.setAttribute(
"maxOccurs" ,
"unbounded" );
766 oInnerNode.setAttribute(
"minOccurs" ,
"0" );
768 oSeqNode.appendChild( oInnerNode );
773 oNode = createElement(
"xs:complexType" );
775 oInnerNode.appendChild( oNode );
781 QDomElement oInnerSeq = createElement(
"xs:sequence" );
783 oNode.appendChild( oInnerSeq );
789 oNode = createElement(
"xs:element" );
791 oNode.setAttribute(
"type" ,
"xs:string" );
792 oNode.setAttribute(
"nillable" ,
"true" );
793 oNode.setAttribute(
"name" ,
"Key" );
795 oInnerSeq.appendChild( oNode );
801 oNode = createElement(
"xs:element" );
803 oNode.setAttribute(
"type" , sType );
804 oNode.setAttribute(
"nillable" ,
"true" );
805 oNode.setAttribute(
"name" ,
"Value" );
807 oInnerSeq.appendChild( oNode );
813 QDomElement oElementNode = createElement(
"xs:element" );
815 oElementNode.setAttribute(
"type" ,
"tns:" + sArrayName );
816 oElementNode.setAttribute(
"nillable",
"true" );
817 oElementNode.setAttribute(
"name" , sArrayName );
823 appendChild( oRoot );
827 QDomElement oIncNode = createElement(
"xs:include" );
830 QString sBaseUri(
"http://" +
831 pRequest->m_headers->value(
"host") +
832 pRequest->m_path +
"xsd" +
"?type=");
834 oIncNode.setAttribute(
"schemaLocation", sBaseUri + sClassName );
836 oRoot.appendChild( oIncNode );
839 oRoot.appendChild( oTypeNode );
840 oRoot.appendChild( oElementNode );
862 QString sTargetNamespace =
"http://mythtv.org";
864 QDomElement oRoot = createElement(
"xs:schema" );
866 oRoot.setAttribute(
"xmlns:xs" ,
"http://www.w3.org/2001/XMLSchema");
867 oRoot.setAttribute(
"xmlns:tns" , sTargetNamespace );
868 oRoot.setAttribute(
"targetNamespace" , sTargetNamespace );
869 oRoot.setAttribute(
"elementFormDefault" ,
"qualified" );
870 oRoot.setAttribute(
"attributeFormDefault",
"unqualified" );
880 if (sType.startsWith(
"V2"))
883 if (sType ==
"QDateTime")
886 if (sType ==
"QDate")
889 if (sType ==
"QTime")
901 if (bCustomType || sType.startsWith(
"V2"))
903 QString sTypeName( sType );
905 if (sTypeName.startsWith(
"V2"))
906 sTypeName.remove(0,2);
907 sTypeName.remove( QChar(
'*') );
909 if (sType ==
"QStringList" )
910 return "ArrayOfString";
915 if (sType ==
"QDateTime")
918 if (sType ==
"QDate")
921 if (sType ==
"QTime")
928 return "unsignedInt";
930 if (sType ==
"qlonglong" )
933 if (sType ==
"std::chrono::seconds" )
936 if (sType ==
"qulonglong" )
937 return "unsignedLong";
939 if (sType ==
"QJsonObject" )
942 if (sType ==
"long long" )
945 if (sType ==
"QFileInfo" )
948 if (sType.startsWith(
'Q'))
949 return sType.mid( 1 ).toLower();
951 return sType.toLower();
960 const QMetaObject *pMeta = pObject->metaObject();
965 nIdx = pMeta->indexOfClassInfo( sPropName.toUtf8() );
969 QString sMetadata = pMeta->classInfo( nIdx ).value();
970 QStringList sOptions = sMetadata.split(
';' );
972 QString sFullKey = sKey +
"=";
974 auto hasKey = [&sFullKey](
const QString& o) {
return o.startsWith( sFullKey ); };
975 auto it = std::find_if(sOptions.cbegin(), sOptions.cend(), hasKey);
976 if (it != sOptions.cend())
977 return (*it).mid( sFullKey.length() );
985 LOG(VB_GENERAL, LOG_ERR,
"MythCSD Exception: " + msg);
static HTTPResponse ErrorResponse(MythHTTPStatus Status, const QString &ServerName)
static HTTPResponse DataResponse(const HTTPRequest2 &Request, const HTTPData &Data)
static MythMimeType MimeTypeForName(const QString &Name)
Return a mime type that matches the given name.
static HTTPResponse Error(const HTTPRequest2 &pRequest, const QString &msg)
static QString ConvertTypeToXSD(const QString &sType, bool bCustomType=false)
HTTPResponse GetXSD(const HTTPRequest2 &pRequest, QString sTypeName)
bool RenderXSD(const HTTPRequest2 &pRequest, QObject *pClass)
QDomElement CreateSchemaRoot()
static QString ReadPropertyMetadata(QObject *pObject, const QString &sPropName, const QString &sKey)
static bool IsEnum(const QMetaProperty &metaProperty, const QString &sType)
bool RenderMapXSD(const HTTPRequest2 &pRequest, const QString &sClassName, bool bCustomType)
bool RenderArrayXSD(const HTTPRequest2 &pRequest, const QString &sClassName, bool bCustomType)
static bool IsNillable(const QString &sType)
std::shared_ptr< MythHTTPRequest > HTTPRequest2
std::shared_ptr< MythHTTPResponse > HTTPResponse
#define LOG(_MASK_, _LEVEL_, _QSTRING_)