Как обернуть вложенную строку (метаданные) в TagGroup

Мои импортированные метаданные имеют предопределенную вложенную структуру (пример показан ниже), которая представляет собой одну строку после импорта в DM. Все метаданные и каждый уровень ветвления заключены в фигурные скобки {}, все ключи и значения ключей заключены в кавычки "" и разделены двоеточием:

Мой вопрос: как преобразовать данные и обернуть их в объект TagGroup, чтобы операции индексирования, поиска и доступа к данным можно было выполнять намного проще?

Спасибо!

Вот пример:

{
    "Acquisition": {
        "AcquisitionStartDatetime": {
            "DateTime": "1473763749"
        },
        "AcquisitionDatetime": {
            "DateTime": "0"
        },
        "BeamType": "",
        "SourceType": "Monochromator"
    },
    "BinaryResult": {
        "AcquisitionUnit": "",
        "CompositionType": "",
        "DetectorIndex": "3",
        "Detector": "HAADF",
        "PixelSize": {
            "width": "5.408370946750477e-010",
            "height": "5.408370946750477e-010"
        },
        "PixelUnitX": "m",
        "PixelUnitY": "m",
        "Offset": {
            "x": "-2.769085924736244e-007",
            "y": "-2.769085924736244e-007"
        },
        "Encoding": ""
    },
    "Sample": "",
    "GasInjectionSystems": ""
}

person w4m    schedule 26.09.2016    source источник
comment
На самом деле эти метаданные конвертируются из данных FEI Velox 1.2 (.emd), файлового формата на основе HDF5. Я пытаюсь реализовать рабочий скрипт для импорта файлов. Любая помощь будет оценена по достоинству!   -  person w4m    schedule 26.09.2016
comment
Кажется, вам понадобится умеренно сложный рекурсивный синтаксический анализатор строк, который нелегко предоставить в виде краткого ответа на вопрос на этом форуме. Я сделал аналогичный синтаксический анализатор для импорта XML в DM и хотел бы помочь вам с вашим приложением. Если вы заинтересованы в совместной работе, пожалуйста, свяжитесь со мной через веб-сайт/контактную информацию, указанную в моем профиле.   -  person Mike Kundmann    schedule 27.09.2016
comment
Наличие скрипта импорта Velox наверняка заинтересует многих! Если у вас что-то работает, было бы здорово, если бы вы могли отправить его в базу данных скриптов DM. также.   -  person BmyGuest    schedule 27.09.2016
comment
@BmyGuest это то, для чего я предназначен.   -  person w4m    schedule 27.09.2016
comment
@MikeKundmann Спасибо за подсказки! Я все еще учусь, делая. Я свяжусь с вами позже, когда это будет действительно важно для меня. :-)   -  person w4m    schedule 27.09.2016
comment
@BmyGuest Только что закончил рабочую версию и протестировал ее на этой неделе. загружен в базу несколько минут назад. :-)   -  person w4m    schedule 07.10.2016


Ответы (2)


Изменить: исправлен код сейчас

Я уверен, что возможна более очищенная версия, но она выполняет задачу:

Class CMetaStringToTagGroup
{
    // Find next string bracketed by " in input string, starting search
    // at given index. Returns string and end-position of search
    string FindNextKeyName( object self, string input, number & searchPos )
    {
        number totalLength = len( input )
        number start = 0, end = 0
        while( searchPos < totalLength )
        {
            searchpos++
            if ( "\"" == input.mid(searchpos-1,1) )
            {
                if ( !start ) 
                    start = searchpos-1
                else
                    {
                    end = searchpos-1
                    return input.mid(start+1,end-start-1)
                    }
            }
        }
        return ""
    }

    // Returns the next of either "{" ,  "}" or """ after a collon ":"
    string GetNextIndicator( object self, string input, number & searchPos )
    {
        number totalLength = len( input )
        while( searchPos < totalLength )
        {
            searchpos++        
            if ( "{" == input.mid(searchpos-1,1) )
                return "{"
            if ( "}" == input.mid(searchpos-1,1) )
                return "}"
            if ( "\"" == input.mid(searchpos-1,1) )
                return "\""
        }
        return ""
    }

    // In a tag-path string, find location of last colon 
    number findLastColon( object self, string input )
    {
        number totalLength = len( input )
        number lastPos = -1
        number searchPos = 0
        while( searchPos < totalLength )
        {
            searchpos++
            if ( ":" == input.mid(searchpos-1,1) )
                lastPos = searchpos-1
        }
        return lastPos
    }

    // Parse textstring and create taggroup from it
    TagGroup CreateTagFromText( object self, string input )
    {
        TagGroup rootTG = NewTagGroup()
        string currentPath = ""

        number totalLength = len( input )
        number searchPos = 0 
        number searchPos2
        string keyName, indicator
        while( searchPos < totalLength )
        {
            // search for new key or closing bracket, whatever first 
            searchPos2 = searchPos
            indicator = self.GetNextIndicator( input, searchPos2 )
            keyName = self.FindNextKeyName( input, searchPos )
            if ( ( "}" == indicator ) && (searchpos2<searchPos ) )
            {
                // decrease hierachy
                number cutPos = self.findLastColon( currentPath )
                currentPath = left( currentPath, cutPos )
                result("\n DEC ")
                searchPos = searchPos2
            }
            else
            {
                // Either add value or new  sub-tagGroup
                if ( "" == keyname ) break; // No more keys found
                indicator = self.GetNextIndicator( input, searchPos )
                if ( "" == indicator ) break;   // No more indicator found -- should not happen!

                if ( "{" == indicator )
                {
                    // increase hierachy
                    currentPath += ":" + keyname
                    rootTg.TagGroupSetTagAsTagGroup( currentPath, NewTagGroup() )
                    result("\n INC ("+keyname+")")
                }
                else if ( "\"" == indicator )
                {
                    // Add value
                    searchPos--
                    string valStr = self.FindNextKeyName( input, searchPos )
                    rootTg.TagGroupSetTagAsString( currentPath + ":" + keyname, valStr )
                    result("\n   VAL("+keyname+") ")
                }
            }
        }
        return rootTg
    }
}

