2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
2014-09-25 18:03:04 -04:00
# include "InternationalizationPrivatePCH.h"
# include "Internationalization/InternationalizationArchive.h"
2014-03-14 14:13:41 -04:00
# include "Internationalization/InternationalizationMetadata.h"
2014-09-25 18:03:04 -04:00
# include "JsonInternationalizationArchiveSerializer.h"
# include "JsonInternationalizationMetadataSerializer.h"
2014-03-14 14:13:41 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogInternationalizationArchiveSerializer , Log , All ) ;
2014-09-25 18:03:04 -04:00
const FString FJsonInternationalizationArchiveSerializer : : TAG_FORMATVERSION = TEXT ( " FormatVersion " ) ;
const FString FJsonInternationalizationArchiveSerializer : : TAG_NAMESPACE = TEXT ( " Namespace " ) ;
const FString FJsonInternationalizationArchiveSerializer : : TAG_CHILDREN = TEXT ( " Children " ) ;
const FString FJsonInternationalizationArchiveSerializer : : TAG_SUBNAMESPACES = TEXT ( " Subnamespaces " ) ;
const FString FJsonInternationalizationArchiveSerializer : : TAG_DEPRECATED_DEFAULTTEXT = TEXT ( " DefaultText " ) ;
const FString FJsonInternationalizationArchiveSerializer : : TAG_DEPRECATED_TRANSLATEDTEXT = TEXT ( " TranslatedText " ) ;
const FString FJsonInternationalizationArchiveSerializer : : TAG_OPTIONAL = TEXT ( " Optional " ) ;
const FString FJsonInternationalizationArchiveSerializer : : TAG_SOURCE = TEXT ( " Source " ) ;
const FString FJsonInternationalizationArchiveSerializer : : TAG_SOURCE_TEXT = TEXT ( " Text " ) ;
const FString FJsonInternationalizationArchiveSerializer : : TAG_TRANSLATION = TEXT ( " Translation " ) ;
const FString FJsonInternationalizationArchiveSerializer : : TAG_TRANSLATION_TEXT = FJsonInternationalizationArchiveSerializer : : TAG_SOURCE_TEXT ;
const FString FJsonInternationalizationArchiveSerializer : : TAG_METADATA_KEY = TEXT ( " Key " ) ;
const FString FJsonInternationalizationArchiveSerializer : : NAMESPACE_DELIMITER = TEXT ( " . " ) ;
2014-03-14 14:13:41 -04:00
struct FCompareArchiveEntryBySourceAndKey
{
FORCEINLINE bool operator ( ) ( TSharedPtr < FArchiveEntry > A , TSharedPtr < FArchiveEntry > B ) const
{
bool bResult = false ;
if ( A - > Source < B - > Source )
{
bResult = true ;
}
else if ( A - > Source = = B - > Source )
{
if ( A - > KeyMetadataObj . IsValid ( ) ! = B - > KeyMetadataObj . IsValid ( ) )
{
bResult = B - > KeyMetadataObj . IsValid ( ) ;
}
else if ( A - > KeyMetadataObj . IsValid ( ) & & B - > KeyMetadataObj . IsValid ( ) )
{
bResult = ( * ( A - > KeyMetadataObj ) < * ( B - > KeyMetadataObj ) ) ;
}
}
return bResult ;
}
} ;
2014-09-25 18:03:04 -04:00
2014-03-14 14:13:41 -04:00
struct FCompareStructuredArchiveEntryByNamespace
{
FORCEINLINE bool operator ( ) ( TSharedPtr < FStructuredArchiveEntry > A , TSharedPtr < FStructuredArchiveEntry > B ) const
{
return A - > Namespace < B - > Namespace ;
}
} ;
2014-10-15 23:05:20 -04:00
#if 0 // @todo Json: Serializing from FArchive is currently broken
2014-09-25 18:03:04 -04:00
bool FJsonInternationalizationArchiveSerializer : : DeserializeArchive ( FArchive & Archive , TSharedRef < FInternationalizationArchive > InternationalizationArchive )
2014-03-14 14:13:41 -04:00
{
TSharedPtr < FJsonObject > JsonArchiveObj ;
TSharedRef < TJsonReader < > > Reader = TJsonReaderFactory < > : : Create ( & Archive ) ;
bool bExecSuccessful = FJsonSerializer : : Deserialize ( Reader , JsonArchiveObj ) ;
if ( bExecSuccessful & & JsonArchiveObj . IsValid ( ) )
{
bExecSuccessful = DeserializeInternal ( JsonArchiveObj . ToSharedRef ( ) , InternationalizationArchive ) ;
}
return bExecSuccessful ;
}
2014-10-15 23:05:20 -04:00
# endif
2014-03-14 14:13:41 -04:00
2014-09-25 18:03:04 -04:00
bool FJsonInternationalizationArchiveSerializer : : DeserializeArchive ( const FString & InStr , TSharedRef < FInternationalizationArchive > InternationalizationArchive )
2014-03-14 14:13:41 -04:00
{
TSharedPtr < FJsonObject > JsonArchiveObj ;
TSharedRef < TJsonReader < > > Reader = TJsonReaderFactory < > : : Create ( InStr ) ;
bool bExecSuccessful = FJsonSerializer : : Deserialize ( Reader , JsonArchiveObj ) ;
if ( bExecSuccessful & & JsonArchiveObj . IsValid ( ) )
{
bExecSuccessful = DeserializeInternal ( JsonArchiveObj . ToSharedRef ( ) , InternationalizationArchive ) ;
}
return bExecSuccessful ;
}
2014-09-25 18:03:04 -04:00
bool FJsonInternationalizationArchiveSerializer : : DeserializeArchive ( TSharedRef < FJsonObject > InJsonObj , TSharedRef < FInternationalizationArchive > InternationalizationArchive )
2014-03-14 14:13:41 -04:00
{
return DeserializeInternal ( InJsonObj , InternationalizationArchive ) ;
}
2014-09-25 18:03:04 -04:00
2014-10-15 23:05:20 -04:00
#if 0 // @todo Json: Serializing from FArchive is currently broken
2014-09-25 18:03:04 -04:00
bool FJsonInternationalizationArchiveSerializer : : SerializeArchive ( TSharedRef < const FInternationalizationArchive > InternationalizationArchive , FArchive & Archive )
2014-03-14 14:13:41 -04:00
{
TSharedRef < FJsonObject > JsonArchiveObj = MakeShareable ( new FJsonObject ) ;
bool bExecSuccessful = SerializeInternal ( InternationalizationArchive , JsonArchiveObj ) ;
if ( bExecSuccessful )
{
TSharedRef < TJsonWriter < > > Writer = TJsonWriterFactory < > : : Create ( & Archive ) ;
bExecSuccessful = FJsonSerializer : : Serialize ( JsonArchiveObj , Writer ) ;
Writer - > Close ( ) ;
}
return bExecSuccessful ;
}
2014-10-15 23:05:20 -04:00
# endif
2014-03-14 14:13:41 -04:00
2014-09-25 18:03:04 -04:00
bool FJsonInternationalizationArchiveSerializer : : SerializeArchive ( TSharedRef < const FInternationalizationArchive > InternationalizationArchive , FString & Str )
2014-03-14 14:13:41 -04:00
{
TSharedRef < FJsonObject > JsonArchiveObj = MakeShareable ( new FJsonObject ) ;
bool bExecSuccessful = SerializeInternal ( InternationalizationArchive , JsonArchiveObj ) ;
if ( bExecSuccessful )
{
TSharedRef < TJsonWriter < > > Writer = TJsonWriterFactory < > : : Create ( & Str ) ;
bExecSuccessful = FJsonSerializer : : Serialize ( JsonArchiveObj , Writer ) ;
Writer - > Close ( ) ;
}
return bExecSuccessful ;
}
2014-09-25 18:03:04 -04:00
bool FJsonInternationalizationArchiveSerializer : : SerializeArchive ( TSharedRef < const FInternationalizationArchive > InternationalizationArchive , TSharedRef < FJsonObject > JsonObj )
2014-03-14 14:13:41 -04:00
{
return SerializeInternal ( InternationalizationArchive , JsonObj ) ;
}
2014-09-25 18:03:04 -04:00
bool FJsonInternationalizationArchiveSerializer : : DeserializeInternal ( TSharedRef < FJsonObject > InJsonObj , TSharedRef < FInternationalizationArchive > InternationalizationArchive )
2014-03-14 14:13:41 -04:00
{
2014-09-14 19:37:14 -04:00
if ( InJsonObj - > HasField ( TAG_FORMATVERSION ) )
{
2014-09-25 18:03:04 -04:00
const int32 FormatVersion = static_cast < int > ( InJsonObj - > GetNumberField ( TAG_FORMATVERSION ) ) ;
InternationalizationArchive - > SetFormatVersion ( static_cast < FInternationalizationArchive : : EFormatVersion > ( FormatVersion ) ) ;
2014-09-14 19:37:14 -04:00
}
else
{
2014-09-25 18:03:04 -04:00
InternationalizationArchive - > SetFormatVersion ( FInternationalizationArchive : : EFormatVersion : : Initial ) ;
2014-09-14 19:37:14 -04:00
}
2014-03-14 14:13:41 -04:00
return JsonObjToArchive ( InJsonObj , TEXT ( " " ) , InternationalizationArchive ) ;
}
2014-09-25 18:03:04 -04:00
bool FJsonInternationalizationArchiveSerializer : : SerializeInternal ( TSharedRef < const FInternationalizationArchive > InInternationalizationArchive , TSharedRef < FJsonObject > JsonObj )
2014-03-14 14:13:41 -04:00
{
TSharedPtr < FStructuredArchiveEntry > RootElement = MakeShareable ( new FStructuredArchiveEntry ( TEXT ( " " ) ) ) ;
// Condition the data so that it exists in a structured hierarchy for easy population of the JSON object.
GenerateStructuredData ( InInternationalizationArchive , RootElement ) ;
SortStructuredData ( RootElement ) ;
// Clear anything that may be in the JSON object
JsonObj - > Values . Empty ( ) ;
2014-09-14 19:37:14 -04:00
// Set format version.
2014-09-25 18:03:04 -04:00
JsonObj - > SetNumberField ( TAG_FORMATVERSION , static_cast < double > ( InInternationalizationArchive - > GetFormatVersion ( ) ) ) ;
2014-09-14 19:37:14 -04:00
2014-03-14 14:13:41 -04:00
// Setup the JSON object using the structured data created
StructuredDataToJsonObj ( RootElement , JsonObj ) ;
return true ;
}
2014-09-25 18:03:04 -04:00
bool FJsonInternationalizationArchiveSerializer : : JsonObjToArchive ( TSharedRef < FJsonObject > InJsonObj , FString ParentNamespace , TSharedRef < FInternationalizationArchive > InternationalizationArchive )
2014-03-14 14:13:41 -04:00
{
bool bConvertSuccess = true ;
FString AccumulatedNamespace = ParentNamespace ;
if ( InJsonObj - > HasField ( TAG_NAMESPACE ) )
{
if ( ! ( AccumulatedNamespace . IsEmpty ( ) ) )
{
AccumulatedNamespace + = NAMESPACE_DELIMITER ;
}
AccumulatedNamespace + = InJsonObj - > GetStringField ( TAG_NAMESPACE ) ;
}
else
{
UE_LOG ( LogInternationalizationArchiveSerializer , Warning , TEXT ( " Encountered an object with a missing namespace while converting to Internationalization archive. " ) ) ;
bConvertSuccess = false ;
}
// Process all the child objects
if ( bConvertSuccess & & InJsonObj - > HasField ( TAG_CHILDREN ) )
{
const TArray < TSharedPtr < FJsonValue > > ChildrenArray = InJsonObj - > GetArrayField ( TAG_CHILDREN ) ;
for ( TArray < TSharedPtr < FJsonValue > > : : TConstIterator ChildIter ( ChildrenArray . CreateConstIterator ( ) ) ; ChildIter ; + + ChildIter )
{
const TSharedPtr < FJsonValue > ChildEntry = * ChildIter ;
const TSharedPtr < FJsonObject > ChildJSONObject = ChildEntry - > AsObject ( ) ;
FString SourceText ;
TSharedPtr < FLocMetadataObject > SourceMetadata ;
if ( ChildJSONObject - > HasTypedField < EJson : : String > ( TAG_DEPRECATED_DEFAULTTEXT ) )
{
SourceText = ChildJSONObject - > GetStringField ( TAG_DEPRECATED_DEFAULTTEXT ) ;
}
else if ( ChildJSONObject - > HasTypedField < EJson : : Object > ( TAG_SOURCE ) )
{
const TSharedPtr < FJsonObject > SourceJSONObject = ChildJSONObject - > GetObjectField ( TAG_SOURCE ) ;
if ( SourceJSONObject - > HasTypedField < EJson : : String > ( TAG_SOURCE_TEXT ) )
{
SourceText = SourceJSONObject - > GetStringField ( TAG_SOURCE_TEXT ) ;
// Source meta data is mixed in with the source text, we'll process metadata if the source json object has more than one entry
if ( SourceJSONObject - > Values . Num ( ) > 1 )
{
// We load in the entire source object as metadata and just remove the source text.
2014-09-25 18:03:04 -04:00
FJsonInternationalizationMetaDataSerializer : : DeserializeMetadata ( SourceJSONObject . ToSharedRef ( ) , SourceMetadata ) ;
2014-03-14 14:13:41 -04:00
if ( SourceMetadata . IsValid ( ) )
{
SourceMetadata - > Values . Remove ( TAG_SOURCE_TEXT ) ;
}
}
}
else
{
bConvertSuccess = false ;
}
}
else
{
bConvertSuccess = false ;
}
FString TranslationText ;
TSharedPtr < FLocMetadataObject > TranslationMetadata ;
if ( ChildJSONObject - > HasTypedField < EJson : : String > ( TAG_DEPRECATED_TRANSLATEDTEXT ) )
{
TranslationText = ChildJSONObject - > GetStringField ( TAG_DEPRECATED_TRANSLATEDTEXT ) ;
}
else if ( ChildJSONObject - > HasTypedField < EJson : : Object > ( TAG_TRANSLATION ) )
{
const TSharedPtr < FJsonObject > TranslationJSONObject = ChildJSONObject - > GetObjectField ( TAG_TRANSLATION ) ;
if ( TranslationJSONObject - > HasTypedField < EJson : : String > ( TAG_TRANSLATION_TEXT ) )
{
TranslationText = TranslationJSONObject - > GetStringField ( TAG_TRANSLATION_TEXT ) ;
// Source meta data is mixed in with the source text, we'll process metadata if the source json object has more than one entry
if ( TranslationJSONObject - > Values . Num ( ) > 1 )
{
// We load in the entire source object as metadata and remove the source text
2014-09-25 18:03:04 -04:00
FJsonInternationalizationMetaDataSerializer : : DeserializeMetadata ( TranslationJSONObject . ToSharedRef ( ) , TranslationMetadata ) ;
2014-03-14 14:13:41 -04:00
if ( TranslationJSONObject . IsValid ( ) )
{
TranslationJSONObject - > Values . Remove ( TAG_TRANSLATION_TEXT ) ;
}
}
}
else
{
bConvertSuccess = false ;
}
}
else
{
bConvertSuccess = false ;
}
if ( bConvertSuccess )
{
FLocItem Source ( SourceText ) ;
Source . MetadataObj = SourceMetadata ;
FLocItem Translation ( TranslationText ) ;
Translation . MetadataObj = TranslationMetadata ;
bool bIsOptional = false ;
if ( ChildJSONObject - > HasTypedField < EJson : : Boolean > ( TAG_OPTIONAL ) )
{
bIsOptional = ChildJSONObject - > GetBoolField ( TAG_OPTIONAL ) ;
}
TSharedPtr < FLocMetadataObject > MetadataNode ;
if ( ChildJSONObject - > HasTypedField < EJson : : Object > ( TAG_METADATA_KEY ) )
{
const TSharedPtr < FJsonObject > MetaDataKeyJSONObject = ChildJSONObject - > GetObjectField ( TAG_METADATA_KEY ) ;
2014-09-25 18:03:04 -04:00
FJsonInternationalizationMetaDataSerializer : : DeserializeMetadata ( MetaDataKeyJSONObject . ToSharedRef ( ) , MetadataNode ) ;
2014-03-14 14:13:41 -04:00
}
bool bAddSuccessful = InternationalizationArchive - > AddEntry ( AccumulatedNamespace , Source , Translation , MetadataNode , bIsOptional ) ;
if ( ! bAddSuccessful )
{
UE_LOG ( LogInternationalizationArchiveSerializer , Warning , TEXT ( " Could not add JSON entry to the Internationalization archive: Namespace:%s DefaultText:%s " ) , * AccumulatedNamespace , * SourceText ) ;
}
}
}
}
if ( bConvertSuccess & & InJsonObj - > HasField ( TAG_SUBNAMESPACES ) )
{
const TArray < TSharedPtr < FJsonValue > > SubnamespaceArray = InJsonObj - > GetArrayField ( TAG_SUBNAMESPACES ) ;
for ( TArray < TSharedPtr < FJsonValue > > : : TConstIterator SubnamespaceIter ( SubnamespaceArray . CreateConstIterator ( ) ) ; SubnamespaceIter ; + + SubnamespaceIter )
{
const TSharedPtr < FJsonValue > SubnamespaceEntry = * SubnamespaceIter ;
const TSharedPtr < FJsonObject > SubnamespaceJSONObject = SubnamespaceEntry - > AsObject ( ) ;
if ( ! JsonObjToArchive ( SubnamespaceJSONObject . ToSharedRef ( ) , AccumulatedNamespace , InternationalizationArchive ) )
{
bConvertSuccess = false ;
break ;
}
}
}
return bConvertSuccess ;
}
2014-09-25 18:03:04 -04:00
void FJsonInternationalizationArchiveSerializer : : GenerateStructuredData ( TSharedRef < const FInternationalizationArchive > InInternationalizationArchive , TSharedPtr < FStructuredArchiveEntry > RootElement )
2014-03-14 14:13:41 -04:00
{
//Loop through all the unstructured archive entries and build up our structured hierarchy
for ( TArchiveEntryContainer : : TConstIterator It ( InInternationalizationArchive - > GetEntryIterator ( ) ) ; It ; + + It )
{
const TSharedRef < FArchiveEntry > UnstructuredArchiveEntry = It . Value ( ) ;
TArray < FString > NamespaceTokens ;
// Tokenize the namespace by using '.' as a delimiter
2015-03-02 15:51:37 -05:00
int32 NamespaceTokenCount = UnstructuredArchiveEntry - > Namespace . ParseIntoArray ( NamespaceTokens , * NAMESPACE_DELIMITER , true ) ;
2014-03-14 14:13:41 -04:00
TSharedPtr < FStructuredArchiveEntry > StructuredArchiveEntry = RootElement ;
//Loop through all the namespace tokens and find the appropriate structured entry, if it does not exist add it. At the end StructuredArchiveEntry
// will point to the correct hierarchy entry for a given namespace
for ( int32 TokenIndex = 0 ; TokenIndex < NamespaceTokenCount ; + + TokenIndex )
{
TSharedPtr < FStructuredArchiveEntry > FoundNamespaceEntry ;
for ( int SubNamespaceIndex = 0 ; SubNamespaceIndex < StructuredArchiveEntry - > SubNamespaces . Num ( ) ; SubNamespaceIndex + + )
{
if ( StructuredArchiveEntry - > SubNamespaces [ SubNamespaceIndex ] - > Namespace = = NamespaceTokens [ TokenIndex ] )
{
FoundNamespaceEntry = StructuredArchiveEntry - > SubNamespaces [ SubNamespaceIndex ] ;
break ;
}
}
if ( ! FoundNamespaceEntry . IsValid ( ) )
{
int32 index = StructuredArchiveEntry - > SubNamespaces . Add ( MakeShareable ( new FStructuredArchiveEntry ( NamespaceTokens [ TokenIndex ] ) ) ) ;
FoundNamespaceEntry = StructuredArchiveEntry - > SubNamespaces [ index ] ;
}
StructuredArchiveEntry = FoundNamespaceEntry ;
}
// We add the unstructured Archive entry to the hierarchy
StructuredArchiveEntry - > ArchiveEntries . AddUnique ( UnstructuredArchiveEntry ) ;
}
}
2014-09-25 18:03:04 -04:00
void FJsonInternationalizationArchiveSerializer : : SortStructuredData ( TSharedPtr < FStructuredArchiveEntry > InElement )
2014-03-14 14:13:41 -04:00
{
if ( ! InElement . IsValid ( ) )
{
return ;
}
// Sort the manifest entries by source text.
InElement - > ArchiveEntries . Sort ( FCompareArchiveEntryBySourceAndKey ( ) ) ;
// Sort the subnamespaces by namespace string
InElement - > SubNamespaces . Sort ( FCompareStructuredArchiveEntryByNamespace ( ) ) ;
// Do the sorting for each of the subnamespaces
for ( TArray < TSharedPtr < FStructuredArchiveEntry > > : : TIterator Iter ( InElement - > SubNamespaces . CreateIterator ( ) ) ; Iter ; + + Iter )
{
TSharedPtr < FStructuredArchiveEntry > SubElement = * Iter ;
SortStructuredData ( SubElement ) ;
}
}
2014-09-25 18:03:04 -04:00
void FJsonInternationalizationArchiveSerializer : : StructuredDataToJsonObj ( TSharedPtr < const FStructuredArchiveEntry > InElement , TSharedRef < FJsonObject > OutJsonObj )
2014-03-14 14:13:41 -04:00
{
OutJsonObj - > SetStringField ( TAG_NAMESPACE , InElement - > Namespace ) ;
TArray < TSharedPtr < FJsonValue > > NamespaceArray ;
TArray < TSharedPtr < FJsonValue > > EntryArray ;
//Write namespace content entries
for ( TArray < TSharedPtr < FArchiveEntry > > : : TConstIterator Iter ( InElement - > ArchiveEntries ) ; Iter ; + + Iter )
{
const TSharedPtr < FArchiveEntry > Entry = * Iter ;
TSharedPtr < FJsonObject > EntryNode = MakeShareable ( new FJsonObject ) ;
2014-09-14 19:37:14 -04:00
FString ProcessedSourceText = Entry - > Source . Text ;
FString ProcessedTranslation = Entry - > Translation . Text ;
2014-03-14 14:13:41 -04:00
TSharedPtr < FJsonObject > SourceNode ;
if ( Entry - > Source . MetadataObj . IsValid ( ) )
{
2014-09-25 18:03:04 -04:00
FJsonInternationalizationMetaDataSerializer : : SerializeMetadata ( Entry - > Source . MetadataObj . ToSharedRef ( ) , SourceNode ) ;
2014-03-14 14:13:41 -04:00
}
if ( ! SourceNode . IsValid ( ) )
{
SourceNode = MakeShareable ( new FJsonObject ) ;
}
SourceNode - > SetStringField ( TAG_SOURCE_TEXT , ProcessedSourceText ) ;
EntryNode - > SetObjectField ( TAG_SOURCE , SourceNode ) ;
TSharedPtr < FJsonObject > TranslationNode ;
if ( Entry - > Translation . MetadataObj . IsValid ( ) )
{
2014-09-25 18:03:04 -04:00
FJsonInternationalizationMetaDataSerializer : : SerializeMetadata ( Entry - > Translation . MetadataObj . ToSharedRef ( ) , TranslationNode ) ;
2014-03-14 14:13:41 -04:00
}
if ( ! TranslationNode . IsValid ( ) )
{
TranslationNode = MakeShareable ( new FJsonObject ) ;
}
TranslationNode - > SetStringField ( TAG_TRANSLATION_TEXT , ProcessedTranslation ) ;
EntryNode - > SetObjectField ( TAG_TRANSLATION , TranslationNode ) ;
if ( Entry - > KeyMetadataObj . IsValid ( ) )
{
TSharedPtr < FJsonObject > KeyDataNode ;
2014-09-25 18:03:04 -04:00
FJsonInternationalizationMetaDataSerializer : : SerializeMetadata ( Entry - > KeyMetadataObj . ToSharedRef ( ) , KeyDataNode ) ;
2014-03-14 14:13:41 -04:00
if ( KeyDataNode . IsValid ( ) )
{
EntryNode - > SetObjectField ( TAG_METADATA_KEY , KeyDataNode ) ;
}
}
// We only add the optional field if it is true, it is assumed to be false otherwise.
if ( Entry - > bIsOptional = = true )
{
EntryNode - > SetBoolField ( TAG_OPTIONAL , Entry - > bIsOptional ) ;
}
EntryArray . Add ( MakeShareable ( new FJsonValueObject ( EntryNode ) ) ) ;
}
//Write the subnamespaces
for ( TArray < TSharedPtr < FStructuredArchiveEntry > > : : TConstIterator Iter ( InElement - > SubNamespaces ) ; Iter ; + + Iter )
{
const TSharedPtr < FStructuredArchiveEntry > SubElement = * Iter ;
if ( SubElement . IsValid ( ) )
{
TSharedRef < FJsonObject > SubObject = MakeShareable ( new FJsonObject ) ;
StructuredDataToJsonObj ( SubElement , SubObject ) ;
NamespaceArray . Add ( MakeShareable ( new FJsonValueObject ( SubObject ) ) ) ;
}
}
if ( EntryArray . Num ( ) > 0 )
{
OutJsonObj - > SetArrayField ( TAG_CHILDREN , EntryArray ) ;
}
if ( NamespaceArray . Num ( ) > 0 )
{
OutJsonObj - > SetArrayField ( TAG_SUBNAMESPACES , NamespaceArray ) ;
}
}