CPLXMLNode *GDALMultiDomainMetadata::Serialize()

{
    CPLXMLNode *psFirst = NULL;

    for( int iDomain = 0; 
         papszDomainList != NULL && papszDomainList[iDomain] != NULL; 
         iDomain++)
    {
        char **papszMD = papoMetadataLists[iDomain]->List();
        // Do not serialize empty domains
        if( papszMD == NULL || papszMD[0] == NULL )
            continue;

        CPLXMLNode *psMD;
        int bFormatXML = FALSE;
        
        psMD = CPLCreateXMLNode( NULL, CXT_Element, "Metadata" );

        if( strlen( papszDomainList[iDomain] ) > 0 )
            CPLCreateXMLNode( 
                CPLCreateXMLNode( psMD, CXT_Attribute, "domain" ), 
                CXT_Text, papszDomainList[iDomain] );

        if( EQUALN(papszDomainList[iDomain],"xml:",4) 
            && CSLCount(papszMD) == 1 )
        {
            CPLXMLNode *psValueAsXML = CPLParseXMLString( papszMD[0] );
            if( psValueAsXML != NULL )
            {
                bFormatXML = TRUE;

                CPLCreateXMLNode( 
                    CPLCreateXMLNode( psMD, CXT_Attribute, "format" ), 
                    CXT_Text, "xml" );
                
                CPLAddXMLChild( psMD, psValueAsXML );
            }
        }

        if( !bFormatXML )
        {
            CPLXMLNode* psLastChild = NULL;
            // To go after domain attribute
            if( psMD->psChild != NULL )
            {
                psLastChild = psMD->psChild;
                while( psLastChild->psNext != NULL )
                    psLastChild = psLastChild->psNext; 
            }
            for( int i = 0; papszMD != NULL && papszMD[i] != NULL; i++ )
            {
                const char *pszRawValue;
                char *pszKey = NULL;
                CPLXMLNode *psMDI;
                
                pszRawValue = CPLParseNameValue( papszMD[i], &pszKey );
                
                psMDI = CPLCreateXMLNode( NULL, CXT_Element, "MDI" );
                if( psLastChild == NULL )
                    psMD->psChild = psMDI;
                else
                    psLastChild->psNext = psMDI;
                psLastChild = psMDI;

                CPLSetXMLValue( psMDI, "#key", pszKey );
                CPLCreateXMLNode( psMDI, CXT_Text, pszRawValue );
                
                CPLFree( pszKey );
            }
        }
            
        if( psFirst == NULL )
            psFirst = psMD;
        else
            CPLAddXMLSibling( psFirst, psMD );
    }

    return psFirst;
}
CPLXMLNode *GDALMultiDomainMetadata::Serialize()

{
    CPLXMLNode *psFirst = nullptr;

    for( int iDomain = 0;
         papszDomainList != nullptr && papszDomainList[iDomain] != nullptr;
         iDomain++ )
    {
        char **papszMD = papoMetadataLists[iDomain]->List();
        // Do not serialize empty domains.
        if( papszMD == nullptr || papszMD[0] == nullptr )
            continue;

        CPLXMLNode *psMD = CPLCreateXMLNode( nullptr, CXT_Element, "Metadata" );

        if( strlen( papszDomainList[iDomain] ) > 0 )
            CPLCreateXMLNode(
                CPLCreateXMLNode( psMD, CXT_Attribute, "domain" ),
                CXT_Text, papszDomainList[iDomain] );

        bool bFormatXML = false;

        if( STARTS_WITH_CI(papszDomainList[iDomain], "xml:")
            && CSLCount(papszMD) == 1 )
        {
            CPLXMLNode *psValueAsXML = CPLParseXMLString( papszMD[0] );
            if( psValueAsXML != nullptr )
            {
                bFormatXML = true;

                CPLCreateXMLNode(
                    CPLCreateXMLNode( psMD, CXT_Attribute, "format" ),
                    CXT_Text, "xml" );

                CPLAddXMLChild( psMD, psValueAsXML );
            }
        }

        if( !bFormatXML )
        {
            CPLXMLNode* psLastChild = nullptr;
            // To go after domain attribute.
            if( psMD->psChild != nullptr )
            {
                psLastChild = psMD->psChild;
                while( psLastChild->psNext != nullptr )
                    psLastChild = psLastChild->psNext;
            }
            for( int i = 0; papszMD != nullptr && papszMD[i] != nullptr; i++ )
            {
                char *pszKey = nullptr;

                const char *pszRawValue =
                    CPLParseNameValue( papszMD[i], &pszKey );

                CPLXMLNode *psMDI =
                    CPLCreateXMLNode( nullptr, CXT_Element, "MDI" );
                if( psLastChild == nullptr )
                    psMD->psChild = psMDI;
                else
                    psLastChild->psNext = psMDI;
                psLastChild = psMDI;

                CPLSetXMLValue( psMDI, "#key", pszKey );
                CPLCreateXMLNode( psMDI, CXT_Text, pszRawValue );

                CPLFree( pszKey );
            }
        }

        if( psFirst == nullptr )
            psFirst = psMD;
        else
            CPLAddXMLSibling( psFirst, psMD );
    }

    return psFirst;
}