{
    // Reading input text
    number fileID = OpenFileForReading("C:\\test.txt")
    object fStream = NewStreamFromFileReference(fileID,1)
    string inputStr = fStream.StreamReadAsText(0, fStream.StreamGetSize())

    // Parsing text
    number searchPos = 0
    TagGroup con = alloc(CMetaStringToTagGroup).CreateTagFromText( inputStr )
    con.TagGroupopenBrowserwindow("",0)
}

введите здесь описание изображения

person BmyGuest    schedule 27.09.2016
comment
Большое спасибо! Результаты кажутся не совсем правильными... Acquisition, BinaryResult, Sample и GasInjectionSystem должны быть на одном уровне. По моему наблюдению за структурой метаданных папки имеют шаблон [FOLDER_NAME : { ], а записи имеют шаблон [ENTRY_NAME : ENTRY_VALUE], первый символ { и последний } лучше пропустить. Сначала я попытаюсь следовать вашему коду... - person w4m; 27.09.2016
comment
@w4m исправил это сейчас. - person BmyGuest; 28.09.2016
comment
Кстати, существует ли какая-либо функция, которая записывает эту красивую группу тегов в тег изображения? По документу в справке DM и вашему справочнику я нашел только группы функций Set...Note(image, string). - person w4m; 30.09.2016
comment
вставка строки img.SetStringNote(currentPath + : + keyname, valStr) в функцию CreateTagFromText кажется, по крайней мере, способом добавить иерархические теги к изображению, конечно, в этой функции нужен дополнительный varabal (image & img). - person w4m; 30.09.2016
comment
Вы ищете ImageGetTagGroup(), TagGroupCopyTagsFrom() и TagGroupSetTagAsTagGroup(). Возможно, также используйте TagGroupClone(), чтобы убедиться, что вы случайно не «прикрепили» одну группу тегов к более чем одному изображению в памяти. (Хотя есть случаи, когда это нужно;). Если у вас есть какие-либо вопросы, задайте их как отдельный вопрос. - person BmyGuest; 30.09.2016

Как отметил Майк в комментариях, это скорее утомительная, чем сложная задача. Лучше всего создать небольшой скрипт парсера в отдельном классе, который превращает форматы

"NAME: { в TagGroups ярлыка NAME плюс повышенный уровень иерархии.

а также

"NAME": "VALUE" в теги с ярлыком NAME и значением VALUE.

а также

} на шаг "уменьшить уровень иерархии".

Обратите внимание, что вы всегда можете использовать String при создании группы тегов, даже если вы хотите прочитать ее как число позднее.

Рекурсивно просматривайте и запоминайте «уровень группы тегов», в котором вы находитесь, чтобы каждый новый тег добавлялся на этом уровне. Пропустить недопустимые разделы текста.

В справочной документации F1 DigitalMicrograph есть раздел о строках, в котором перечислены команды, которые вам, скорее всего, понадобятся:

String StringAppend( String s1, String s2 ) 
Number StringCompare( String s1, String s2 ) 
Boolean StringIsValid( String str ) 
String StringToLower( String str ) 
String StringToUpper( String str ) 
Number len( String str )
String left( String str, Number count )
String mid( String str, Number offset, Number count )
String right( String str, Number count )
Number find( String s1, String s2 )
Number val( String str )

Кроме того, я считаю иногда полезным использовать tert-оператор для строк, как в

number isOK = 1
string str =  isOK == 1 ? "true" : "false"

Кроме того, при синтаксическом анализе следите за символами табуляции и возврата строки. (Используйте \t и \n для их поиска. Вам может понадобиться использовать "\n" и "\t" при указании int в строке, так как \ будет интерпретироваться как управляющий символ.)

person BmyGuest    schedule 27.09.2016