1

Тема: AHK: Разбор ответа VK API или JSON

Всем привет. Проблема такая - не могу разобрать ответ от VK API.
Загружаю файл через UrlDownloadToFile посредством запроса к VK.
Ответ загружаю в %ID группы%.txt
Пробывал через RegExMatch и через RegExReplace, но так как в ответе приходит слишком много запрещенных символов, то AHK постоянно выдает ошибки по поводу запрещенных символов или вовсе неправильно понимает меня.
Пример файла ответа прикрепляю ниже.

+ открыть спойлер

{"response":{"count":8132,"items":[{"id":65166,"from_id":230663862,"date":1495702509,"text":"[id15397810|Кирилл], и пусть весь мир подождет, мы же тут свадьбу фотаем))) Наверное, автоматически включается бессмертие и подключается разрешение на нарушения))","reply_to_user":15397810,"reply_to_comment":65066,"pid":440481750},{"id":65066,"from_id":15397810,"date":1495619512,"text":"Типичный переход дороги в неположенном месте.","pid":440481750},{"id":64686,"from_id":62897079,"date":1495299141,"text":"Пробег 17500, 2016 г.в. цена 510тыс.руб. По всем вопросам в личку","pid":456254153},{"id":64532,"from_id":200417393,"date":1495127968,"text":"Пятнашка","pid":400840174},{"id":64530,"from_id":200417393,"date":1495127932,"text":"Пятнашка","pid":400826413},{"id":64465,"from_id":408535812,"date":1495038511,"text":"Прям на фоне трека выгледит клас","pid":456252859},{"id":64464,"from_id":408535812,"date":1495038507,"text":"","attachments":[{"type":"sticker","sticker":{"id":4483,"product_id":143,"photo_64":"https:\/\/vk.com\/images\/stickers\/4483\/64.png","photo_128":"https:\/\/vk.com\/images\/stickers\/4483\/128.png","photo_256":"https:\/\/vk.com\/images\/stickers\/4483\/256.png","photo_352":"https:\/\/vk.com\/images\/stickers\/4483\/352.png","photo_512":"https:\/\/vk.com\/images\/stickers\/4483\/512.png","width":256,"height":256}}],"pid":456252859},{"id":63669,"from_id":12305785,"date":1494511135,"text":"Антон, на 10 до 200разметка","reply_to_user":108744649,"reply_to_comment":63446,"pid":456252930},{"id":63510,"from_id":410054677,"date":1494417393,"text":"800","pid":456252930},{"id":63446,"from_id":108744649,"date":1494324744,"text":"10","pid":456252930},{"id":63269,"from_id":20008734,"date":1494169687,"text":"Еще бы)) он крут","pid":456252860},{"id":63267,"from_id":393615385,"date":1494159412,"text":"сам выложил ....сам лайкнул... красавчик","pid":456252877},{"id":63254,"from_id":31855993,"date":1494149322,"text":"Продам ВАЗ 21093 2003 год выпуска; карбюратор; 240000 пробег; музыка пионер; сигнализация; стоимость 65 000 ( торг уместен). Обращаться по телефону 8-982-320-34-68.","pid":456252656},{"id":63218,"from_id":358605259,"date":1494132071,"text":"Дебилы","pid":456252849},{"id":63217,"from_id":33478310,"date":1494132071,"text":"Автомобиль, ехавший по трассе, на все деньги!!!

Skype: darya281293
(Не обращайте внимания на логин)

2

Re: AHK: Разбор ответа VK API или JSON

Извиняюсь за мультитему. Выходила ошибка о невозможности отправить сообщение.

Skype: darya281293
(Не обращайте внимания на логин)

3

Re: AHK: Разбор ответа VK API или JSON

Вк даёт ответ в формате json. Ищи библиотеки для его парса на ахк

4

Re: AHK: Разбор ответа VK API или JSON

Apache пишет:

AHK постоянно выдает ошибки по поводу запрещенных символов

Разве в AHK есть запрещённые символы?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

5

Re: AHK: Разбор ответа VK API или JSON

Нашел json.ahk библиотеку. Код прикладываю:

/**
 * Lib: JSON.ahk
 *     JSON lib for AutoHotkey.
 * Version:
 *     v2.1.3 [updated 04/18/2016 (MM/DD/YYYY)]
 * License:
 *     WTFPL [http://wtfpl.net/]
 * Requirements:
 *     Latest version of AutoHotkey (v1.1+ or v2.0-a+)
 * Installation:
 *     Use #Include JSON.ahk or copy into a function library folder and then
 *     use #Include <JSON>
 * Links:
 *     GitHub:     - https://github.com/cocobelgica/AutoHotkey-JSON
 *     Forum Topic - http://goo.gl/r0zI8t
 *     Email:      - cocobelgica <at> gmail <dot> com
 */


/**
 * Class: JSON
 *     The JSON object contains methods for parsing JSON and converting values
 *     to JSON. Callable - NO; Instantiable - YES; Subclassable - YES;
 *     Nestable(via #Include) - NO.
 * Methods:
 *     Load() - see relevant documentation before method definition header
 *     Dump() - see relevant documentation before method definition header
 */
class JSON
{
	/**
	 * Method: Load
	 *     Parses a JSON string into an AHK value
	 * Syntax:
	 *     value := JSON.Load( text [, reviver ] )
	 * Parameter(s):
	 *     value      [retval] - parsed value
	 *     text    [in, ByRef] - JSON formatted string
	 *     reviver   [in, opt] - function object, similar to JavaScript's
	 *                           JSON.parse() 'reviver' parameter
	 */
	class Load extends JSON.Functor
	{
		Call(self, ByRef text, reviver:="")
		{
			this.rev := IsObject(reviver) ? reviver : false
		; Object keys(and array indices) are temporarily stored in arrays so that
		; we can enumerate them in the order they appear in the document/text instead
		; of alphabetically. Skip if no reviver function is specified.
			this.keys := this.rev ? {} : false

			static quot := Chr(34), bashq := "\" . quot
			     , json_value := quot . "{[01234567890-tfn"
			     , json_value_or_array_closing := quot . "{[]01234567890-tfn"
			     , object_key_or_object_closing := quot . "}"

			key := ""
			is_key := false
			root := {}
			stack := [root]
			next := json_value
			pos := 0

			while ((ch := SubStr(text, ++pos, 1)) != "") {
				if InStr(" `t`r`n", ch)
					continue
				if !InStr(next, ch, 1)
					this.ParseError(next, text, pos)

				holder := stack[1]
				is_array := holder.IsArray

				if InStr(",:", ch) {
					next := (is_key := !is_array && ch == ",") ? quot : json_value

				} else if InStr("}]", ch) {
					ObjRemoveAt(stack, 1)
					next := stack[1]==root ? "" : stack[1].IsArray ? ",]" : ",}"

				} else {
					if InStr("{[", ch) {
					; Check if Array() is overridden and if its return value has
					; the 'IsArray' property. If so, Array() will be called normally,
					; otherwise, use a custom base object for arrays
						static json_array := Func("Array").IsBuiltIn || ![].IsArray ? {IsArray: true} : 0
					
					; sacrifice readability for minor(actually negligible) performance gain
						(ch == "{")
							? ( is_key := true
							  , value := {}
							  , next := object_key_or_object_closing )
						; ch == "["
							: ( value := json_array ? new json_array : []
							  , next := json_value_or_array_closing )
						
						ObjInsertAt(stack, 1, value)

						if (this.keys)
							this.keys[value] := []
					
					} else {
						if (ch == quot) {
							i := pos
							while (i := InStr(text, quot,, i+1)) {
								value := StrReplace(SubStr(text, pos+1, i-pos-1), "\\", "\u005c")

								static tail := A_AhkVersion<"2" ? 0 : -1
								if (SubStr(value, tail) != "\")
									break
							}

							if (!i)
								this.ParseError("'", text, pos)

							  value := StrReplace(value,  "\/",  "/")
							, value := StrReplace(value, bashq, quot)
							, value := StrReplace(value,  "\b", "`b")
							, value := StrReplace(value,  "\f", "`f")
							, value := StrReplace(value,  "\n", "`n")
							, value := StrReplace(value,  "\r", "`r")
							, value := StrReplace(value,  "\t", "`t")

							pos := i ; update pos
							
							i := 0
							while (i := InStr(value, "\",, i+1)) {
								if !(SubStr(value, i+1, 1) == "u")
									this.ParseError("\", text, pos - StrLen(SubStr(value, i+1)))

								uffff := Abs("0x" . SubStr(value, i+2, 4))
								if (A_IsUnicode || uffff < 0x100)
									value := SubStr(value, 1, i-1) . Chr(uffff) . SubStr(value, i+6)
							}

							if (is_key) {
								key := value, next := ":"
								continue
							}
						
						} else {
							value := SubStr(text, pos, i := RegExMatch(text, "[\]\},\s]|$",, pos)-pos)

							static number := "number", integer :="integer"
							if value is %number%
							{
								if value is %integer%
									value += 0
							}
							else if (value == "true" || value == "false")
								value := %value% + 0
							else if (value == "null")
								value := ""
							else
							; we can do more here to pinpoint the actual culprit
							; but that's just too much extra work.
								this.ParseError(next, text, pos, i)

							pos += i-1
						}

						next := holder==root ? "" : is_array ? ",]" : ",}"
					} ; If InStr("{[", ch) { ... } else

					is_array? key := ObjPush(holder, value) : holder[key] := value

					if (this.keys && this.keys.HasKey(holder))
						this.keys[holder].Push(key)
				}
			
			} ; while ( ... )

			return this.rev ? this.Walk(root, "") : root[""]
		}

		ParseError(expect, ByRef text, pos, len:=1)
		{
			static quot := Chr(34), qurly := quot . "}"
			
			line := StrSplit(SubStr(text, 1, pos), "`n", "`r").Length()
			col := pos - InStr(text, "`n",, -(StrLen(text)-pos+1))
			msg := Format("{1}`n`nLine:`t{2}`nCol:`t{3}`nChar:`t{4}"
			,     (expect == "")     ? "Extra data"
			    : (expect == "'")    ? "Unterminated string starting at"
			    : (expect == "\")    ? "Invalid \escape"
			    : (expect == ":")    ? "Expecting ':' delimiter"
			    : (expect == quot)   ? "Expecting object key enclosed in double quotes"
			    : (expect == qurly)  ? "Expecting object key enclosed in double quotes or object closing '}'"
			    : (expect == ",}")   ? "Expecting ',' delimiter or object closing '}'"
			    : (expect == ",]")   ? "Expecting ',' delimiter or array closing ']'"
			    : InStr(expect, "]") ? "Expecting JSON value or array closing ']'"
			    :                      "Expecting JSON value(string, number, true, false, null, object or array)"
			, line, col, pos)

			static offset := A_AhkVersion<"2" ? -3 : -4
			throw Exception(msg, offset, SubStr(text, pos, len))
		}

		Walk(holder, key)
		{
			value := holder[key]
			if IsObject(value) {
				for i, k in this.keys[value] {
					; check if ObjHasKey(value, k) ??
					v := this.Walk(value, k)
					if (v != JSON.Undefined)
						value[k] := v
					else
						ObjDelete(value, k)
				}
			}
			
			return this.rev.Call(holder, key, value)
		}
	}

	/**
	 * Method: Dump
	 *     Converts an AHK value into a JSON string
	 * Syntax:
	 *     str := JSON.Dump( value [, replacer, space ] )
	 * Parameter(s):
	 *     str        [retval] - JSON representation of an AHK value
	 *     value          [in] - any value(object, string, number)
	 *     replacer  [in, opt] - function object, similar to JavaScript's
	 *                           JSON.stringify() 'replacer' parameter
	 *     space     [in, opt] - similar to JavaScript's JSON.stringify()
	 *                           'space' parameter
	 */
	class Dump extends JSON.Functor
	{
		Call(self, value, replacer:="", space:="")
		{
			this.rep := IsObject(replacer) ? replacer : ""

			this.gap := ""
			if (space) {
				static integer := "integer"
				if space is %integer%
					Loop, % ((n := Abs(space))>10 ? 10 : n)
						this.gap .= " "
				else
					this.gap := SubStr(space, 1, 10)

				this.indent := "`n"
			}

			return this.Str({"": value}, "")
		}

		Str(holder, key)
		{
			value := holder[key]

			if (this.rep)
				value := this.rep.Call(holder, key, ObjHasKey(holder, key) ? value : JSON.Undefined)

			if IsObject(value) {
			; Check object type, skip serialization for other object types such as
			; ComObject, Func, BoundFunc, FileObject, RegExMatchObject, Property, etc.
				static type := A_AhkVersion<"2" ? "" : Func("Type")
				if (type ? type.Call(value) == "Object" : ObjGetCapacity(value) != "") {
					if (this.gap) {
						stepback := this.indent
						this.indent .= this.gap
					}

					is_array := value.IsArray
				; Array() is not overridden, rollback to old method of
				; identifying array-like objects. Due to the use of a for-loop
				; sparse arrays such as '[1,,3]' are detected as objects({}). 
					if (!is_array) {
						for i in value
							is_array := i == A_Index
						until !is_array
					}

					str := ""
					if (is_array) {
						Loop, % value.Length() {
							if (this.gap)
								str .= this.indent
							
							v := this.Str(value, A_Index)
							str .= (v != "") ? v . "," : "null,"
						}
					} else {
						colon := this.gap ? ": " : ":"
						for k in value {
							v := this.Str(value, k)
							if (v != "") {
								if (this.gap)
									str .= this.indent

								str .= this.Quote(k) . colon . v . ","
							}
						}
					}

					if (str != "") {
						str := RTrim(str, ",")
						if (this.gap)
							str .= stepback
					}

					if (this.gap)
						this.indent := stepback

					return is_array ? "[" . str . "]" : "{" . str . "}"
				}
			
			} else ; is_number ? value : "value"
				return ObjGetCapacity([value], 1)=="" ? value : this.Quote(value)
		}

		Quote(string)
		{
			static quot := Chr(34), bashq := "\" . quot

			if (string != "") {
				  string := StrReplace(string,  "\",  "\\")
				; , string := StrReplace(string,  "/",  "\/") ; optional in ECMAScript
				, string := StrReplace(string, quot, bashq)
				, string := StrReplace(string, "`b",  "\b")
				, string := StrReplace(string, "`f",  "\f")
				, string := StrReplace(string, "`n",  "\n")
				, string := StrReplace(string, "`r",  "\r")
				, string := StrReplace(string, "`t",  "\t")

				static rx_escapable := A_AhkVersion<"2" ? "O)[^\x20-\x7e]" : "[^\x20-\x7e]"
				while RegExMatch(string, rx_escapable, m)
					string := StrReplace(string, m.Value, Format("\u{1:04x}", Ord(m.Value)))
			}

			return quot . string . quot
		}
	}

	/**
	 * Property: Undefined
	 *     Proxy for 'undefined' type
	 * Syntax:
	 *     undefined := JSON.Undefined
	 * Remarks:
	 *     For use with reviver and replacer functions since AutoHotkey does not
	 *     have an 'undefined' type. Returning blank("") or 0 won't work since these
	 *     can't be distnguished from actual JSON values. This leaves us with objects.
	 *     Replacer() - the caller may return a non-serializable AHK objects such as
	 *     ComObject, Func, BoundFunc, FileObject, RegExMatchObject, and Property to
	 *     mimic the behavior of returning 'undefined' in JavaScript but for the sake
	 *     of code readability and convenience, it's better to do 'return JSON.Undefined'.
	 *     Internally, the property returns a ComObject with the variant type of VT_EMPTY.
	 */
	Undefined[]
	{
		get {
			static empty := {}, vt_empty := ComObject(0, &empty, 1)
			return vt_empty
		}
	}

	class Functor
	{
		__Call(method, ByRef arg, args*)
		{
		; When casting to Call(), use a new instance of the "function object"
		; so as to avoid directly storing the properties(used across sub-methods)
		; into the "function object" itself.
			if IsObject(method)
				return (new this).Call(method, arg, args*)
			else if (method == "")
				return (new this).Call(arg, args*)
		}
}

К библиотеке написан пример: Value := JSON.load (text, [reviever]
Мой код:

#include json.ahk
Fileread, JSON, 1.txt
content := JSON.Load (JSON)

msgbox %Content%

В msgbox приходит обычный JSON файл без изменений.
Не совсем дружу с работами с библиотекой.

Skype: darya281293
(Не обращайте внимания на логин)

6 (изменено: Apache, 2017-05-27 15:42:19)

Re: AHK: Разбор ответа VK API или JSON

был бы рад получить хоть 1 пример с получением text и pid в переменную и ее выводом на msgbox с помощью библиотеки.

Код программы загрузки комментариев на всякий случай:

gfile=группы.txt
B=0
Filereadline, token, token.txt, 1
Loop, Read, %gfile%
{
urldownloadtofile, https://api.vk.com/method/photos.getAllComments?v=5.4&owner_id=-%A_LoopReadLine%&access_token=%token%, %A_LoopReadLine%.txt
B++
}
msgbox Загружено %B% групп
return
GuiClose:
ExitApp
Skype: darya281293
(Не обращайте внимания на логин)

7

Re: AHK: Разбор ответа VK API или JSON

Apache, вы уже тут столько ненужных буквы понаписали, а требуется-то всего лишь имеющийся JSON (тот, что вы привели в первом посте — не валидный), и чёткое объяснение, что именно вам из него нужно получить.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

8

Re: AHK: Разбор ответа VK API или JSON

Пришлось самому писать парс для JSON, полученным UrlDownloadToFile.

Fileread, line, 1.txt ; Чтение файла-ответа JSON c однострочным форматом, полученным UrlDownloadToFile (ПОД ЗАМЕНУ)
FoundPos := 1 ; Обнуляем позицию для CommentsID
FoundPosID := 1 ; Обнуляем позицию для From_ID
;foundpos := RegExMatch, (Line, "\Q{\E.id.:(.*?)\Q,\E", subpart)
;Поиск и запись ID комментария
Loop
	{
	FoundPos := RegExMatch(line, """id"":(.*?),""from_id""\:", SubPat, Foundpos) ; Поиск CommentsID
	FoundPosID := RegExMatch(line, """from_id"":(.*?),""date"":", FromID, FoundposID) ; Поиск From_ID
msgbox, subpat1 - %subpat1%`n subpat2 - %subpat2%`n subpat - %subpat% `n foundpos - %foundpos% ; Выводим результаты
IfInString, Subpat1, "" ;Проверяем на пустую строку
	{
	Msgbox Запись окончена ; Если строка пуста
	exitapp ; Выодим отсюда
	}
	else ; Если строка не пуста
		{
		IniWrite, %subpat1%, 1.ini, %SubPat1%, Commentid ; Записываем CommentID в INI-Файл 
		Foundpos := Foundpos+10
		}
		IfInString, From_ID1, "" ;Проверяем на пустую строку From_ID
	{
	Msgbox Запись окончена ; Если строка пуста
	exitapp ; Выодим отсюда
	}
	else ; Если строка не пуста
		{
		IniWrite, %FromID1%, 1.ini, %SubPat1%, From_ID ; Записываем CommentID в INI-Файл 
		FoundposID := FoundposID+10
		}
	}

Если есть мысли облегчения поиска - выслушаю. А так все работает и пишет в Ini-файл.

Skype: darya281293
(Не обращайте внимания на логин)

9 (изменено: ypppu, 2017-05-29 18:32:10)

Re: AHK: Разбор ответа VK API или JSON

Еще проблема: Через раз выдает неверные данные из различныx параметров.
Код:

+ открыть спойлер

FoundPos := 1

Loop, %A_WorkingDir%\pars\*.txt
	{
		
		;If (Size>100)
		;	{
				
				GroupID = %A_LoopFileName%
				RegExMatch(A_LoopFileName, "(.*).txt", GroupID)
				;MsgBox, %GroupID1%
				
				Loop
					{
						FileRead, line, %A_WorkingDir%\pars\%A_LoopFileName%
						FoundPos := RegExMatch(line, "{""id"":(.*?),""from_id"":(.*?),""date"":(.*?),""text"":""(.*?)"",""pid"":(.*?)}", pat, Foundpos) ; Поиск CommentsID
			
						msgbox %pat1%`n`n %pat2%`n `n %pat3%`n`n %pat4%`n`n %pat5%`n`n %pat6%`n`n %pat7%`n`n %FoundPos%`n %A_LoopFileName% 
						FoundPos := FoundPos+1
						
						if !pat1
							Goto, Label1
						else
							IniWrite, %pat1%, %A_WorkingDir%\Ini\%GroupID1%.ini, Comment, CommentID
						
					}
		;	}
		
		Label1:
		;MsgBox, %CommentsID1% %A_LoopFileName% %CommentsID%
		
	}

Пример файла недоJSON'a:

+ открыть спойлер
{"response":{"count":46,"items":[{"id":861,"from_id":-100039716,"date":1486129352,"text":"","attachments":[{"type":"photo","photo":{"id":456241399,"album_id":-8,"owner_id":-100039716,"user_id":100,"photo_75":"https:\/\/pp.userapi.com\/c626416\/v626416742\/504f0\/Og0xQc3_u8g.jpg","photo_130":"https:\/\/pp.userapi.com\/c626416\/v626416742\/504f1\/zKSNzaGaFSo.jpg","photo_604":"https:\/\/pp.userapi.com\/c626416\/v626416742\/504f2\/yY7rxXQ4UfY.jpg","photo_807":"https:\/\/pp.userapi.com\/c626416\/v626416742\/504f3\/sha1_cYDxRI.jpg","width":628,"height":709,"text":"","date":1486129353,"access_key":"ad3a291f0985e374f5"}}],"pid":456240757},{"id":859,"from_id":9508742,"date":1484481219,"text":"Магазин расположен по адресу: https:\/\/laluna.com.ua\/","pid":456240683},{"id":757,"from_id":-100039716,"date":1468651686,"text":"Победитель: https:\/\/vk.com\/id280623449","pid":420766709},{"id":753,"from_id":-100039716,"date":1467359388,"text":"","attachments":[{"type":"photo","photo":{"id":418772290,"album_id":-8,"owner_id":-100039716,"user_id":100,"photo_75":"https:\/\/pp.userapi.com\/c626619\/v626619742\/18995\/ZdWcIaIVb64.jpg","photo_130":"https:\/\/pp.userapi.com\/c626619\/v626619742\/18996\/w8RzfjkPZGs.jpg","photo_604":"https:\/\/pp.userapi.com\/c626619\/v626619742\/18997\/SMCVRNe4e_4.jpg","photo_807":"https:\/\/pp.userapi.com\/c626619\/v626619742\/18998\/BcaFpiWEX1w.jpg","width":725,"height":758,"text":"","date":1467359391,"access_key":"a92d1477496bcc3b34"}}],"pid":418638891},{"id":752,"from_id":-100039716,"date":1467358122,"text":"","attachments":[{"type":"photo","photo":{"id":418770175,"album_id":-8,"owner_id":-100039716,"user_id":100,"photo_75":"https:\/\/pp.userapi.com\/c626619\/v626619742\/1898d\/bOT44f6Ly7A.jpg","photo_130":"https:\/\/pp.userapi.com\/c626619\/v626619742\/1898e\/uv1piux9izw.jpg","photo_604":"https:\/\/pp.userapi.com\/c626619\/v626619742\/1898f\/It3J6TQnu7k.jpg","photo_807":"https:\/\/pp.userapi.com\/c626619\/v626619742\/18990\/ZGyTRT6UMug.jpg","width":725,"height":646,"text":"","date":1467358122,"access_key":"cb7ac5a7df16a138f9"}}],"pid":418639265},{"id":750,"from_id":-100039716,"date":1467272359,"text":"","attachments":[{"type":"photo","photo":{"id":418637936,"album_id":-8,"owner_id":-100039716,"user_id":100,"photo_75":"https:\/\/pp.userapi.com\/c626619\/v626619742\/18771\/x5NFtv5odt0.jpg","photo_130":"https:\/\/pp.userapi.com\/c626619\/v626619742\/18772\/_M6Yz-DUX3Q.jpg","photo_604":"https:\/\/pp.userapi.com\/c626619\/v626619742\/18773\/EXFs5-MK-BY.jpg","photo_807":"https:\/\/pp.userapi.com\/c626619\/v626619742\/18774\/UvYWrin5fJw.jpg","width":733,"height":568,"text":"","date":1467272358,"access_key":"ad0ce9382e0c6277fa"}}],"pid":414998677},{"id":739,"from_id":-100039716,"date":1465755035,"text":"Победитель: *Оля Друзь (https:\/\/vk.com\/id200487815)","pid":414998677},{"id":738,"from_id":-100039716,"date":1465754752,"text":"Видео розыгрыша: https:\/\/vk.com\/video-91401362_456239568","attachments":[{"type":"video","video":{"id":456239568,"owner_id":-91401362,"title":"любой из представленных подарков 
Skype: darya281293
(Не обращайте внимания на логин)

10 (изменено: ypppu, 2017-05-29 18:32:56)

Re: AHK: Разбор ответа VK API или JSON

Проблема в том, что он ищет, например:
"ID":323,"From_id":-9382993......."ID":324,"From_id":-9382992......
Скрипт то наxодит в %pat1% "323", то ,"From_id":-9382993......."ID":324, то "-9382993......."ID":".
Выxодит, что он может начать поиск верно, но закончить на следующем ответе, бывает вовсе верно ищет, а бывает что вовсе в месте поиска ID выводит From_id.

Начал искать с from_id до Нужного мне id.

+ открыть спойлер

http://imgdepo.com/id/10695193.jpg

Нашел вообще параметры с прикрепленного видео

z=video9508742_456239023
+ открыть спойлер

http://imgdepo.com/id/10695194.jpg

pat1 тоже перепрыгнул и закинул все в переменную, pat4 (Текст сообщения) начала писать с 1-го и закончил вторым ответом.

+ открыть спойлер

http://imgdepo.com/id/10695195.jpg

Пример поиска из файла примера на скриншотаx.

Skype: darya281293
(Не обращайте внимания на логин)

11

Re: AHK: Разбор ответа VK API или JSON

Apache, прочитайте еще раз внимательно сообщение номер 8.

12

Re: AHK: Разбор ответа VK API или JSON

Уважаемые, а возможно распарсить следующий JSON


{"response":{"count":1327,"items":[{"id":456239092,"album_id":43057155,"owner_id":-4410189,"user_id":468722286,"photo_75":"https:\/\/pp.userapi.com\/c840126\/v840126582\/7499d\/-WVOjdnpJZI.jpg","photo_130":"https:\/\/pp.userapi.com\/c840126\/v840126582\/7499e\/uQcruFXFMdk.jpg","photo_604":"https:\/\/pp.userapi.com\/c840126\/v840126582\/7499f\/y43rEl-TAkA.jpg","width":450,"height":600,"text":"","date":1516419054,"likes":{"user_likes":0,"count":0},"reposts":{"count":0}},{"id":456239078,"album_id":42994275,"owner_id":-4410189,"user_id":178805115,"photo_75":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286c2\/zjw36aXGsrg.jpg","photo_130":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286c3\/6pqM4Ptzqzo.jpg","photo_604":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286c4\/bVjh384ZaLs.jpg","width":600,"height":300,"text":"http:\/\/fas.st\/UF5a3","date":1498331078,"likes":{"user_likes":0,"count":0},"reposts":{"count":0}},{"id":456239077,"album_id":203534724,"owner_id":-4410189,"user_id":178805115,"photo_75":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286bb\/jUH3jjLme28.jpg","photo_130":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286bc\/dvTzcguDpI0.jpg","photo_604":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286bd\/6uf84mYlyu8.jpg","width":600,"height":300,"text":"http:\/\/fas.st\/UF5a3","date":1498331077,"likes":{"user_likes":0,"count":0},"reposts":{"count":0}},{"id":456239049,"album_id":43023085,"owner_id":-4410189,"user_id":100,"photo_75":"https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe0\/8F1vthi-tjo.jpg","photo_130":"https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe1\/KxtmhBBZuY4.jpg","photo_604":"https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe2\/ZoT63tAPvHg.jpg","photo_807":"https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe3\/zbDlM4tkBS8.jpg","photo_1280":"https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe4\/sKgl1iXF-5o.jpg","width":877,"height":561,"text":"Эскиз к роману в стихах А.С.Пушкина \"Евгений Онегин\". Автор Lena Ashraf.","date":1492174953,"likes":{"user_likes":0,"count":1},"reposts":{"count":0}}]}}

и получить список из выборочных значений в следующем формате


"id":456239092
"owner_id":-4410189
https:\/\/pp.userapi.com\/c840126\/v840126582\/7499f\/y43rEl-TAkA.jpg
"text":""

"id":456239078
"owner_id":-4410189
https:\/\/pp.userapi.com\/c639429\/v639429115\/286c4\/bVjh384ZaLs.jpg
"text":"http:\/\/fas.st\/UF5a3"

"id":456239077
"owner_id":-4410189
https:\/\/pp.userapi.com\/c639429\/v639429115\/286bd\/6uf84mYlyu8.jpg
"text":"http:\/\/fas.st\/UF5a3"

"id":456239049
"owner_id":-4410189
https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe4\/sKgl1iXF-5o.jpg
"text":"Эскиз к роману в стихах А.С.Пушкина \"Евгений Онегин\". Автор Lena Ashraf."

где первый "count" попадает в отдельную переменную, а ссылки на изображения представляют собой их увеличенные версии? А то я сам и в получении одного значения не преуспел)).

13 (изменено: KusochekDobra, 2018-02-03 18:57:12)

Re: AHK: Разбор ответа VK API или JSON

Пользуюсь для работы с JSON, вот этой приспособой, немного модифицированного примера, исходник которого можно посмотреть по ссылке в примере:


;-----------------------------------------------------------------------------------------------------------------------------------------
; JSON.ahk (Определение класса)
; Слегка переделаный src -> https://community.spiceworks.com/scripts/show/3203-autohotkey-json-encoder-decoder
; by CaptainCode on Jun 20, 2015
; Методы:
;		Decode(принимает строковое представление JSON) - возвращает объект AHK
;		Encode(принимает AHK объект) - Возвращает строку JSON
; JScript -> https://docs.microsoft.com/en-us/scripting/javascript/reference/javascript-reference
;-----------------------------------------------------------------------------------------------------------------------------------------

Class JSON {
	SC := "", jsCode := ""
	__New() {	; Создать COM-объект, который будет использоваться для декодирования строки
		this.SC				:= ComObjCreate("ScriptControl") 
		this.SC.Language	:= "JScript"
		ComObjError(false)
		; Описание тела функции JScript (похож на JavaScript), не AHK.
		this.jsCode			:=
		(Join`r`n
		"function arrangeForAhkTraversing(obj) {
			if(obj instanceof Array) {
				for(var i=0 ; i < obj.length ; ++i)
					obj[i] = arrangeForAhkTraversing(obj[i]) ;
				return ['array',obj] ;
			} else if(obj instanceof Object) {
				var keys = [], values = [] ;
				for(var key in obj){
					keys.push(key) ;
					values.push(arrangeForAhkTraversing(obj[key])) ;
				}
				return ['object',[keys,values]] ;
			} else
				return [typeof obj,obj] ;
		}"
		)
	}
	
	; Декодирует JSON-строку в массив, вызывая функцию JS с помощью COM-объекта и
	; возвращает объект AHK.
	Decode(jsonStr) {
		this.SC.ExecuteStatement(this.jsCode "; obj=" jsonStr)
		return this.convertJScriptObjToAhks( this.SC.Eval("arrangeForAhkTraversing(obj)") )
	}
	
	convertJScriptObjToAhks(jsObj){
		if(jsObj[0]="object") {
			obj := {}, keys := jsObj[1][0], values := jsObj[1][1]
			loop % keys.length
				obj[keys[A_INDEX-1]] := this.convertJScriptObjToAhks( values[A_INDEX-1] )
			return obj
		} else if(jsObj[0]="array") {
			array := []
			loop % jsObj[1].length
				array.insert(this.convertJScriptObjToAhks( jsObj[1][A_INDEX-1] ))
			return array
		} else
			return jsObj[1]
	}
	
	Encode(obj) {
		str := ""
		array := true
		for k in obj {
			if (k == A_Index)
				continue
			array := false
			break
		} if (array)
			for a, b in obj
				str .= (IsObject(b) ? this.Encode(b) :  b) . ","
		else
			for a, b in obj
				str .= ("""" a """:") . (IsObject(b) ? this.Encode(b) : """" b """") . ","
		str := RTrim(str, " ,")
		return (array ? "[" str "]" : "{" str "}")
	}
}

Сохраните в файле "JSON.ahk"
Пример извлечения значений из четвёртого элемента в массиве "items":


#SingleInstance, Force
#NoEnv
SetWorkingDir, A_ScriptDir

#Include <JSON>
oJson := New JSON()

jText = {"response":{"count":1327,"items":[{"id":456239092,"album_id":43057155,"owner_id":-4410189,"user_id":468722286,"photo_75":"https:\/\/pp.userapi.com\/c840126\/v840126582\/7499d\/-WVOjdnpJZI.jpg","photo_130":"https:\/\/pp.userapi.com\/c840126\/v840126582\/7499e\/uQcruFXFMdk.jpg","photo_604":"https:\/\/pp.userapi.com\/c840126\/v840126582\/7499f\/y43rEl-TAkA.jpg","width":450,"height":600,"text":"","date":1516419054,"likes":{"user_likes":0,"count":0},"reposts":{"count":0}},{"id":456239078,"album_id":42994275,"owner_id":-4410189,"user_id":178805115,"photo_75":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286c2\/zjw36aXGsrg.jpg","photo_130":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286c3\/6pqM4Ptzqzo.jpg","photo_604":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286c4\/bVjh384ZaLs.jpg","width":600,"height":300,"text":"http:\/\/fas.st\/UF5a3","date":1498331078,"likes":{"user_likes":0,"count":0},"reposts":{"count":0}},{"id":456239077,"album_id":203534724,"owner_id":-4410189,"user_id":178805115,"photo_75":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286bb\/jUH3jjLme28.jpg","photo_130":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286bc\/dvTzcguDpI0.jpg","photo_604":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286bd\/6uf84mYlyu8.jpg","width":600,"height":300,"text":"http:\/\/fas.st\/UF5a3","date":1498331077,"likes":{"user_likes":0,"count":0},"reposts":{"count":0}},{"id":456239049,"album_id":43023085,"owner_id":-4410189,"user_id":100,"photo_75":"https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe0\/8F1vthi-tjo.jpg","photo_130":"https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe1\/KxtmhBBZuY4.jpg","photo_604":"https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe2\/ZoT63tAPvHg.jpg","photo_807":"https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe3\/zbDlM4tkBS8.jpg","photo_1280":"https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe4\/sKgl1iXF-5o.jpg","width":877,"height":561,"text":"Эскиз к роману в стихах А.С.Пушкина \"Евгений Онегин\". Автор Lena Ashraf.","date":1492174953,"likes":{"user_likes":0,"count":1},"reposts":{"count":0}}]}}

oJ		 := oJson.Decode(jText)		; Превратить в объект AHK
frElem	 := oJ.response.items[4]	; Четвёртый элемент из запроса

; Доступ к полям объекта через точку, или квадратные скобки
textItem := Format("id = {1}`nalbum_id = {2}`nowner_id = {3}`nphoto_75 = {4}`ntext = {5}"
				, frElem["id"], frElem.album_id, frElem.owner_id, frElem.photo_75, frElem["text"])

MsgBox,,Title,% textItem

return

Escape::
	ExitApp

UPD:
Единственное, метод Encode() не устанавливает escape символы, так что может не везде быть применим, но для контекста AHK годится более чем.

+ DD

14

Re: AHK: Разбор ответа VK API или JSON

KusochekDobra
Спасибо! А можно ли извлечь одномоментно все элементы, не определяя по номеру? И есть ли настройка извлечения именно последнего фото с бОльшим разрешением и случайным номером ключа — внутри каждого элемента? Или настройка извлечения всех изображений — которые можно будет уже потом очистить от уменьшенных копий?

15 (изменено: KusochekDobra, 2018-02-03 19:19:16)

Re: AHK: Разбор ответа VK API или JSON

Как Вы это себе представляете? Это ведь стандартный синтаксис AHK. Используется содержимое массива, с доступом через ключ "items". В Вашем примере 4 элемента, чтобы перебрать поочерёдно все элементы этого массива используйте цикл, например:


Loop,% oJ.response.items.Length() {
	item := oJ.response.items[A_Index]
	MsgBox,,Title,% Format("id = {1}`nalbum_id = {2}`nowner_id = {3}`nphoto_75 = {4}`ntext = {5}"
				, item["id"], item.album_id, item.owner_id, item.photo_75, item["text"])
}

UPD:
Чтобы перебрать вообще все поля всех элементов:


oJ := oJson.Decode(jText)		; Превратить в объект AHK
allItemsText := ""
Loop,% oJ.response.items.Length() {
	item := oJ.response.items[A_Index], txt := "`nItem № " . A_Index . "`n"
	for k, v in item {
		txt .= k " = " v "`n"
	}
	allItemsText .= txt
}
MsgBox,,Title,% allItemsText
+ DD

16

Re: AHK: Разбор ответа VK API или JSON

А как думаете: для сотни элементов будет ли эффективней заменами регулярными выражениями перевести нужные ключи на новую строку с уникальным символом в начале, и потом извлечь всё начинающееся этим символом, — или использовать метод разбора JSON, которым, как я понял, получить определенные фото (либо все фото) нельзя?

17

Re: AHK: Разбор ответа VK API или JSON

Вы видимо плохо представляете себе, что такое JSON. Советую почитать об этом в Гугле.
Если очень коротко, то JSON-строка помещается всем своим содержимым в переменную и всё, что Вы видите в текстовом представлении до её преобразования, доступно из объекта, в который она превращается. Нужно только указать индекс для элементов-массивов, или имя ключа, для полей объектов.

18

Re: AHK: Разбор ответа VK API или JSON

На мой взгляд, использование объекта более оправданно, нежели парсинг. Так Вы получаете удобный, структурированный объект в памяти программы, которым можно манипулировать в процессе, извлекая из него нужные значения, как при использовании любой переменной.

19

Re: AHK: Разбор ответа VK API или JSON

По-моему, парсинг в любом случае придется использовать, поскольку вариации имён ключей у фотографий не постоянные. Тут лучше наверно сразу парсить.

20

Re: AHK: Разбор ответа VK API или JSON

А что это изменит?
В случае с парсингом Вы будете искать в тексте конкретные вхождения последовательности символов, точно так же представляющих имя соответствующего имени ключа в объекте. Разве нет?

Ещё раз, поясните пожалуйста, что конкретно нужно получать из элементов массива "items"?

21 (изменено: DD, 2018-02-03 20:36:36)

Re: AHK: Разбор ответа VK API или JSON

Требовалось получать следующие четыре ключа,

"id":456239092
"owner_id":-4410189
https:\/\/pp.userapi.com\/c840126\/v840126582\/7499f\/y43rEl-TAkA.jpg
"text":""

со ссылкой на последнюю фотографию внутри каждого элемента. Фотографии в каждом элементе даны в нескольких разрешениях, а нужна последняя, бОльшего формата. С этой целью добавил к коду рег. шаблон, перед обработкой оставляющий только крупные фото:


#SingleInstance, Force
#NoEnv
SetWorkingDir, A_ScriptDir

#Include JSON.ahk
oJson := New JSON()

jText = {"response":{"count":1327,"items":[{"id":456239092,"album_id":43057155,"owner_id":-4410189,"user_id":468722286,"photo_75":"https:\/\/pp.userapi.com\/c840126\/v840126582\/7499d\/-WVOjdnpJZI.jpg","photo_130":"https:\/\/pp.userapi.com\/c840126\/v840126582\/7499e\/uQcruFXFMdk.jpg","photo_604":"https:\/\/pp.userapi.com\/c840126\/v840126582\/7499f\/y43rEl-TAkA.jpg","width":450,"height":600,"text":"","date":1516419054,"likes":{"user_likes":0,"count":0},"reposts":{"count":0}},{"id":456239078,"album_id":42994275,"owner_id":-4410189,"user_id":178805115,"photo_75":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286c2\/zjw36aXGsrg.jpg","photo_130":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286c3\/6pqM4Ptzqzo.jpg","photo_604":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286c4\/bVjh384ZaLs.jpg","width":600,"height":300,"text":"http:\/\/fas.st\/UF5a3","date":1498331078,"likes":{"user_likes":0,"count":0},"reposts":{"count":0}},{"id":456239077,"album_id":203534724,"owner_id":-4410189,"user_id":178805115,"photo_75":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286bb\/jUH3jjLme28.jpg","photo_130":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286bc\/dvTzcguDpI0.jpg","photo_604":"https:\/\/pp.userapi.com\/c639429\/v639429115\/286bd\/6uf84mYlyu8.jpg","width":600,"height":300,"text":"http:\/\/fas.st\/UF5a3","date":1498331077,"likes":{"user_likes":0,"count":0},"reposts":{"count":0}},{"id":456239049,"album_id":43023085,"owner_id":-4410189,"user_id":100,"photo_75":"https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe0\/8F1vthi-tjo.jpg","photo_130":"https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe1\/KxtmhBBZuY4.jpg","photo_604":"https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe2\/ZoT63tAPvHg.jpg","photo_807":"https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe3\/zbDlM4tkBS8.jpg","photo_1280":"https:\/\/pp.userapi.com\/c638723\/v638723276\/2bfe4\/sKgl1iXF-5o.jpg","width":877,"height":561,"text":"Эскиз к роману в стихах А.С.Пушкина \"Евгений Онегин\". Автор Lena Ashraf.","date":1492174953,"likes":{"user_likes":0,"count":1},"reposts":{"count":0}}]}}

     jText := RegExReplace(jText, """photo_\d+""[^\}]*""photo_\d+""", """photo_big""")

oJ		 := oJson.Decode(jText)		; Превратить в объект AHK

Loop,% oJ.response.items.Length() {
	item := oJ.response.items[A_Index]
	MsgBox,,Title,% Format("id = {1}`nowner_id = {2}`nphoto_big = {3}`ntext = {4}"
				, item["id"], item.owner_id, item.photo_big, item["text"])
}
return

22 (изменено: KusochekDobra, 2018-02-03 21:23:33)

Re: AHK: Разбор ответа VK API или JSON

Поскольку все разрешения имеют фиксированные имена ключей(это видно из примера), можно перечислить их в убывающем порядке в массиве и перебирать ключи текущего элемента массива из этого перечисления:


oJ := oJson.Decode(jText)		; Превратить в объект AHK
photoKeys := ["photo_1280","photo_807","photo_604","photo_130","photo_75"]
Loop,% oJ.response.items.Length() {
	item := oJ.response.items[A_Index],  i := 1
	while (!item.HasKey(photoKeys[i++]))
		Continue
	MsgBox,,Title,% Format("id = {1}`nowner_id = {2}`nphoto_big = {3}`ntext = {4}"
					, item["id"], item.owner_id, item[photoKeys[i-1]], item["text"])
}

Если в перечислении из примера не все варианты, их наверняка можно найти в документации и включить в массив.

23

Re: AHK: Разбор ответа VK API или JSON

Интересный вариант, спасибо!

24

Re: AHK: Разбор ответа VK API или JSON

KusochekDobra пишет:

Чтобы перебрать вообще все поля всех элементов:

По какой причине в следующем JSON все поля не перебираются? (Для работы скрипта нужно подключить код JSON.ahk из 13 поста) —


#SingleInstance, Force
#NoEnv
SetWorkingDir, A_ScriptDir

#Include %A_ScriptDir%\JSON.ahk
oJson := New JSON()

jText = {"response":[{"id":3161,"from_id":146251528,"to_id":146251528,"date":1507114850,"post_type":"post","text":"Невозможно преподать опыт. Нельзя научиться от другого, как жить. Нужно только прожить жизнь и сделать какой-то свой вывод. Его нельзя передать другому. Мы часто говорим: нужно воспользоваться опытом наших отцов, но тогда это было бы очень просто. К сожалению, мы должны получить свой собственный жизненный опыт, чтобы иметь свое собственное отношение к жизни. Но когда мы его получаем, к сожалению жизнь кончается и мы не можем им воспользоваться. А молодые растут, не слушаются стариков и правильно делают, а когда они его тоже находят, жизнь их также кончается, и в этом и есть закон жизни.\nНельзя человека заставить испытывать внушенные чувства, можно опираться лишь на свой жизненный опыт для того чтобы понять, что такое жизнь.\n\nА. Тарковский","post_source":{"type":"api","platform":"android"},"comments":{"count":0,"groups_can_post":true,"can_post":0},"likes":{"count":20,"user_likes":0,"can_like":1,"can_publish":1},"reposts":{"count":0,"user_reposted":0}}]}


;Чтобы перебрать вообще все поля всех элементов:

oJ := oJson.Decode(jText)		; Превратить в объект AHK
allItemsText := ""
Loop,% oJ.response.items.Length() {
	item := oJ.response.items[A_Index], txt := "`nItem № " . A_Index . "`n"
	for k, v in item {
		txt .= k " = " v "`n"
	}
	allItemsText .= txt
}
MsgBox,,Title,% allItemsText
return

25

Re: AHK: Разбор ответа VK API или JSON

Самое первое, что бросается в глаза:

Loop,% oJ.response.items.Length() {

Здесь, Вы обращаетесь к Length(), не существующего поля items, в объекте response, представленном линейным массивом, к членам которого обращаются по индексу. Внутри него, кстати, в Вашем примере, всего один элемент.

А вообще, по нужде перешёл на "1.1.28.02 x64" и при загрузке, ссылается на строку ComObjCreate("ScriptControl"), говоря, что класс не зарегистрирован. Так что, приспособа оказалась не живучей, в силу своей НЕ универсальности. Предлагаю пользоваться забугорным вариантом из поста №5 этой беседы, или найти на просторах форума другие адаптации.

26 (изменено: Malcev, 2018-05-04 17:23:03)

Re: AHK: Разбор ответа VK API или JSON

KusochekDobra пишет:

А вообще, по нужде перешёл на "1.1.28.02 x64" и при загрузке, ссылается на строку ComObjCreate("ScriptControl"), говоря, что класс не зарегистрирован. Так что, приспособа оказалась не живучей, в силу своей НЕ универсальности.

http://forum.script-coding.com/viewtopi … 74#p103274

KusochekDobra пишет:

Предлагаю пользоваться забугорным вариантом из поста №5 этой беседы

Он может глючить:

json_str ={"test":0E-7}
JSON.Load(json_str)


/**
 * Lib: JSON.ahk
 *     JSON lib for AutoHotkey.
 * Version:
 *     v2.1.3 [updated 04/18/2016 (MM/DD/YYYY)]
 * License:
 *     WTFPL [http://wtfpl.net/]
 * Requirements:
 *     Latest version of AutoHotkey (v1.1+ or v2.0-a+)
 * Installation:
 *     Use #Include JSON.ahk or copy into a function library folder and then
 *     use #Include <JSON>
 * Links:
 *     GitHub:     - https://github.com/cocobelgica/AutoHotkey-JSON
 *     Forum Topic - http://goo.gl/r0zI8t
 *     Email:      - cocobelgica <at> gmail <dot> com
 */


/**
 * Class: JSON
 *     The JSON object contains methods for parsing JSON and converting values
 *     to JSON. Callable - NO; Instantiable - YES; Subclassable - YES;
 *     Nestable(via #Include) - NO.
 * Methods:
 *     Load() - see relevant documentation before method definition header
 *     Dump() - see relevant documentation before method definition header
 */
class JSON
{
	/**
	 * Method: Load
	 *     Parses a JSON string into an AHK value
	 * Syntax:
	 *     value := JSON.Load( text [, reviver ] )
	 * Parameter(s):
	 *     value      [retval] - parsed value
	 *     text    [in, ByRef] - JSON formatted string
	 *     reviver   [in, opt] - function object, similar to JavaScript's
	 *                           JSON.parse() 'reviver' parameter
	 */
	class Load extends JSON.Functor
	{
		Call(self, ByRef text, reviver:="")
		{
			this.rev := IsObject(reviver) ? reviver : false
		; Object keys(and array indices) are temporarily stored in arrays so that
		; we can enumerate them in the order they appear in the document/text instead
		; of alphabetically. Skip if no reviver function is specified.
			this.keys := this.rev ? {} : false

			static quot := Chr(34), bashq := "\" . quot
			     , json_value := quot . "{[01234567890-tfn"
			     , json_value_or_array_closing := quot . "{[]01234567890-tfn"
			     , object_key_or_object_closing := quot . "}"

			key := ""
			is_key := false
			root := {}
			stack := [root]
			next := json_value
			pos := 0

			while ((ch := SubStr(text, ++pos, 1)) != "") {
				if InStr(" `t`r`n", ch)
					continue
				if !InStr(next, ch, 1)
					this.ParseError(next, text, pos)

				holder := stack[1]
				is_array := holder.IsArray

				if InStr(",:", ch) {
					next := (is_key := !is_array && ch == ",") ? quot : json_value

				} else if InStr("}]", ch) {
					ObjRemoveAt(stack, 1)
					next := stack[1]==root ? "" : stack[1].IsArray ? ",]" : ",}"

				} else {
					if InStr("{[", ch) {
					; Check if Array() is overridden and if its return value has
					; the 'IsArray' property. If so, Array() will be called normally,
					; otherwise, use a custom base object for arrays
						static json_array := Func("Array").IsBuiltIn || ![].IsArray ? {IsArray: true} : 0
					
					; sacrifice readability for minor(actually negligible) performance gain
						(ch == "{")
							? ( is_key := true
							  , value := {}
							  , next := object_key_or_object_closing )
						; ch == "["
							: ( value := json_array ? new json_array : []
							  , next := json_value_or_array_closing )
						
						ObjInsertAt(stack, 1, value)

						if (this.keys)
							this.keys[value] := []
					
					} else {
						if (ch == quot) {
							i := pos
							while (i := InStr(text, quot,, i+1)) {
								value := StrReplace(SubStr(text, pos+1, i-pos-1), "\\", "\u005c")

								static tail := A_AhkVersion<"2" ? 0 : -1
								if (SubStr(value, tail) != "\")
									break
							}

							if (!i)
								this.ParseError("'", text, pos)

							  value := StrReplace(value,  "\/",  "/")
							, value := StrReplace(value, bashq, quot)
							, value := StrReplace(value,  "\b", "`b")
							, value := StrReplace(value,  "\f", "`f")
							, value := StrReplace(value,  "\n", "`n")
							, value := StrReplace(value,  "\r", "`r")
							, value := StrReplace(value,  "\t", "`t")

							pos := i ; update pos
							
							i := 0
							while (i := InStr(value, "\",, i+1)) {
								if !(SubStr(value, i+1, 1) == "u")
									this.ParseError("\", text, pos - StrLen(SubStr(value, i+1)))

								uffff := Abs("0x" . SubStr(value, i+2, 4))
								if (A_IsUnicode || uffff < 0x100)
									value := SubStr(value, 1, i-1) . Chr(uffff) . SubStr(value, i+6)
							}

							if (is_key) {
								key := value, next := ":"
								continue
							}
						
						} else {
							value := SubStr(text, pos, i := RegExMatch(text, "[\]\},\s]|$",, pos)-pos)

							static number := "number", integer :="integer"
							if value is %number%
							{
								if value is %integer%
									value += 0
							}
							else if (value == "true" || value == "false")
								value := %value% + 0
							else if (value == "null")
								value := ""
							else
							; we can do more here to pinpoint the actual culprit
							; but that's just too much extra work.
								this.ParseError(next, text, pos, i)

							pos += i-1
						}

						next := holder==root ? "" : is_array ? ",]" : ",}"
					} ; If InStr("{[", ch) { ... } else

					is_array? key := ObjPush(holder, value) : holder[key] := value

					if (this.keys && this.keys.HasKey(holder))
						this.keys[holder].Push(key)
				}
			
			} ; while ( ... )

			return this.rev ? this.Walk(root, "") : root[""]
		}

		ParseError(expect, ByRef text, pos, len:=1)
		{
			static quot := Chr(34), qurly := quot . "}"
			
			line := StrSplit(SubStr(text, 1, pos), "`n", "`r").Length()
			col := pos - InStr(text, "`n",, -(StrLen(text)-pos+1))
			msg := Format("{1}`n`nLine:`t{2}`nCol:`t{3}`nChar:`t{4}"
			,     (expect == "")     ? "Extra data"
			    : (expect == "'")    ? "Unterminated string starting at"
			    : (expect == "\")    ? "Invalid \escape"
			    : (expect == ":")    ? "Expecting ':' delimiter"
			    : (expect == quot)   ? "Expecting object key enclosed in double quotes"
			    : (expect == qurly)  ? "Expecting object key enclosed in double quotes or object closing '}'"
			    : (expect == ",}")   ? "Expecting ',' delimiter or object closing '}'"
			    : (expect == ",]")   ? "Expecting ',' delimiter or array closing ']'"
			    : InStr(expect, "]") ? "Expecting JSON value or array closing ']'"
			    :                      "Expecting JSON value(string, number, true, false, null, object or array)"
			, line, col, pos)

			static offset := A_AhkVersion<"2" ? -3 : -4
			throw Exception(msg, offset, SubStr(text, pos, len))
		}

		Walk(holder, key)
		{
			value := holder[key]
			if IsObject(value) {
				for i, k in this.keys[value] {
					; check if ObjHasKey(value, k) ??
					v := this.Walk(value, k)
					if (v != JSON.Undefined)
						value[k] := v
					else
						ObjDelete(value, k)
				}
			}
			
			return this.rev.Call(holder, key, value)
		}
	}

	/**
	 * Method: Dump
	 *     Converts an AHK value into a JSON string
	 * Syntax:
	 *     str := JSON.Dump( value [, replacer, space ] )
	 * Parameter(s):
	 *     str        [retval] - JSON representation of an AHK value
	 *     value          [in] - any value(object, string, number)
	 *     replacer  [in, opt] - function object, similar to JavaScript's
	 *                           JSON.stringify() 'replacer' parameter
	 *     space     [in, opt] - similar to JavaScript's JSON.stringify()
	 *                           'space' parameter
	 */
	class Dump extends JSON.Functor
	{
		Call(self, value, replacer:="", space:="")
		{
			this.rep := IsObject(replacer) ? replacer : ""

			this.gap := ""
			if (space) {
				static integer := "integer"
				if space is %integer%
					Loop, % ((n := Abs(space))>10 ? 10 : n)
						this.gap .= " "
				else
					this.gap := SubStr(space, 1, 10)

				this.indent := "`n"
			}

			return this.Str({"": value}, "")
		}

		Str(holder, key)
		{
			value := holder[key]

			if (this.rep)
				value := this.rep.Call(holder, key, ObjHasKey(holder, key) ? value : JSON.Undefined)

			if IsObject(value) {
			; Check object type, skip serialization for other object types such as
			; ComObject, Func, BoundFunc, FileObject, RegExMatchObject, Property, etc.
				static type := A_AhkVersion<"2" ? "" : Func("Type")
				if (type ? type.Call(value) == "Object" : ObjGetCapacity(value) != "") {
					if (this.gap) {
						stepback := this.indent
						this.indent .= this.gap
					}

					is_array := value.IsArray
				; Array() is not overridden, rollback to old method of
				; identifying array-like objects. Due to the use of a for-loop
				; sparse arrays such as '[1,,3]' are detected as objects({}). 
					if (!is_array) {
						for i in value
							is_array := i == A_Index
						until !is_array
					}

					str := ""
					if (is_array) {
						Loop, % value.Length() {
							if (this.gap)
								str .= this.indent
							
							v := this.Str(value, A_Index)
							str .= (v != "") ? v . "," : "null,"
						}
					} else {
						colon := this.gap ? ": " : ":"
						for k in value {
							v := this.Str(value, k)
							if (v != "") {
								if (this.gap)
									str .= this.indent

								str .= this.Quote(k) . colon . v . ","
							}
						}
					}

					if (str != "") {
						str := RTrim(str, ",")
						if (this.gap)
							str .= stepback
					}

					if (this.gap)
						this.indent := stepback

					return is_array ? "[" . str . "]" : "{" . str . "}"
				}
			
			} else ; is_number ? value : "value"
				return ObjGetCapacity([value], 1)=="" ? value : this.Quote(value)
		}

		Quote(string)
		{
			static quot := Chr(34), bashq := "\" . quot

			if (string != "") {
				  string := StrReplace(string,  "\",  "\\")
				; , string := StrReplace(string,  "/",  "\/") ; optional in ECMAScript
				, string := StrReplace(string, quot, bashq)
				, string := StrReplace(string, "`b",  "\b")
				, string := StrReplace(string, "`f",  "\f")
				, string := StrReplace(string, "`n",  "\n")
				, string := StrReplace(string, "`r",  "\r")
				, string := StrReplace(string, "`t",  "\t")

				static rx_escapable := A_AhkVersion<"2" ? "O)[^\x20-\x7e]" : "[^\x20-\x7e]"
				while RegExMatch(string, rx_escapable, m)
					string := StrReplace(string, m.Value, Format("\u{1:04x}", Ord(m.Value)))
			}

			return quot . string . quot
		}
	}

	/**
	 * Property: Undefined
	 *     Proxy for 'undefined' type
	 * Syntax:
	 *     undefined := JSON.Undefined
	 * Remarks:
	 *     For use with reviver and replacer functions since AutoHotkey does not
	 *     have an 'undefined' type. Returning blank("") or 0 won't work since these
	 *     can't be distnguished from actual JSON values. This leaves us with objects.
	 *     Replacer() - the caller may return a non-serializable AHK objects such as
	 *     ComObject, Func, BoundFunc, FileObject, RegExMatchObject, and Property to
	 *     mimic the behavior of returning 'undefined' in JavaScript but for the sake
	 *     of code readability and convenience, it's better to do 'return JSON.Undefined'.
	 *     Internally, the property returns a ComObject with the variant type of VT_EMPTY.
	 */
	Undefined[]
	{
		get {
			static empty := {}, vt_empty := ComObject(0, &empty, 1)
			return vt_empty
		}
	}

	class Functor
	{
		__Call(method, ByRef arg, args*)
		{
		; When casting to Call(), use a new instance of the "function object"
		; so as to avoid directly storing the properties(used across sub-methods)
		; into the "function object" itself.
			if IsObject(method)
				return (new this).Call(method, arg, args*)
			else if (method == "")
				return (new this).Call(arg, args*)
		}
	}
}

27 (изменено: DD, 2018-05-04 17:53:50)

Re: AHK: Разбор ответа VK API или JSON

У меня ни один код не сработал с этим JSON.

28

Re: AHK: Разбор ответа VK API или JSON

Если в примере, который Вы запускаете всё так же, как описано в 24 сообщении, то ещё раз напомню, что внешний цикл Loop, запрашивает длину несуществующего поля items, предполагая его массивом "[]".

jText = {"response":[{"id":3161,"from_id":146251528,"to_id":146251528,"date":1507114850,"post_type":"post","text":"Невозможно преподать опыт. Нельзя научиться от другого, как жить. Нужно только прожить жизнь и сделать какой-то свой вывод. Его нельзя передать другому. Мы часто говорим: нужно воспользоваться опытом наших отцов, но тогда это было бы очень просто. К сожалению, мы должны получить свой собственный жизненный опыт, чтобы иметь свое собственное отношение к жизни. Но когда мы его получаем, к сожалению жизнь кончается и мы не можем им воспользоваться. А молодые растут, не слушаются стариков и правильно делают, а когда они его тоже находят, жизнь их также кончается, и в этом и есть закон жизни.\nНельзя человека заставить испытывать внушенные чувства, можно опираться лишь на свой жизненный опыт для того чтобы понять, что такое жизнь.\n\nА. Тарковский","post_source":{"type":"api","platform":"android"},"comments":{"count":0,"groups_can_post":true,"can_post":0},"likes":{"count":20,"user_likes":0,"can_like":1,"can_publish":1},"reposts":{"count":0,"user_reposted":0}}]}

29

Re: AHK: Разбор ответа VK API или JSON

Мой в этом случае не глючит:

json_str = {"test":0E-7}

ahkObj := JSON.Parse(json_str)
for k, v in ahkObj
   MsgBox, % k . " = " . v

class JSON
{
   static JS := JSON._GetJScripObject()
   
   Parse(JsonString)  {
      try oJSON := this.JS.("(" JsonString ")")
      catch  {
         MsgBox, Wrong JsonString!
         Return
      }
      Return this._CreateObject(oJSON)
   }
   
   Stringify(obj)  {
      if IsObject( obj )  {
         isArray := true
         for key in obj
            if !( key = A_Index || isArray := false )
               break
            
         for k, v in obj
            str .= ( A_Index = 1 ? "" : "," ) . ( isArray ? "" : this.Stringify(k) . ":" ) . this.Stringify(v)

         return isArray ? "[" str "]" : "{" str "}"
      }
      else if (obj*1)
         return obj
      
      for k, v in [["\", "\\"], [A_Tab, "\t"], ["""", "\"""], ["/", "\/"], ["`n", "\n"], ["`r", "\r"], [Chr(12), "\f"], [Chr(08), "\b"]]
         obj := StrReplace( obj, v[1], v[2] )
      
      while RegexMatch( obj, "[^\x20-\x7e]", key )  {
         str := Asc( key )
         val := "\u" . Chr( ( ( str >> 12 ) & 15 ) + ( ( ( str >> 12 ) & 15 ) < 10 ? 48 : 55 ) )
               . Chr( ( ( str >> 8 ) & 15 ) + ( ( ( str >> 8 ) & 15 ) < 10 ? 48 : 55 ) )
               . Chr( ( ( str >> 4 ) & 15 ) + ( ( ( str >> 4 ) & 15 ) < 10 ? 48 : 55 ) )
               . Chr( ( str & 15 ) + ( ( str & 15 ) < 10 ? 48 : 55 ) )
         obj := StrReplace(obj, key, val)
      }
      Return """" obj """"
   }
   
   GetFromUrl(url, body := "", contentType := "", userAgent := "")  {
      ; в случае удачи будет возвращена строка, в случае ошибки — массив с одним элементом-строкой с описанием ошибки
      try  {
         XmlHttp := ComObjCreate("Microsoft.XmlHttp")
         XmlHttp.Open("GET", url, false)
         ( contentType && XmlHttp.SetRequestHeader("Content-Type", contentType) )
         ( userAgent && XmlHttp.SetRequestHeader("User-Agent", userAgent) )
         XmlHttp.Send(body)
      }
      catch e
         Return ["Error!`n" . e.Message]
      status := XmlHttp.Status
      Return status = 200 ? XmlHttp.ResponseText : ["Error! Status: " . status . ", ResponseText: " . XmlHttp.ResponseText]
   }

   _GetJScripObject()  {
      VarSetCapacity(tmpFile, (MAX_PATH := 260) << !!A_IsUnicode, 0)
      DllCall("GetTempFileName", Str, A_Temp, Str, "AHK", UInt, 0, Str, tmpFile)
      
      FileAppend,
      (
      <component>
      <public><method name='eval'/></public>
      <script language='JScript'></script>
      </component>
      ), % tmpFile
      
      JS := ObjBindMethod( ComObjGet("script:" . tmpFile), "eval" )
      FileDelete, % tmpFile
      JSON._AddMethods(JS)
      Return JS
   }

   _AddMethods(ByRef JS)  {
      JScript =
      (
         Object.prototype.GetKeys = function () {
            var keys = []
            for (var k in this)
               if (this.hasOwnProperty(k))
                  keys.push(k)
            return keys
         }
         Object.prototype.IsArray = function () {
            var toStandardString = {}.toString
            return toStandardString.call(this) == '[object Array]'
         }
      )
      JS.("delete ActiveXObject; delete GetObject;")
      JS.(JScript)
   }

   _CreateObject(ObjJS)  {
      res := ObjJS.IsArray()
      if (res = "")
         Return ObjJS
      
      else if (res = -1)  {
         obj := []
         Loop % ObjJS.length
            obj[A_Index] := this._CreateObject(ObjJS[A_Index - 1])
      }
      else if (res = 0)  {
         obj := {}
         keys := ObjJS.GetKeys()
         Loop % keys.length
            k := keys[A_Index - 1], obj[k] := this._CreateObject(ObjJS[k])
      }
      Return obj
   }
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

30

Re: AHK: Разбор ответа VK API или JSON

KusochekDobra, теперь въехал, спасибо)).
teadrinker, а как наладить одномоментный вывод всех элементов?

31 (изменено: KusochekDobra, 2018-05-04 18:11:01)

Re: AHK: Разбор ответа VK API или JSON

У меня, Ваш вариант возвращает "test = 0".

1.1.28.02 x64

Понял, там не строка.

32

Re: AHK: Разбор ответа VK API или JSON

Любопытно, отчего с кодом teadrinker`а некоторые значения не выводятся, — "android", например?

33

Re: AHK: Разбор ответа VK API или JSON


oJ := JSON.Parse(jText)
MsgBox,,Title,% oJ.response[1].post_source.platform

У меня выводится.

34

Re: AHK: Разбор ответа VK API или JSON

А по умолчанию почему не выводятся, чтобы не было необходимости прописывать все возможные названия элементов?

35

Re: AHK: Разбор ответа VK API или JSON

Я не понял, что нужно.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

36

Re: AHK: Разбор ответа VK API или JSON

По какому "умолчанию"?
К полям объекта обращаются по их имени, как к обычным переменным, с разницей лишь в том, что через точку происходит указание наследования, к какому пространству имён относится эта переменная. Чтобы получить список всех полей объекта, его нужно обойти в цикле. Обычно, так же, для всех JSON, у API, к которому за ним обращаются, есть документация, в которой описаны все такие поля. Так что к обходу всего объекта, только для того чтобы узнать имена его полей, не обращаются.

37

Re: AHK: Разбор ответа VK API или JSON

Имелось в виду, что в коде ведь не указано про наличие "post_source" — однако его значение выводится, вот и возник вопрос об отсутствии такого умолчального извлечения для "platform". Собственно, о чём мы выше беседовали в части «перебрать вообще все поля всех элементов».

38

Re: AHK: Разбор ответа VK API или JSON

Ну почему же, посмотрите внимательно на правую часть jText и сравните именование пути к нужному полю после oJ := JSON.Parse(jText), по степени вложенности данных, границы которых обозначают фигурные и квадратные скобки:
oJ = весь объект.
response = его единственное поле, являющееся линейным массивом ([]), с единственным же элементом, к которому обращаемся указывая его индекс. Он и содержит все ключевые данные запроса.
post_source = один из ключей этих данных:


oJ := JSON.Parse(jText)
data := oJ.response[1]
s := ""
for k in data
	s .= k . "`n"
MsgBox,,Ключи,% s

Который сам, так же является объектом в этой нотации и уже в нём, "android" - содержится в ключе = platform.

Иными словами, platform - это переменная объекта post_source, который принадлежит первому элементу массива response, являющегося ключом объекта oJ и чтобы получить из неё "android", ВСЕГДА, нужно указывать этот путь.

+ DD

39

Re: AHK: Разбор ответа VK API или JSON

А возможна тогда такая же авто-обработка под-полей — ведь они структурированы в определенном формате?

40 (изменено: KusochekDobra, 2018-05-04 21:46:35)

Re: AHK: Разбор ответа VK API или JSON

Можно всё, что подсказывает воображение. Но насколько полезно и оправдывает ли цель, средства?
Можно перебрать все поля объекта рекурсивно, но их всё равно нужно где-то хранить. Если собирать их в массив, то по индексу Вы получите данные из полей объекта собранные в алфавитном порядке, утратив при этом возможность ассоциировать с именем поля, в котором данные хранились. Тогда, остаётся опять, объект:


oJ := JSON.Parse(jText)
data := {}
Repack(oJ, data)
s := ""
for k in data
	s .= k . "`n"
MsgBox,,Ключи,% s
MsgBox,,Платформа,% data.platform
ExitApp

Repack(obj_in, ByRef obj_out) {
	for k, v in obj_in
		IsObject(v) ? Repack(v, obj_out) : obj_out[k] := v
}

Здесь в функцию Repack() передаётся первым параметром исследуемый объект, а вторым, по ссылке, объект-хранилище, в который аккумулируются только конечные поля из всего объекта. Но это будет работать в этом примере, где response содержит всего один элемент, а если их будет несколько, тогда одноимённые поля будут перезаписаны теми, которые исследовались последними.

Update:
Даже, кстати, data.count - в этом примере, получит значение три раза => 0, 20 и 0.

41

Re: AHK: Разбор ответа VK API или JSON

Ясно. Спасибо за разъяснения, Вы очень добры. Конечная цель у меня JSON переделать в HTML.

42 (изменено: DD, 2019-02-09 18:18:43)

Re: AHK: Разбор ответа VK API или JSON

Возник вопрос по парсингу JSON Инстаграма скриптом teadrinker`а. Не удаётся понять, каким должно быть название общего объекта, в который входят все остальные. Для парсера по ссылке (где парсился JSON ЖЖ) — это был объект "comments". А каким он должен быть для Инсты? (Соответствующее место в коде выделил) —

ResponseText =
(
{"data":{"shortcode_media":{"edge_media_to_parent_comment":{"count":214,"page_info":{"has_next_page":true,"end_cursor":"{\"bifilter_token\": \"KBUBAgBAAP__________AAAAAAAAAAAA\"}"},"edges":[{"node":{"id":"17897868703293004","text":"КОММЕНТАРИЙ1","created_at":1549215799,"did_report_as_spam":false,"owner":{"id":"2127714636","is_verified":false,"profile_pic_url":"https://scontent-waw1-1.cdninstagram.com/vp/8b1c17aa6e2a4656204f9cdf4c2d4955/5CFE43C8/t51.2885-19/s150x150/14704945_203801490047027_7764135745324843008_a.jpg?_nc_ht=scontent-waw1-1.cdninstagram.com","username":"anutagim"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18024305008069155","text":"КОММЕНТАРИЙ2","created_at":1549215692,"did_report_as_spam":false,"owner":{"id":"8937356095","is_verified":false,"profile_pic_url":"https://instagram.fkul4-1.fna.fbcdn.net/vp/e5c5567fe4c80c801e89b770ef19cd7d/5CDDD9F1/t51.2885-19/44884218_345707102882519_2446069589734326272_n.jpg?_nc_ht=instagram.fkul4-1.fna.fbcdn.net","username":"chelovek_.m"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17965264054212404","text":"КОММЕНТАРИЙ3","created_at":1549215534,"did_report_as_spam":false,"owner":{"id":"2606911119","is_verified":false,"profile_pic_url":"https://scontent-waw1-1.cdninstagram.com/vp/22612abedd9e4807f6535165ec493fe9/5CF736BA/t51.2885-19/s150x150/34481264_247721202475350_8203240656068411392_n.jpg?_nc_ht=scontent-waw1-1.cdninstagram.com","username":"dimezzo"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18009939652122498","text":"КОММЕНТАРИЙ4","created_at":1549214731,"did_report_as_spam":false,"owner":{"id":"7084799449","is_verified":false,"profile_pic_url":"https://scontent-waw1-1.cdninstagram.com/vp/9c94166639397a8976ff13f2312e995c/5CF7930A/t51.2885-19/s150x150/31169585_1990747227856493_5538750551740645376_n.jpg?_nc_ht=scontent-waw1-1.cdninstagram.com","username":"larisavolkova3442"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18029917120025023","text":"КОММЕНТАРИЙ5","created_at":1549230065,"did_report_as_spam":false,"owner":{"id":"9169502797","is_verified":false,"profile_pic_url":"https://scontent-waw1-1.cdninstagram.com/vp/9b34956baa1800342d2dc2af01407baa/5CE4A098/t51.2885-19/s150x150/44843568_506726413167283_1791644804367515648_n.jpg?_nc_ht=scontent-waw1-1.cdninstagram.com","username":"dmitr00071rus"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":1,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[{"node":{"id":"17985996481196353","text":"КОММЕНТАРИЙ6","created_at":1549260364,"did_report_as_spam":false,"owner":{"id":"1701676825","is_verified":false,"profile_pic_url":"https://scontent-waw1-1.cdninstagram.com/vp/a4bec6b5e0ad3229e006e33b148ee1b4/5CF18F24/t51.2885-19/s150x150/29402854_585635281810584_3436974783223300096_n.jpg?_nc_ht=scontent-waw1-1.cdninstagram.com","username":"nataly_roik"},"viewer_has_liked":false,"edge_liked_by":{"count":4}}}]}}},{"node":{"id":"18003209032190281","text":"КОММЕНТАРИЙ7","created_at":1549649343,"did_report_as_spam":false,"owner":{"id":"6965901844","is_verified":false,"profile_pic_url":"https://instagram.fkul4-1.fna.fbcdn.net/vp/e5c5567fe4c80c801e89b770ef19cd7d/5CDDD9F1/t51.2885-19/44884218_345707102882519_2446069589734326272_n.jpg?_nc_ht=instagram.fkul4-1.fna.fbcdn.net","username":"exelsi0r"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":1,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[{"node":{"id":"18015438781100759","text":"КОММЕНТАРИЙ8","created_at":1549649367,"did_report_as_spam":false,"owner":{"id":"6965901844","is_verified":false,"profile_pic_url":"https://instagram.fkul4-1.fna.fbcdn.net/vp/e5c5567fe4c80c801e89b770ef19cd7d/5CDDD9F1/t51.2885-19/44884218_345707102882519_2446069589734326272_n.jpg?_nc_ht=instagram.fkul4-1.fna.fbcdn.net","username":"exelsi0r"},"viewer_has_liked":false,"edge_liked_by":{"count":0}}}]}}}]}}},"status":"ok"}
)

gosub JSON_Parse
;msgbox % ResponseText

JSON_Parse:
obj := JSON.Parse(ResponseText)
keys =
(
id
text
created_at
owner
profile_pic_url
username
viewer_has_liked
edge_liked_by
edge_threaded_comments
edges
)

;================================
;================================
;================================
for k, v in obj.edges  {  ;=================ВМЕСТО edges 
;================================
;================================
;================================
   Loop, parse, keys, `n, `r
      %A_LoopField%%k% := SearchKey(v, A_LoopField)


MsgBox, % id%a_index% "`n" text%a_index% "`n" created_at%a_index% "`n" owner%a_index% "`n" profile_pic_url%a_index% "`n" username%a_index% "`n" viewer_has_liked%a_index% "`n" edge_liked_by%a_index% "`n" edge_threaded_comments%a_index% "`n" edges%a_index% "`n"

;   CmtThreads .= "..........."
}
return

SearchKey(obj, key)  {
   for k, v in obj  {
      if (k = key)
         Return v
      
      if IsObject(v)  {
         res := SearchKey(v, key)
         if (res != "")
            Return res
      }
   }
}

class JSON
{
   static JS := JSON._GetJScripObject()
   
   Parse(JsonString)  {
      try oJSON := this.JS.("(" JsonString ")")
      catch  {
         MsgBox, Wrong JsonString!
         Return
      }
      Return this._CreateObject(oJSON)
   }

   _GetJScripObject()  {
      VarSetCapacity(tmpFile, (MAX_PATH := 260) << !!A_IsUnicode, 0)
      DllCall("GetTempFileName", Str, A_Temp, Str, "AHK", UInt, 0, Str, tmpFile)
      
      FileAppend,
      (
      <component>
      <public><method name='eval'/></public>
      <script language='JScript'></script>
      </component>
      ), % tmpFile
      
      JS := ObjBindMethod( ComObjGet("script:" . tmpFile), "eval" )
      FileDelete, % tmpFile
      JSON._AddMethods(JS)
      Return JS
   }

   _AddMethods(ByRef JS)  {
      JScript =
      (
         Object.prototype.GetKeys = function () {
            var keys = []
            for (var k in this)
               if (this.hasOwnProperty(k))
                  keys.push(k)
            return keys
         }
         Object.prototype.IsArray = function () {
            var toStandardString = {}.toString
            return toStandardString.call(this) == '[object Array]'
         }
      )
      JS.("delete ActiveXObject; delete GetObject;")
      JS.(JScript)
   }

   _CreateObject(ObjJS)  {
      res := ObjJS.IsArray()
      if (res = "")
         Return ObjJS
      
      else if (res = -1)  {
         obj := []
         Loop % ObjJS.length
            obj[A_Index] := this._CreateObject(ObjJS[A_Index - 1])
      }
      else if (res = 0)  {
         obj := {}
         keys := ObjJS.GetKeys()
         Loop % keys.length
            k := keys[A_Index - 1], obj[k] := this._CreateObject(ObjJS[k])
      }
      Return obj
   }
}

43

Re: AHK: Разбор ответа VK API или JSON

Объект самого верхнего уровня — это тот, что мы получаем в результате JSON.Parse(). Ключи верхнего уровня:

obj := JSON.Parse(ResponseText)

for k in obj
   MsgBox, % k
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

44 (изменено: DD, 2019-02-10 01:05:39)

Re: AHK: Разбор ответа VK API или JSON

Указал в качестве ключа верхнего уровня ключ "data", но список под-ключей из "keys" не выводится. Почему они пустые?

45

Re: AHK: Разбор ответа VK API или JSON

Судя по вложенности, к полю "edges" нужно обращаться не "obj.edges", а так:

obj.data.shortcode_media.edge_media_to_parent_comment.edges

Там будет массив объектов, у каждого из которых в поле "node" находится ожидаемый Вами список.

+ DD

46

Re: AHK: Разбор ответа VK API или JSON

А по какой причине содержимое 5 и 7-го поля "node", пропускается?

47 (изменено: KusochekDobra, 2019-02-10 13:49:34)

Re: AHK: Разбор ответа VK API или JSON

sKeys := ["id","text","created_at","owner","profile_pic_url","username","viewer_has_liked","edge_liked_by","edge_threaded_comments","edges"]
edges := JSON.Parse(ResponseText).data.shortcode_media.edge_media_to_parent_comment.edges

list := ""
For k, v in edges {
	list .= Format("| ========>&<======= [ edge #{} ] ========>&<======= |`n", A_Index)
	For index, item in sKeys {
		list .= Format("`t{}. - {} = {}`n", A_Index, item, IsObject(val := SearchKey(v.node, item)) ? JSON.Stringify(val) : val )
	} list .= "`n"
}

MsgBox % list

SearchKey(obj, key)  {
   for k, v in obj  {
      if (k = key)
         Return v
      
      if IsObject(v)  {
         res := SearchKey(v, key)
         if (res != "")
            Return res
      }
   }
}
+ DD

48

Re: AHK: Разбор ответа VK API или JSON

Спасибо!

49

Re: AHK: Разбор ответа VK API или JSON

Но почему на этот раз выводятся не все 8 блоков, а лишь первые 6, последовательно?

50

Re: AHK: Разбор ответа VK API или JSON

Если речь о количестве элементов массива "edges", то, в Вашем примере их всего 6.

MsgBox % edges.Length()

51

Re: AHK: Разбор ответа VK API или JSON

То есть, без пропусков нельзя всё получить за раз, с учётом структуры комментариев и под-комментариев? Какими парсерами разбирают такие случаи?

52

Re: AHK: Разбор ответа VK API или JSON

Не уверен, что правильно понимаю, но кажется, ограничение, с которым Вы сталкиваетесь, либо в данных полученного ответа, либо понимания своей цели. Уточните пожалуйста, что конкретно должно пониматься под "всё", если сформулированное решение и так получает всё?

Напомню, что я никогда не имел дело с VK API и не представляю какова иерархия интересов в таких запросах.

53

Re: AHK: Разбор ответа VK API или JSON

Рискну предположить, что речь о паре "edges", находящихся в двух последних элементах, которые не пусты.

sKeys := ["id","text","created_at","owner","profile_pic_url","username","viewer_has_liked","edge_liked_by","edge_threaded_comments","edges"]
edges := JSON.Parse(ResponseText).data.shortcode_media.edge_media_to_parent_comment.edges

MsgBox % Clipboard := ListEdges(edges, sKeys)
ListEdges(edges, srchKeys, inner := false) {
	list := ""
	For k, v in edges {
		list .= Format("{}| ========>&<======= [ {}edge #{} ] ========>&<======= |`n", inner ? "`t" : "", inner ? "Inner " : "", A_Index)
		For index, item in srchKeys {
			val := SearchKey(v.node, item)
			innerEdges := item == "edges" ? val.Length() ? val : "" : ""
			list .= Format("{}{}. - {} = {}`n", inner ? "`t`t" : "`t", A_Index, item, IsObject(val) ? JSON.Stringify(val) : val )
		} if (innerEdges) {
			list .= ListEdges(innerEdges, srchKeys, true)
		}
		list .= "`n"
	} Return list
}
SearchKey(obj, key)  {
	for k, v in obj  {
		if (k = key)
			Return v

		if IsObject(v)  {
			res := SearchKey(v, key)
			if (res != "")
				Return res
		}
	}
}

Весь текст "MsgBox" не вмещает, поэтому он копируется в буфер, откуда его можно вставить в редактор и изучить.

54

Re: AHK: Разбор ответа VK API или JSON

Вот так спасибо! Да, под "всё" имелись в виду те оставшиеся значения по ключам, которые пропускались в предыдущих вариантах разбора этого JSON с Интсаграмма.

55 (изменено: DD, 2019-02-11 14:37:54)

Re: AHK: Разбор ответа VK API или JSON

KusochekDobra пишет:

что конкретно должно пониматься под "всё", если сформулированное решение и так получает всё?

Заметил, что в этой JSON-выдаче, вложенный комментарий дублируется вместо предыдущего (в коде убрал лишние ключи для наглядности):

ResponseText =
(
{"data":{"shortcode_media":{"edge_media_to_parent_comment":{"count":112,"page_info":{"has_next_page":true,"end_cursor":"{\"bifilter_token\": \"KAkBAgAQAP__AAAA\"}"},"edges":[{"node":{"text":"Коммент1","owner":{"id":"3432418287"},"edge_liked_by":{"count":1},"edge_threaded_comments":{"count":6,"page_info":{"has_next_page":true,"end_cursor":"QVFCbGxYVThuMnJ5VVZSMktoc2Z1QlM4elVkYnZRMmQxQW1Ba2psZ1FSNFUwekdFc1RVMzlBLWIwUHN1QXpvNVRaYS1XY3JxNWRTdlpnYnpNc0c3a1J4bg=="},"edges":[{"node":{"text":"Коммент2","owner":{"id":"2221367895"},"edge_liked_by":{"count":0}}},{"node":{"text":"Коммент3","owner":{"id":"1514648096"},"edge_liked_by":{"count":1}}},{"node":{"text":"Коммент4","owner":{"id":"5527469791"},"edge_liked_by":{"count":0}}}]}}},{"node":{"text":"Коммент5","owner":{"id":"8620373103"},"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"text":"Коммент6","owner":{"id":"8620373103"},"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"text":"Коммент7","owner":{"id":"8620373103"},"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"text":"Коммент8","owner":{"id":"6226683833"},"edge_liked_by":{"count":2},"edge_threaded_comments":{"count":16,"page_info":{"has_next_page":true,"end_cursor":"QVFBS2tjN19Od3k5WmZTYXUxSE9qUmhzdHBzWTdULW1TRmFLb3A0amNWakx4aFh5dTZkY1MzZGFkak1VaWZ6U1lLTXNVU1VSQUx1bWRMNGExTUNUdWN1TQ=="},"edges":[{"node":{"text":"Коммент9","owner":{"id":"6226683833"},"edge_liked_by":{"count":1}}},{"node":{"text":"Коммент10","owner":{"id":"5480555413"},"edge_liked_by":{"count":1}}},{"node":{"text":"Коммент11","owner":{"id":"6226683833"},"edge_liked_by":{"count":0}}}]}}}]}}},"status":"ok"}
)

sKeys := ["text","created_at","end_cursor","edges"]
edges := JSON.Parse(ResponseText).data.shortcode_media.edge_media_to_parent_comment.edges

MsgBox % Clipboard := ListEdges(edges, sKeys)
ListEdges(edges, srchKeys, inner := false) {
	list := ""
	For k, v in edges {
		list .= Format("{}| ========>&<======= [ {}edge #{} ] ========>&<======= |`n", inner ? "`t" : "", inner ? "Inner " : "", A_Index)
		For index, item in srchKeys {
			val := SearchKey(v.node, item)
			innerEdges := item == "edges" ? val.Length() ? val : "" : ""
			list .= Format("{}{}. - {} = {}`n", inner ? "`t`t" : "`t", A_Index, item, IsObject(val) ? JSON.Stringify(val) : val )
		} if (innerEdges) {
			list .= ListEdges(innerEdges, srchKeys, true)
		}
		list .= "`n"
	} Return list
}
SearchKey(obj, key)  {
	for k, v in obj  {
		if (k = key)
			Return v

		if IsObject(v)  {
			res := SearchKey(v, key)
			if (res != "")
				Return res
		}
	}
}
class JSON
{
   static JS := JSON._GetJScripObject()
   
   Parse(JsonString)  {
      try oJSON := this.JS.("(" JsonString ")")
      catch  {
         MsgBox, Wrong JsonString!
         Return
      }
      Return this._CreateObject(oJSON)
   }

   _GetJScripObject()  {
      VarSetCapacity(tmpFile, (MAX_PATH := 260) << !!A_IsUnicode, 0)
      DllCall("GetTempFileName", Str, A_Temp, Str, "AHK", UInt, 0, Str, tmpFile)
      
      FileAppend,
      (
      <component>
      <public><method name='eval'/></public>
      <script language='JScript'></script>
      </component>
      ), % tmpFile
      
      JS := ObjBindMethod( ComObjGet("script:" . tmpFile), "eval" )
      FileDelete, % tmpFile
      JSON._AddMethods(JS)
      Return JS
   }

   _AddMethods(ByRef JS)  {
      JScript =
      (
         Object.prototype.GetKeys = function () {
            var keys = []
            for (var k in this)
               if (this.hasOwnProperty(k))
                  keys.push(k)
            return keys
         }
         Object.prototype.IsArray = function () {
            var toStandardString = {}.toString
            return toStandardString.call(this) == '[object Array]'
         }
      )
      JS.("delete ActiveXObject; delete GetObject;")
      JS.(JScript)
   }

   _CreateObject(ObjJS)  {
      res := ObjJS.IsArray()
      if (res = "")
         Return ObjJS
      
      else if (res = -1)  {
         obj := []
         Loop % ObjJS.length
            obj[A_Index] := this._CreateObject(ObjJS[A_Index - 1])
      }
      else if (res = 0)  {
         obj := {}
         keys := ObjJS.GetKeys()
         Loop % keys.length
            k := keys[A_Index - 1], obj[k] := this._CreateObject(ObjJS[k])
      }
      Return obj
   }
}

56 (изменено: DD, 2019-02-11 14:38:54)

Re: AHK: Разбор ответа VK API или JSON

Есть ли возможность для этих JSON получать все блоки (со входящими в каждый из них комментариями и тп) — без дублей, пропусков и структуры?

57

Re: AHK: Разбор ответа VK API или JSON

DD пишет:

Заметил, что в этой JSON-выдаче, вложенный комментарий дублируется вместо предыдущего

Не совсем так. Дело в том, что итератор перебирает объект в алфавитном порядке и поскольку SearchKey() возвращает первое найденное совпадение, то находит его первым делом во вложенном "edges". Нужно только немного модифицировать SearchKey(), чтобы вначале исследовались поля текущего инстанса и, если нет найденных ключей, то искать во вложенных, если таковые имеются:


SearchKey(obj, key, outerFields := true)  {
	temp := []
	for k, v in obj  {
		if (k = key)
			Return v
		
		if (outerFields && IsObject(v))
			temp.Push(v)
		else if IsObject(v)  {
			res := SearchKey(v, key)
			if (res != "")
				Return res
		}
	}
	for index, item in temp
		if ((res := SearchKey(item, key)) != "")
			Return res
}

Здесь "outerFields" - отвечает за эту вариативность, по умолчанию устанавливая на такой алгоритм.

+ DD

58

Re: AHK: Разбор ответа VK API или JSON

Для пущей корректности, последней строкой в теле этой функции стоило бы добавить возвращаемый результат в случае, если поиск оказался неудачным и ничего не было найдено(например Return "Неудачно"), но если Вы уверены, что искомые ключи там обязаны быть, то в этом действительно нет необходимости.

59 (изменено: DD, 2019-02-11 17:22:01)

Re: AHK: Разбор ответа VK API или JSON

KusochekDobra, опять же заметил, что, хоть последовательность в содержимом комментариев соблюдается, но другие ключи внутри блока продолжают дублироваться и переноситься с вложенного блока на внешний. В примере это видно в 3 и 4 блоках, у которых "username" в результатах один и тот же, хотя в строке они разные, прошу взглянуть —

ResponseText =
(
{"data":{"shortcode_media":{"edge_media_to_parent_comment":{"count":224,"page_info":{"has_next_page":true,"end_cursor":"{\"cached_comments_cursor\": \"17988603055194856\", \"bifilter_token\": \"KC0BDABAABgAEAAQAAgACAB799_Lz77P7011eOpvf_W__wAUAAAAABAEQ0EgwBAA\"}"},"edges":[{"node":{"id":"18033126139045251","text":"cmt1","created_at":1549564430,"did_report_as_spam":false,"owner":{"id":"7147681468","is_verified":false,"profile_pic_url":"pic1","username":"uname1"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18035179396030512","text":"cmt2","created_at":1549564345,"did_report_as_spam":false,"owner":{"id":"9037884033","is_verified":false,"profile_pic_url":"pic2","username":"uname2"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17864531659321218","text":"cmt3","created_at":1549563973,"did_report_as_spam":false,"owner":{"id":"3881253436","is_verified":false,"profile_pic_url":"pic3","username":"uname3"},"viewer_has_liked":false,"edge_liked_by":{"count":1},"edge_threaded_comments":{"count":3,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[{"node":{"id":"18031519045002885","text":"cmt4","created_at":1549565442,"did_report_as_spam":false,"owner":{"id":"1514648096","is_verified":false,"profile_pic_url":"pic4","username":"uname4"},"viewer_has_liked":false,"edge_liked_by":{"count":3}}},{"node":{"id":"18014501047114258","text":"cmt5","created_at":1549622948,"did_report_as_spam":false,"owner":{"id":"3881253436","is_verified":false,"profile_pic_url":"pic5","username":"uname5"},"viewer_has_liked":false,"edge_liked_by":{"count":0}}},{"node":{"id":"18012364975121513","text":"cmt6","created_at":1549624991,"did_report_as_spam":false,"owner":{"id":"1514648096","is_verified":false,"profile_pic_url":"pic6","username":"uname6"},"viewer_has_liked":false,"edge_liked_by":{"count":1}}}]}}},{"node":{"id":"18014605018119580","text":"cmt7","created_at":1549563882,"did_report_as_spam":false,"owner":{"id":"1575737610","is_verified":false,"profile_pic_url":"pic7","username":"uname7"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18006807262092548","text":"cmt8","created_at":1549563710,"did_report_as_spam":false,"owner":{"id":"3451206464","is_verified":false,"profile_pic_url":"pic8","username":"uname8"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18014414656112658","text":"cmt9","created_at":1549563555,"did_report_as_spam":false,"owner":{"id":"3451206464","is_verified":false,"profile_pic_url":"pic9","username":"uname9"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17899732756291214","text":"cmt10","created_at":1549563119,"did_report_as_spam":false,"owner":{"id":"2330649029","is_verified":false,"profile_pic_url":"pic10","username":"uname10"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18030447571010198","text":"cmt11","created_at":1549562991,"did_report_as_spam":false,"owner":{"id":"5763461995","is_verified":false,"profile_pic_url":"pic11","username":"uname11"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18016886404100187","text":"cmt12","created_at":1549562982,"did_report_as_spam":false,"owner":{"id":"321345545","is_verified":false,"profile_pic_url":"pic12","username":"uname12"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17992787185168932","text":"cmt13","created_at":1549562672,"did_report_as_spam":false,"owner":{"id":"3267878847","is_verified":false,"profile_pic_url":"pic13","username":"uname13"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18014099035112644","text":"cmt14","created_at":1549562649,"did_report_as_spam":false,"owner":{"id":"7495332966","is_verified":false,"profile_pic_url":"pic14","username":"uname14"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17851892326346682","text":"cmt15","created_at":1549562460,"did_report_as_spam":false,"owner":{"id":"8692656309","is_verified":false,"profile_pic_url":"pic15","username":"uname15"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}}]}}},"status":"ok"}
)

sKeys := ["text","username","profile_pic_url","end_cursor","edges"]
edges := JSON.Parse(ResponseText).data.shortcode_media.edge_media_to_parent_comment.edges

MsgBox % Clipboard := ListEdges(edges, sKeys)
ListEdges(edges, srchKeys, inner := false) {
	list := ""
	For k, v in edges {
		list .= Format("{}| ========>&<======= [ {}edge #{} ] ========>&<======= |`n", inner ? "`t" : "", inner ? "Inner " : "", A_Index)
		For index, item in srchKeys {
			val := SearchKey(v.node, item)
			innerEdges := item == "edges" ? val.Length() ? val : "" : ""
			list .= Format("{}{}. - {} = {}`n", inner ? "`t`t" : "`t", A_Index, item, IsObject(val) ? JSON.Stringify(val) : val )
		} if (innerEdges) {
			list .= ListEdges(innerEdges, srchKeys, true)
		}
		list .= "`n"
	} Return list
}
SearchKey(obj, key, outerFields := true)  {
	temp := []
	for k, v in obj  {
		if (k = key)
			Return v
		
		if (outerFields && IsObject(v))
			temp.Push(v)
		else if IsObject(v)  {
			res := SearchKey(v, key)
			if (res != "")
				Return res
		}
	}
	for index, item in temp
		if ((res := SearchKey(item, key)) != "")
			Return res
}
class JSON
{
   static JS := JSON._GetJScripObject()
   
   Parse(JsonString)  {
      try oJSON := this.JS.("(" JsonString ")")
      catch  {
         MsgBox, Wrong JsonString!
         Return
      }
      Return this._CreateObject(oJSON)
   }

   _GetJScripObject()  {
      VarSetCapacity(tmpFile, (MAX_PATH := 260) << !!A_IsUnicode, 0)
      DllCall("GetTempFileName", Str, A_Temp, Str, "AHK", UInt, 0, Str, tmpFile)
      
      FileAppend,
      (
      <component>
      <public><method name='eval'/></public>
      <script language='JScript'></script>
      </component>
      ), % tmpFile
      
      JS := ObjBindMethod( ComObjGet("script:" . tmpFile), "eval" )
      FileDelete, % tmpFile
      JSON._AddMethods(JS)
      Return JS
   }

   _AddMethods(ByRef JS)  {
      JScript =
      (
         Object.prototype.GetKeys = function () {
            var keys = []
            for (var k in this)
               if (this.hasOwnProperty(k))
                  keys.push(k)
            return keys
         }
         Object.prototype.IsArray = function () {
            var toStandardString = {}.toString
            return toStandardString.call(this) == '[object Array]'
         }
      )
      JS.("delete ActiveXObject; delete GetObject;")
      JS.(JScript)
   }

   _CreateObject(ObjJS)  {
      res := ObjJS.IsArray()
      if (res = "")
         Return ObjJS
      
      else if (res = -1)  {
         obj := []
         Loop % ObjJS.length
            obj[A_Index] := this._CreateObject(ObjJS[A_Index - 1])
      }
      else if (res = 0)  {
         obj := {}
         keys := ObjJS.GetKeys()
         Loop % keys.length
            k := keys[A_Index - 1], obj[k] := this._CreateObject(ObjJS[k])
      }
      Return obj
   }
}

60

Re: AHK: Разбор ответа VK API или JSON

В этом случае, будет проще описать относительные пути к каждому из полей, и проходя по элементам массива, запрашивать их значения напрямую по списку, а так же проверять Length() вложенных edges, на предмет наличия элементов, у которых аналогичная структура, за исключением возможности иметь вложенные edges. Это исключит ошибки наверняка.

61

Re: AHK: Разбор ответа VK API или JSON

Имелось в виду, что данные из одного блока переносятся в другой. Нельзя ли убрать структурирование — представляя подряд все блоки в сплошном виде — но чтобы данные из блоков соответствовали строке?

62

Re: AHK: Разбор ответа VK API или JSON

Обратите внимание, что если элементы edges содержат вложенные edges, то это неизбежно ведёт к дублированию имён. Список запрашиваемых имён описан линейно, а их фактическое расположение имеет разный уровень вложенности. В этом случае, нужно либо сопровождать каждое имя соответствующим ему уровнем вложенности и описывать взаимодействие с этой механикой в алгоритме функции, либо, просто описать их относительные пути и обращаться к ним на каждой итерации, как описано выше. Даже если просто перечислить всё в сплошном виде, но чтобы данные соответствовали структуре, то это всё равно подразумевает описание сигнатуры для каждого искомого элемента. К тому же, раз Вы запрашиваете объект с одной и той же структурой, это не потребует от Вас много усилий.

63

Re: AHK: Разбор ответа VK API или JSON

Прошу прощения, надо было сразу обратить внимание на это, а так я только время у Вас отнял.

64

Re: AHK: Разбор ответа VK API или JSON

А какой-то простой правкой json-строки этого можно добиться, или если получать не "edges", а "node", которые охватывают все блоки?

65

Re: AHK: Разбор ответа VK API или JSON

Регулярками. Но тогда будет неочевидно, какие из них были вложены.

66

Re: AHK: Разбор ответа VK API или JSON

В смысле: что на что править? Я как ни экспериментировал — не вытанцовывается.

67 (изменено: DD, 2019-02-11 23:36:04)

Re: AHK: Разбор ответа VK API или JSON

Так же прибавка после «.edges» — «.node», — все node не выводит:

edges := JSON.Parse(ResponseText).data.shortcode_media.edge_media_to_parent_comment.edges

68

Re: AHK: Разбор ответа VK API или JSON


ResponseText = {"data":{"shortcode_media":{"edge_media_to_parent_comment":{"count":224,"page_info":{"has_next_page":true,"end_cursor":"{\"cached_comments_cursor\": \"17988603055194856\", \"bifilter_token\": \"KC0BDABAABgAEAAQAAgACAB799_Lz77P7011eOpvf_W__wAUAAAAABAEQ0EgwBAA\"}"},"edges":[{"node":{"id":"18033126139045251","text":"cmt1","created_at":1549564430,"did_report_as_spam":false,"owner":{"id":"7147681468","is_verified":false,"profile_pic_url":"pic1","username":"uname1"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18035179396030512","text":"cmt2","created_at":1549564345,"did_report_as_spam":false,"owner":{"id":"9037884033","is_verified":false,"profile_pic_url":"pic2","username":"uname2"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17864531659321218","text":"cmt3","created_at":1549563973,"did_report_as_spam":false,"owner":{"id":"3881253436","is_verified":false,"profile_pic_url":"pic3","username":"uname3"},"viewer_has_liked":false,"edge_liked_by":{"count":1},"edge_threaded_comments":{"count":3,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[{"node":{"id":"18031519045002885","text":"cmt4","created_at":1549565442,"did_report_as_spam":false,"owner":{"id":"1514648096","is_verified":false,"profile_pic_url":"pic4","username":"uname4"},"viewer_has_liked":false,"edge_liked_by":{"count":3}}},{"node":{"id":"18014501047114258","text":"cmt5","created_at":1549622948,"did_report_as_spam":false,"owner":{"id":"3881253436","is_verified":false,"profile_pic_url":"pic5","username":"uname5"},"viewer_has_liked":false,"edge_liked_by":{"count":0}}},{"node":{"id":"18012364975121513","text":"cmt6","created_at":1549624991,"did_report_as_spam":false,"owner":{"id":"1514648096","is_verified":false,"profile_pic_url":"pic6","username":"uname6"},"viewer_has_liked":false,"edge_liked_by":{"count":1}}}]}}},{"node":{"id":"18014605018119580","text":"cmt7","created_at":1549563882,"did_report_as_spam":false,"owner":{"id":"1575737610","is_verified":false,"profile_pic_url":"pic7","username":"uname7"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18006807262092548","text":"cmt8","created_at":1549563710,"did_report_as_spam":false,"owner":{"id":"3451206464","is_verified":false,"profile_pic_url":"pic8","username":"uname8"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18014414656112658","text":"cmt9","created_at":1549563555,"did_report_as_spam":false,"owner":{"id":"3451206464","is_verified":false,"profile_pic_url":"pic9","username":"uname9"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17899732756291214","text":"cmt10","created_at":1549563119,"did_report_as_spam":false,"owner":{"id":"2330649029","is_verified":false,"profile_pic_url":"pic10","username":"uname10"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18030447571010198","text":"cmt11","created_at":1549562991,"did_report_as_spam":false,"owner":{"id":"5763461995","is_verified":false,"profile_pic_url":"pic11","username":"uname11"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18016886404100187","text":"cmt12","created_at":1549562982,"did_report_as_spam":false,"owner":{"id":"321345545","is_verified":false,"profile_pic_url":"pic12","username":"uname12"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17992787185168932","text":"cmt13","created_at":1549562672,"did_report_as_spam":false,"owner":{"id":"3267878847","is_verified":false,"profile_pic_url":"pic13","username":"uname13"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18014099035112644","text":"cmt14","created_at":1549562649,"did_report_as_spam":false,"owner":{"id":"7495332966","is_verified":false,"profile_pic_url":"pic14","username":"uname14"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17851892326346682","text":"cmt15","created_at":1549562460,"did_report_as_spam":false,"owner":{"id":"8692656309","is_verified":false,"profile_pic_url":"pic15","username":"uname15"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}}]}}},"status":"ok"}

sKeys := { "text":				[]
		 , "username":			["owner"]
		 , "profile_pic_url":	["owner"]
		 , "end_cursor":		["edge_threaded_comments", "page_info"]
		 , "edges":				["edge_threaded_comments"]}
			
edges := JSON.Parse(ResponseText).data.shortcode_media.edge_media_to_parent_comment.edges
MsgBox % ListValues(edges, sKeys)

ExitApp
ListValues(edges, srchKeys, inner := false) {
	list := ""
	For k, v in edges {
		tmpArray := []
		list .= Format("{}| ====>&<==== [ {}edge #{} ] ====>&<==== |`n", inner ? "`t" : "", inner ? "Inner " : "", A_Index)
		For name, path in srchKeys {
			tmp := v.node
			For index, item in path {
				tmp := tmp[ item ]
			}
			if (IsObject(val := tmp[ name ])) {
				tmpArray := val
			}
			list .= Format("{}{}. - {} = {}`n", inner ? "`t`t" : "`t", A_Index, name, IsObject(val) ? "[]" : val ? val : "No value" )
		} (tmpArray.Length() && (list .= ListValues(tmpArray, srchKeys, true))) 
	} Return list
}

Сгодится?

+ DD

69 (изменено: DD, 2019-02-13 03:54:43)

Re: AHK: Разбор ответа VK API или JSON

Спасибо! Возник по ходу вопрос: можно ли без правки строки получать значения "edge_liked_by" и "edge_threaded_comments"? И как разбить содержимое sKeys по переменным, — чтобы, к примеру, в переменной с названием "created_at" — было время и т.д.? Это нужно, чтобы разом оборачивать все переменные из блоков, в тэги.

70

Re: AHK: Разбор ответа VK API или JSON

Непонятно.

DD пишет:

без правки строки получать значения "edge_liked_by" и "edge_threaded_comments"

Какой строки?

DD пишет:

разбить содержимое sKeys по переменным, — чтобы, к примеру, в переменной с названием "created_at" — было время и т.д.

Нужен пример. В примере выше этого поля нет.

DD пишет:

чтобы сразу оборачивать содержимое sKeys в комментарий из тэгов.

В общем-то, тоже, пример для наглядности.

Если что, завтра отвечу. Глаза слипаются.

71 (изменено: DD, 2019-02-14 07:42:12)

Re: AHK: Разбор ответа VK API или JSON

Под строкой, имелась в виду json-строка. Хотелось бы без правки также получать из неё значения "edge_liked_by" и "edge_threaded_comments", которые в обычном виде следуют после "count", да ещё без кавычек:

"edge_liked_by|edge_threaded_comments":{"count":1}

"created_at" упомянул как пример одного из ключей, название которого после отработки json будет соответствовать значению ключа, так чтобы можно было по следующему типу легко сформировать отдельный комментарий, где вместо переменных с названиями "match" — переменные с названиями из нашей json-строки:

cmt .= "<div class=""comment"">`n<img class=""img"" src=""" matchh3 """>`n<div class=""info""><a href=""" matchh4 """>" matchh2 "</a> – <a href=""watch?v=" videoId "&lc=" matchh1 """>" matchh7 "</a><span class=""vote"">" matchh6 "</span></div>`n<div class=""content"">" matchh5 "</div>`n</div>`n"

Код полностью:

ResponseText = {"data":{"shortcode_media":{"edge_media_to_parent_comment":{"count":224,"page_info":{"has_next_page":true,"end_cursor":"{\"cached_comments_cursor\": \"17988603055194856\", \"bifilter_token\": \"KC0BDABAABgAEAAQAAgACAB799_Lz77P7011eOpvf_W__wAUAAAAABAEQ0EgwBAA\"}"},"edges":[{"node":{"id":"18033126139045251","text":"cmt1","created_at":1549564430,"did_report_as_spam":false,"owner":{"id":"7147681468","is_verified":false,"profile_pic_url":"pic1","username":"uname1"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18035179396030512","text":"cmt2","created_at":1549564345,"did_report_as_spam":false,"owner":{"id":"9037884033","is_verified":false,"profile_pic_url":"pic2","username":"uname2"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17864531659321218","text":"cmt3","created_at":1549563973,"did_report_as_spam":false,"owner":{"id":"3881253436","is_verified":false,"profile_pic_url":"pic3","username":"uname3"},"viewer_has_liked":false,"edge_liked_by":{"count":1},"edge_threaded_comments":{"count":3,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[{"node":{"id":"18031519045002885","text":"cmt4","created_at":1549565442,"did_report_as_spam":false,"owner":{"id":"1514648096","is_verified":false,"profile_pic_url":"pic4","username":"uname4"},"viewer_has_liked":false,"edge_liked_by":{"count":3}}},{"node":{"id":"18014501047114258","text":"cmt5","created_at":1549622948,"did_report_as_spam":false,"owner":{"id":"3881253436","is_verified":false,"profile_pic_url":"pic5","username":"uname5"},"viewer_has_liked":false,"edge_liked_by":{"count":0}}},{"node":{"id":"18012364975121513","text":"cmt6","created_at":1549624991,"did_report_as_spam":false,"owner":{"id":"1514648096","is_verified":false,"profile_pic_url":"pic6","username":"uname6"},"viewer_has_liked":false,"edge_liked_by":{"count":1}}}]}}},{"node":{"id":"18014605018119580","text":"cmt7","created_at":1549563882,"did_report_as_spam":false,"owner":{"id":"1575737610","is_verified":false,"profile_pic_url":"pic7","username":"uname7"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18006807262092548","text":"cmt8","created_at":1549563710,"did_report_as_spam":false,"owner":{"id":"3451206464","is_verified":false,"profile_pic_url":"pic8","username":"uname8"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18014414656112658","text":"cmt9","created_at":1549563555,"did_report_as_spam":false,"owner":{"id":"3451206464","is_verified":false,"profile_pic_url":"pic9","username":"uname9"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17899732756291214","text":"cmt10","created_at":1549563119,"did_report_as_spam":false,"owner":{"id":"2330649029","is_verified":false,"profile_pic_url":"pic10","username":"uname10"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18030447571010198","text":"cmt11","created_at":1549562991,"did_report_as_spam":false,"owner":{"id":"5763461995","is_verified":false,"profile_pic_url":"pic11","username":"uname11"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18016886404100187","text":"cmt12","created_at":1549562982,"did_report_as_spam":false,"owner":{"id":"321345545","is_verified":false,"profile_pic_url":"pic12","username":"uname12"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17992787185168932","text":"cmt13","created_at":1549562672,"did_report_as_spam":false,"owner":{"id":"3267878847","is_verified":false,"profile_pic_url":"pic13","username":"uname13"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18014099035112644","text":"cmt14","created_at":1549562649,"did_report_as_spam":false,"owner":{"id":"7495332966","is_verified":false,"profile_pic_url":"pic14","username":"uname14"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17851892326346682","text":"cmt15","created_at":1549562460,"did_report_as_spam":false,"owner":{"id":"8692656309","is_verified":false,"profile_pic_url":"pic15","username":"uname15"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}}]}}},"status":"ok"}

sKeys := {	"edge_liked_by":		[]
		 , "edge_threaded_comments":	[]
		 , "text":			[]
		 , "id":			[]
		 , "created_at":		[]
		 , "username":			["owner"]
		 , "profile_pic_url":		["owner"]
		 , "end_cursor":		["edge_threaded_comments", "page_info"]
		 , "edge_threaded_comments":	["edge_threaded_comments"]
		 , "edges":			["edge_threaded_comments"]}
			
edges := JSON.Parse(ResponseText).data.shortcode_media.edge_media_to_parent_comment.edges
res := % ListValues(edges, sKeys)
MsgBox % res
;fileappend  %res%`n, _____.txt, UTF-8

ExitApp
ListValues(edges, srchKeys, inner := false) {
	list := ""
	For k, v in edges {
		tmpArray := []
		list .= Format("`n{}█ {}#{} `n", inner ? "`t" : "", inner ? "" : "", A_Index)
		For name, path in srchKeys {
			tmp := v.node
			For index, item in path {
				tmp := tmp[ item ]
			}
			if (IsObject(val := tmp[ name ])) {
				tmpArray := val
			}
			list .= Format("{}{}. - {} = {}`n", inner ? "`t" : "", A_Index, name, IsObject(val) ? "[]" : val ? val : "NoValue" )
		} (tmpArray.Length() && (list .= ListValues(tmpArray, srchKeys, true))) 
	} Return list
}
class JSON
{
   static JS := JSON._GetJScripObject()
   
   Parse(JsonString)  {
      try oJSON := this.JS.("(" JsonString ")")
      catch  {
         MsgBox, Wrong JsonString!
         Return
      }
      Return this._CreateObject(oJSON)
   }

   _GetJScripObject()  {
      VarSetCapacity(tmpFile, (MAX_PATH := 260) << !!A_IsUnicode, 0)
      DllCall("GetTempFileName", Str, A_Temp, Str, "AHK", UInt, 0, Str, tmpFile)
      
      FileAppend,
      (
      <component>
      <public><method name='eval'/></public>
      <script language='JScript'></script>
      </component>
      ), % tmpFile
      
      JS := ObjBindMethod( ComObjGet("script:" . tmpFile), "eval" )
      FileDelete, % tmpFile
      JSON._AddMethods(JS)
      Return JS
   }

   _AddMethods(ByRef JS)  {
      JScript =
      (
         Object.prototype.GetKeys = function () {
            var keys = []
            for (var k in this)
               if (this.hasOwnProperty(k))
                  keys.push(k)
            return keys
         }
         Object.prototype.IsArray = function () {
            var toStandardString = {}.toString
            return toStandardString.call(this) == '[object Array]'
         }
      )
      JS.("delete ActiveXObject; delete GetObject;")
      JS.(JScript)
   }

   _CreateObject(ObjJS)  {
      res := ObjJS.IsArray()
      if (res = "")
         Return ObjJS
      
      else if (res = -1)  {
         obj := []
         Loop % ObjJS.length
            obj[A_Index] := this._CreateObject(ObjJS[A_Index - 1])
      }
      else if (res = 0)  {
         obj := {}
         keys := ObjJS.GetKeys()
         Loop % keys.length
            k := keys[A_Index - 1], obj[k] := this._CreateObject(ObjJS[k])
      }
      Return obj
   }
}

72

Re: AHK: Разбор ответа VK API или JSON

Было бы нагляднее, если бы Вы привели пример попытки конечной реализации. С трудом понимаю, что требуется конкретно. Это ведь должно к чему-то приводить, верно?
Если я правильно понимаю, результат ListValues(), Вы потом снова разбираете на составляющие, чтобы вновь получить значения, только из более упрощённого источника, так?
"edge_liked_by" и "edge_threaded_comments" - не следуют в "ResponseText" после "count", напротив, оба они содержат "count" являясь объектами.

Наверное следовало так же дать пояснение, что "sKeys" - это объект, поля которого содержат нисходящие пути по иерархии текущего элемента "node", в виде массивов, порядок элементов которых соответствует имени каждого уровня вложенности для искомого элемента, имя которого, в свою очередь, соответствует имени этого поля. Но это должно быть и так очевидным и тем не менее, Вы допускаете ошибку, устанавливая для "edge_threaded_comments" путь, заканчивающийся на самом себе:

, "edge_threaded_comments":	["edge_threaded_comments"]

Хотя он там же, где и "edge_liked_by":

"edge_liked_by":	[]

В самом верхнем уровне. В корне.

Так же, то, что "edge_liked_by" и "edge_threaded_comments" - объекты, говорит о том, что их значения являются другими полями, а значит, если нужно их получить, то следует добавить их в "sKeys", присвоив разумные имена их полям и описав значениями их массивов вложенность, согласно иерархии.

Ещё раз хочу напомнить, что самый простой путь, это получать значения по относительному пути. Это и в плане описания проще и понятнее и получать Вы их будете в одном цикле, а не в трёх.

И ещё, ListValues() собирает данные в строку только для наглядности и Вы можете изменить её для получения данных в любом формате. В следующем примере, ListValues() вернёт объект с полями "txt" и "data", в которых первое, будет представлять искомое содержимое в текстовом виде, как и раньше, а второе, будет массивом с той же структурой из 12 элементов, в котором третий, будет содержать поле "edges" в виде массива из трёх элементов с той же структурой, что и его родитель.


#Include <JSON>

ResponseText = {"data":{"shortcode_media":{"edge_media_to_parent_comment":{"count":224,"page_info":{"has_next_page":true,"end_cursor":"{\"cached_comments_cursor\": \"17988603055194856\", \"bifilter_token\": \"KC0BDABAABgAEAAQAAgACAB799_Lz77P7011eOpvf_W__wAUAAAAABAEQ0EgwBAA\"}"},"edges":[{"node":{"id":"18033126139045251","text":"cmt1","created_at":1549564430,"did_report_as_spam":false,"owner":{"id":"7147681468","is_verified":false,"profile_pic_url":"pic1","username":"uname1"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18035179396030512","text":"cmt2","created_at":1549564345,"did_report_as_spam":false,"owner":{"id":"9037884033","is_verified":false,"profile_pic_url":"pic2","username":"uname2"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17864531659321218","text":"cmt3","created_at":1549563973,"did_report_as_spam":false,"owner":{"id":"3881253436","is_verified":false,"profile_pic_url":"pic3","username":"uname3"},"viewer_has_liked":false,"edge_liked_by":{"count":1},"edge_threaded_comments":{"count":3,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[{"node":{"id":"18031519045002885","text":"cmt4","created_at":1549565442,"did_report_as_spam":false,"owner":{"id":"1514648096","is_verified":false,"profile_pic_url":"pic4","username":"uname4"},"viewer_has_liked":false,"edge_liked_by":{"count":3}}},{"node":{"id":"18014501047114258","text":"cmt5","created_at":1549622948,"did_report_as_spam":false,"owner":{"id":"3881253436","is_verified":false,"profile_pic_url":"pic5","username":"uname5"},"viewer_has_liked":false,"edge_liked_by":{"count":0}}},{"node":{"id":"18012364975121513","text":"cmt6","created_at":1549624991,"did_report_as_spam":false,"owner":{"id":"1514648096","is_verified":false,"profile_pic_url":"pic6","username":"uname6"},"viewer_has_liked":false,"edge_liked_by":{"count":1}}}]}}},{"node":{"id":"18014605018119580","text":"cmt7","created_at":1549563882,"did_report_as_spam":false,"owner":{"id":"1575737610","is_verified":false,"profile_pic_url":"pic7","username":"uname7"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18006807262092548","text":"cmt8","created_at":1549563710,"did_report_as_spam":false,"owner":{"id":"3451206464","is_verified":false,"profile_pic_url":"pic8","username":"uname8"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18014414656112658","text":"cmt9","created_at":1549563555,"did_report_as_spam":false,"owner":{"id":"3451206464","is_verified":false,"profile_pic_url":"pic9","username":"uname9"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17899732756291214","text":"cmt10","created_at":1549563119,"did_report_as_spam":false,"owner":{"id":"2330649029","is_verified":false,"profile_pic_url":"pic10","username":"uname10"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18030447571010198","text":"cmt11","created_at":1549562991,"did_report_as_spam":false,"owner":{"id":"5763461995","is_verified":false,"profile_pic_url":"pic11","username":"uname11"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18016886404100187","text":"cmt12","created_at":1549562982,"did_report_as_spam":false,"owner":{"id":"321345545","is_verified":false,"profile_pic_url":"pic12","username":"uname12"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17992787185168932","text":"cmt13","created_at":1549562672,"did_report_as_spam":false,"owner":{"id":"3267878847","is_verified":false,"profile_pic_url":"pic13","username":"uname13"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18014099035112644","text":"cmt14","created_at":1549562649,"did_report_as_spam":false,"owner":{"id":"7495332966","is_verified":false,"profile_pic_url":"pic14","username":"uname14"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17851892326346682","text":"cmt15","created_at":1549562460,"did_report_as_spam":false,"owner":{"id":"8692656309","is_verified":false,"profile_pic_url":"pic15","username":"uname15"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}}]}}},"status":"ok"}

sKeys := { "edge_liked_by":				[]
		 , "edge_threaded_comments":	[]
		 , "text":						[]
		 , "id":						[]
		 , "created_at":				[]
		 , "username":					["owner"]
		 , "profile_pic_url":			["owner"]
		 , "end_cursor":				["edge_threaded_comments", "page_info"]
		 , "edge_threaded_comments":	[]
		 , "edges":						["edge_threaded_comments"] }
			
edges := JSON.Parse(ResponseText).data.shortcode_media.edge_media_to_parent_comment.edges
res := % ListValues(edges, sKeys)
;MsgBox % res
Gui,1: Margin, 10, 10
Gui,1: Font,,Consolas
Gui,1: Add, Edit,w700 r40 HScroll,% res.txt
Gui,1: Font
Gui,1: Show,,JSON src
Return
GuiClose:
	ExitApp
ListValues(edges, srchKeys, inner := false) {
	list := "", data := []
	For k, v in edges {
		tmpArray := [], list .= Format("`n{}█ {}#{} `n", inner ? "`t" : "", inner ? "" : "", A_Index), o := {}
		For name, path in srchKeys {
			tmp := v.node
			For index, item in path
				tmp := tmp[ item ]
			if (IsObject(val := tmp[ name ]) && name == "edges")
				tmpArray := val
			list .= Format("{}{}. - {} = {}`n", inner ? "`t" : "", A_Index, name, IsObject(val) ? JSON.Stringify(val) : val ? val : "NoValue" )
			o[name] := val
		} (tmpArray.Length() && (list .= (iObj := ListValues(tmpArray, srchKeys, true)).txt, o.edges := iObj.data)), data.Push(o)
	} Return {"txt": list, "data": data}
}

Обращаться к его содержимому будет проще, чем ещё раз разбирать разбирать строку. Это, по сути, уже упрощённый вариант изначального JSON, описанный согласно установкам в "sKeys".

73 (изменено: DD, 2019-02-15 22:14:39)

Re: AHK: Разбор ответа VK API или JSON

KusochekDobra пишет:

Если я правильно понимаю, результат ListValues(), Вы потом снова разбираете на составляющие, чтобы вновь получить значения, только из более упрощённого источника, так?

Да, именно это). Иными словами, мне надо, чтобы были переменные с названиями ключей, в каждой из которых содержалось бы соответствующее полученное значение ключа. Например: переменная с названием %text% — содержит значение ключа "text", и т.д. Это позволит распредилить все переменные по каркасу из HTML-тегов и накапливать в цикле как комментарий, по типу:


cmt .= "<div class=""comment"">`n<img class=""img"" src=""" matchh3 """>`n<div class=""info""><a href=""" matchh4 """>" matchh2 "</a> – <a href=""watch?v=" videoId "&lc=" matchh1 """>" matchh7 "</a><span class=""vote"">" matchh6 "</span></div>`n<div class=""content"">" matchh5 "</div>`n</div>`n"

То есть, каждый блок нужен не в том виде, как выводится сейчас — а как отдельный комментарий в тегах. В этом скрипте пример такого вывода результатов:


str =
(
{"replycount":173,"comments":[{"collapsed":0,"shown":1,"collapsed":0,"userpic":"https://l-userpic.livejournal.com/125166311/76306440","actions":[{"allowed":1,"href":"https://livejournal.com/2796915.html?replyto=1321676147","name":"reply","title":"Ответить","footer":1},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321676147#t1321676147","name":"permalink","title":"ссылка"},{"checkbox":1,"allowed":1,"name":"checkbox","title":"Выбрать"},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321676147#t1321676147","name":"collapse","title":"Свернуть"},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321676147#t1321676147","name":"expand","title":"Развернуть"}],"uname":"leyb_bronshteyn","loaded":1,"p_tracked":0,"commenter_journal_base":"https://leyb-bronshteyn.livejournal.com/","statprefix":"https://l-stat.livejournal.net","lj_statprefix":"https://l-stat.livejournal.net","dtalkid":1321676147,"talkid":5162797,"thread_url":"https://livejournal.com/2796915.html?thread=1321676147#t1321676147","above":1321663091,"upictitle":"leyb_bronshteyn: trotsky","article":"КОММЕНТАРИЙ1","controls":[{"checkbox":1,"allowed":1,"name":"checkbox","title":"Выбрать"},{"allowed":1,"href":"https://www.livejournal.com/manage/subscriptions/comments.bml?talkid=1321676147&journal=jour","name":"track","title":"Отслеживать"}],"siteroot":"https://www.livejournal.com","poster":"tema","stime":"4 дня назад","ctime":"30 июня 2018, 17:12:32 UTC","parent":1321663091,"massactions":1,"subject":"","deleted":0,"username":[{"journal_url":"https://leyb-bronshteyn.livejournal.com/","striked":null,"journaltype":"P","userhead_url":"https://l-stat.livejournal.net/img/userinfo_v8.svg?v=17080?v=257.1","color":null,"noctxpopup":0,"side_alias":0,"journal":"leyb_bronshteyn","inline_css":0,"attrs":null,"is_identity":0,"bold":1,"show_userhead":1,"username":"leyb_bronshteyn","user_alias":"","profile_url":"https://leyb-bronshteyn.livejournal.com/profile","alias":0}],"is_promo":0,"dname":"leyb_bronshteyn","ctime_ts":1530378752,"is_best":0,"tracked":0},{"shown":0,"collapsed":1,"uname":"","loaded":0,"p_tracked":0,"commenter_journal_base":"","statprefix":"https://l-stat.livejournal.net","lj_statprefix":"https://l-stat.livejournal.net","dtalkid":1321677683,"talkid":5162803,"thread_url":"https://livejournal.com/2796915.html?thread=1321677683#t1321677683","above":1321676147,"siteroot":"https://www.livejournal.com","poster":"tema","stime":"4 дня назад","below":1321699955,"parent":1321676147,"massactions":1,"deleted":1,"is_promo":0,"dname":"","ctime_ts":1530378800,"leafclass":"deleted","is_best":0,"tracked":0},{"shown":1,"collapsed":0,"userpic":"https://l-userpic.livejournal.com/121339544/65211451","actions":[{"allowed":1,"href":"https://livejournal.com/2796915.html?replyto=1321846131","name":"reply","title":"Ответить","footer":1},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321846131#t1321846131","name":"permalink","title":"ссылка"},{"checkbox":1,"allowed":1,"name":"checkbox","title":"Выбрать"},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321846131#t1321846131","name":"collapse","title":"Свернуть"},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321846131#t1321846131","name":"expand","title":"Развернуть"}],"uname":"ext_2042553","loaded":1,"p_tracked":0,"commenter_journal_base":"http://my.mail.ru/list/iwasko/","statprefix":"https://l-stat.livejournal.net","lj_statprefix":"https://l-stat.livejournal.net","dtalkid":1321846131,"talkid":5163461,"thread_url":"https://livejournal.com/2796915.html?thread=1321846131#t1321846131","above":1321806195,"upictitle":"Иван Пирогов: pic#121339544","article":"КОММЕНТАРИЙ2","controls":[{"checkbox":1,"allowed":1,"name":"checkbox","title":"Выбрать"},{"allowed":1,"href":"https://www.livejournal.com/manage/subscriptions/comments.bml?talkid=1321846131&journal=jour","name":"track","title":"Отслеживать"}],"siteroot":"https://www.livejournal.com","poster":"tema","stime":"3 дня назад","ctime":"1 июля 2018, 16:26:49 UTC","parent":1321806195,"massactions":1,"subject":"","deleted":0,"username":[{"journal_url":"http://my.mail.ru/list/iwasko/","striked":null,"journaltype":"I","userhead_url":"https://l-stat.livejournal.net/img/mailru-profile.gif?v=12149?v=257.1","color":null,"noctxpopup":0,"side_alias":0,"journal":"Иван Пирогов","inline_css":0,"attrs":null,"is_identity":1,"bold":1,"show_userhead":1,"username":"ext_2042553","user_alias":"","profile_url":"https://www.livejournal.com/profile?userid=65211451&t=I","alias":0}],"is_promo":0,"dname":"Иван Пирогов","ctime_ts":1530462409,"is_best":0,"tracked":0},{"shown":1,"collapsed":0,"actions":[{"allowed":1,"href":"https://livejournal.com/2796915.html?replyto=1321712499","name":"reply","title":"Ответить","footer":1},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321712499#t1321712499","name":"permalink","title":"ссылка"},{"checkbox":1,"allowed":1,"name":"checkbox","title":"Выбрать"},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321712499#t1321712499","name":"collapse","title":"Свернуть"},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321712499#t1321712499","name":"expand","title":"Развернуть"}],"uname":"v_unitaz","loaded":1,"p_tracked":0,"commenter_journal_base":"https://v-unitaz.livejournal.com/","statprefix":"https://l-stat.livejournal.net","lj_statprefix":"https://l-stat.livejournal.net","dtalkid":1321712499,"talkid":5162939,"thread_url":"https://livejournal.com/2796915.html?thread=1321712499#t1321712499","above":1321677683,"upictitle":"v_unitaz: pic#0","article":"КОММЕНТАРИЙ3","controls":[{"checkbox":1,"allowed":1,"name":"checkbox","title":"Выбрать"},{"allowed":1,"href":"https://www.livejournal.com/manage/subscriptions/comments.bml?talkid=1321712499&journal=jour","name":"track","title":"Отслеживать"}],"siteroot":"https://www.livejournal.com","poster":"tema","stime":"4 дня назад","ctime":"30 июня 2018, 19:08:18 UTC","parent":1321677683,"massactions":1,"subject":"","deleted":0,"username":[{"journal_url":"https://v-unitaz.livejournal.com/","striked":null,"journaltype":"P","userhead_url":"https://l-stat.livejournal.net/img/userinfo_v8.svg?v=17080?v=257.1","color":null,"noctxpopup":0,"side_alias":0,"journal":"v_unitaz","inline_css":0,"attrs":null,"is_identity":0,"bold":1,"show_userhead":1,"username":"v_unitaz","user_alias":"","profile_url":"https://v-unitaz.livejournal.com/profile","alias":0}],"is_promo":0,"dname":"v_unitaz","ctime_ts":1530385698,"is_best":0,"tracked":0},{"shown":1,"collapsed":0,"userpic":"https://l-userpic.livejournal.com/127834290/83644284","actions":[{"allowed":1,"href":"https://livejournal.com/2796915.html?replyto=1321713779","name":"reply","title":"Ответить","footer":1},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321713779#t1321713779","name":"permalink","title":"ссылка"},{"checkbox":1,"allowed":1,"name":"checkbox","title":"Выбрать"},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321713779#t1321713779","name":"collapse","title":"Свернуть"},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321713779#t1321713779","name":"expand","title":"Развернуть"}],"uname":"lovelement","loaded":1,"p_tracked":0,"commenter_journal_base":"https://lovelement.livejournal.com/","statprefix":"https://l-stat.livejournal.net","lj_statprefix":"https://l-stat.livejournal.net","dtalkid":1321713779,"talkid":5162944,"thread_url":"https://livejournal.com/2796915.html?thread=1321713779#t1321713779","above":1321712499,"upictitle":"lovelement: pic#127834290","article":"КОММЕНТАРИЙ4","controls":[{"checkbox":1,"allowed":1,"name":"checkbox","title":"Выбрать"},{"allowed":1,"href":"https://www.livejournal.com/manage/subscriptions/comments.bml?talkid=1321713779&journal=jour","name":"track","title":"Отслеживать"}],"siteroot":"https://www.livejournal.com","poster":"tema","stime":"4 дня назад","below":1321768563,"ctime":"30 июня 2018, 19:15:49 UTC","parent":1321712499,"massactions":1,"subject":"","deleted":0,"username":[{"journal_url":"https://lovelement.livejournal.com/","striked":null,"journaltype":"P","userhead_url":"https://l-stat.livejournal.net/img/userinfo_v8.svg?v=17080?v=257.1","color":null,"noctxpopup":0,"side_alias":0,"journal":"lovelement","inline_css":0,"attrs":null,"is_identity":0,"bold":1,"show_userhead":1,"username":"lovelement","user_alias":"","profile_url":"https://lovelement.livejournal.com/profile","alias":0}],"is_promo":0,"dname":"lovelement","ctime_ts":1530386149,"is_best":0,"tracked":0},{"shown":1,"collapsed":0,"actions":[{"allowed":1,"href":"https://livejournal.com/2796915.html?replyto=1321720435","name":"reply","title":"Ответить","footer":1},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321720435#t1321720435","name":"permalink","title":"ссылка"},{"checkbox":1,"allowed":1,"name":"checkbox","title":"Выбрать"},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321720435#t1321720435","name":"collapse","title":"Свернуть"},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321720435#t1321720435","name":"expand","title":"Развернуть"}],"uname":"v_unitaz","loaded":1,"p_tracked":0,"commenter_journal_base":"https://v-unitaz.livejournal.com/","statprefix":"https://l-stat.livejournal.net","lj_statprefix":"https://l-stat.livejournal.net","dtalkid":1321720435,"talkid":5162970,"thread_url":"https://livejournal.com/2796915.html?thread=1321720435#t1321720435","above":1321713779,"upictitle":"v_unitaz: pic#0","article":"КОММЕНТАРИЙ5","controls":[{"checkbox":1,"allowed":1,"name":"checkbox","title":"Выбрать"},{"allowed":1,"href":"https://www.livejournal.com/manage/subscriptions/comments.bml?talkid=1321720435&journal=jour","name":"track","title":"Отслеживать"}],"siteroot":"https://www.livejournal.com","poster":"tema","stime":"4 дня назад","ctime":"30 июня 2018, 20:29:16 UTC","parent":1321713779,"massactions":1,"subject":"","deleted":0,"username":[{"journal_url":"https://v-unitaz.livejournal.com/","striked":null,"journaltype":"P","userhead_url":"https://l-stat.livejournal.net/img/userinfo_v8.svg?v=17080?v=257.1","color":null,"noctxpopup":0,"side_alias":0,"journal":"v_unitaz","inline_css":0,"attrs":null,"is_identity":0,"bold":1,"show_userhead":1,"username":"v_unitaz","user_alias":"","profile_url":"https://v-unitaz.livejournal.com/profile","alias":0}],"is_promo":0,"dname":"v_unitaz","ctime_ts":1530390556,"is_best":0,"tracked":0},{"shown":1,"collapsed":0,"userpic":"https://l-userpic.livejournal.com/127834290/83644284","actions":[{"allowed":1,"href":"https://livejournal.com/2796915.html?replyto=1321720691","name":"reply","title":"Ответить","footer":1},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321720691#t1321720691","name":"permalink","title":"ссылка"},{"checkbox":1,"allowed":1,"name":"checkbox","title":"Выбрать"},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321720691#t1321720691","name":"collapse","title":"Свернуть"},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321720691#t1321720691","name":"expand","title":"Развернуть"}],"uname":"lovelement","loaded":1,"p_tracked":0,"commenter_journal_base":"https://lovelement.livejournal.com/","statprefix":"https://l-stat.livejournal.net","lj_statprefix":"https://l-stat.livejournal.net","dtalkid":1321720691,"talkid":5162971,"thread_url":"https://livejournal.com/2796915.html?thread=1321720691#t1321720691","above":1321720435,"upictitle":"lovelement: pic#127834290","article":"КОММЕНТАРИЙ6","controls":[{"checkbox":1,"allowed":1,"name":"checkbox","title":"Выбрать"},{"allowed":1,"href":"https://www.livejournal.com/manage/subscriptions/comments.bml?talkid=1321720691&journal=jour","name":"track","title":"Отслеживать"}],"siteroot":"https://www.livejournal.com","poster":"tema","stime":"4 дня назад","ctime":"30 июня 2018, 20:35:06 UTC","parent":1321720435,"massactions":1,"subject":"","deleted":0,"username":[{"journal_url":"https://lovelement.livejournal.com/","striked":null,"journaltype":"P","userhead_url":"https://l-stat.livejournal.net/img/userinfo_v8.svg?v=17080?v=257.1","color":null,"noctxpopup":0,"side_alias":0,"journal":"lovelement","inline_css":0,"attrs":null,"is_identity":0,"bold":1,"show_userhead":1,"username":"lovelement","user_alias":"","profile_url":"https://lovelement.livejournal.com/profile","alias":0}],"is_promo":0,"dname":"lovelement","ctime_ts":1530390906,"is_best":0,"tracked":0},{"shown":1,"collapsed":0,"userpic":"https://l-userpic.livejournal.com/82196355/5817510","actions":[{"allowed":1,"href":"https://livejournal.com/2796915.html?replyto=1321717619","name":"reply","title":"Ответить","footer":1},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321717619#t1321717619","name":"permalink","title":"ссылка"},{"checkbox":1,"allowed":1,"name":"checkbox","title":"Выбрать"},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321717619#t1321717619","name":"collapse","title":"Свернуть"},{"allowed":1,"href":"https://livejournal.com/2796915.html?thread=1321717619#t1321717619","name":"expand","title":"Развернуть"}],"uname":"poulsam","loaded":1,"p_tracked":0,"commenter_journal_base":"https://poulsam.livejournal.com/","statprefix":"https://l-stat.livejournal.net","lj_statprefix":"https://l-stat.livejournal.net","dtalkid":1321717619,"talkid":5162959,"thread_url":"https://livejournal.com/2796915.html?thread=1321717619#t1321717619","above":1321695859,"upictitle":"Poul: pic#82196355","article":"КОММЕНТАРИЙ7","controls":[{"checkbox":1,"allowed":1,"name":"checkbox","title":"Выбрать"},{"allowed":1,"href":"https://www.livejournal.com/manage/subscriptions/comments.bml?talkid=1321717619&journal=jour","name":"track","title":"Отслеживать"}],"siteroot":"https://www.livejournal.com","poster":"tema","stime":"4 дня назад","ctime":"30 июня 2018, 19:47:49 UTC","parent":1321650291,"massactions":1,"subject":"","deleted":0,"username":[{"journal_url":"https://poulsam.livejournal.com/","striked":null,"journaltype":"P","userhead_url":"https://l-stat.livejournal.net/img/userinfo_v8.svg?v=17080?v=257.1","color":null,"noctxpopup":0,"side_alias":0,"journal":"poulsam","inline_css":0,"attrs":null,"is_identity":0,"bold":1,"show_userhead":1,"username":"poulsam","user_alias":"","profile_url":"https://poulsam.livejournal.com/profile","alias":0}],"is_promo":0,"dname":"poulsam","ctime_ts":1530388069,"is_best":0,"tracked":0}]}
)

obj := JSON.Parse(str)
keys =
(
userpic
uname
commenter_journal_base
dtalkid
upictitle
article
ctime
userhead_url
dname
)

for k, v in obj.comments  {
   Loop, parse, keys, `n, `r
      %A_LoopField%%k% := SearchKey(v, A_LoopField)
}


loop
   MsgBox, % userpic%a_index% "`n" uname%a_index% "`n" commenter_journal_base%a_index% "`n" dtalkid%a_index% "`n" upictitle%a_index% "`n" article%a_index% "`n" ctime%a_index% "`n" userhead_url%a_index% "`n" dname%a_index% "`n"

SearchKey(obj, key)  {
   for k, v in obj  {
      if (k = key)
         Return v
      
      if IsObject(v)  {
         res := SearchKey(v, key)
         if (res != "")
            Return res
      }
   }
}

class JSON
{
   static JS := JSON._GetJScripObject()
   
   Parse(JsonString)  {
      try oJSON := this.JS.("(" JsonString ")")
      catch  {
         MsgBox, Wrong JsonString!
         Return
      }
      Return this._CreateObject(oJSON)
   }

   _GetJScripObject()  {
      VarSetCapacity(tmpFile, (MAX_PATH := 260) << !!A_IsUnicode, 0)
      DllCall("GetTempFileName", Str, A_Temp, Str, "AHK", UInt, 0, Str, tmpFile)
      
      FileAppend,
      (
      <component>
      <public><method name='eval'/></public>
      <script language='JScript'></script>
      </component>
      ), % tmpFile
      
      JS := ObjBindMethod( ComObjGet("script:" . tmpFile), "eval" )
      FileDelete, % tmpFile
      JSON._AddMethods(JS)
      Return JS
   }

   _AddMethods(ByRef JS)  {
      JScript =
      (
         Object.prototype.GetKeys = function () {
            var keys = []
            for (var k in this)
               if (this.hasOwnProperty(k))
                  keys.push(k)
            return keys
         }
         Object.prototype.IsArray = function () {
            var toStandardString = {}.toString
            return toStandardString.call(this) == '[object Array]'
         }
      )
      JS.("delete ActiveXObject; delete GetObject;")
      JS.(JScript)
   }

   _CreateObject(ObjJS)  {
      res := ObjJS.IsArray()
      if (res = "")
         Return ObjJS
      
      else if (res = -1)  {
         obj := []
         Loop % ObjJS.length
            obj[A_Index] := this._CreateObject(ObjJS[A_Index - 1])
      }
      else if (res = 0)  {
         obj := {}
         keys := ObjJS.GetKeys()
         Loop % keys.length
            k := keys[A_Index - 1], obj[k] := this._CreateObject(ObjJS[k])
      }
      Return obj
   }
}

Насчёт "edge_liked_by"/"edge_threaded_comments", вроде указывал разные вариации вложенности, но значения не выводятся.

74

Re: AHK: Разбор ответа VK API или JSON

DD пишет:

Да, именно это).

Весьма прискорбно. Вы бы могли возвращать сразу готовую строку из такой функции, на подобии той, которую она уже возвращает, но только в нужной Вам конфигурации.
Если я Вам так и не смог помочь, то добавить мне уже нечего. Доработать решение "напильником" под свои нужды, не сложно.

75

Re: AHK: Разбор ответа VK API или JSON

Но там формат, в котором переменная общая для каждого ключа —


list .= Format("{}{}. - {} = {}`n", inner ? "`t" : "", A_Index, name, IsObject(val) ? JSON.Stringify(val) : val ? val : "NoValue" )

и поэтому, насколько могу судить, каждую строку придется повторно изменять.

"edge_liked_by"/"edge_threaded_comments" — записывал в том числе так, согласно иерархии, но значения не выводятся:

"edge_liked_by":		["owner", "edges"]

76

Re: AHK: Разбор ответа VK API или JSON

DD пишет:

Но там формат, в котором переменная общая для каждого ключа —

В каждый момент формирования этой строки, в переменной "name" - имя искомого поля / имя значения, которое Вы ищете, задавая его в "sKeys", а в "val" его значение. Это поведение демонстрирует текст на выходе всякий раз. Если необходим определённый порядок получения данных, лучше упаковать элементы "sKeys" в отдельные объекты, сделать из него массив и слегка подшаманить в теле функции.

DD пишет:

"edge_liked_by"/"edge_threaded_comments" — записывал в том числе так, согласно иерархии, но значения не выводятся:

Вы внимательно читали пояснение к "sKeys"? Там сказано, что массивы по именам которых обращается итератор, содержат нисходящий путь в иерархии корневого элемента, которым является текущий элемент массива "edges". Например, запись:

, "end_cursor":				["edge_threaded_comments", "page_info"]

Для первого элемента, аналогична записи:

edges[1].node.edge_threaded_comments.page_info.end_cursor

Запись:

"edge_liked_by":		["owner", "edges"]

Не валидна. Говорил об этом выше и приводил пример. В ней, Вы обращаетесь вначале к полю "owner", чтобы получить доступ к "edges", откуда в результате будет обращение к "edge_liked_by", но среди четырёх полей внутри "owner" нет "edges", а любой известный "edges", даже вложенный - это всегда линейный массив.

Нужно усвоить этот, в действительности, простой механизм, а не пытаться оседлать его парсером, выполненным над парсером, сделанным из парсера... То, что Вы пытаетесь "оживить", похоже на то, как суп вилкой есть - можно, но чрезвычайно не эффективно. И за Вас, для Вас, с этим - никто не справится. Поэтому пытайтесь. Я в Вас верю! Проделав такой путь и дойдя до финиша, будет большим расточительством всё бросить(или продолжать следовать прежним путём).

Любые вопросы приветствуются, но к решению нужно прийти самостоятельно.

77

Re: AHK: Разбор ответа VK API или JSON

Вот так что-то наклёвывается, но как сделать, чтобы не было лишних циклов? —

ListValues(edges, srchKeys, inner := false) {
	list := ""
	For k, v in edges {
		tmpArray := []
		list .= Format("`n{}█ {}#{} `n", inner ? "`t" : "", inner ? "" : "", A_Index)
		For name, path in srchKeys {
			tmp := v.node
			For index, item in path {
				tmp := tmp[ item ]
			}
			if (IsObject(val := tmp[ name ])) {
				tmpArray := val
			}

			If InStr(name, "created_at") 
				created_at := val
			If InStr(name, "edge_liked_by") 
				edge_liked_by := val
			If InStr(name, "edge_threaded_comments") 
				edge_threaded_comments := val
			If InStr(name, "end_cursor") 
				end_cursor := val
			If InStr(name, "id") 
				id := val
			If InStr(name, "profile_pic_url") 
				profile_pic_url := val
			If InStr(name, "text") 
				text := val
			If InStr(name, "username") 
				username := val

			;list .= Format("{}{}. - {} = {}`n", inner ? "`t" : "", A_Index, name, IsObject(val) ? "[]" : val ? val : "NoValue" )
			list .= created_at " | " edge_liked_by " | " edge_threaded_comments " | " end_cursor " | " id " | " profile_pic_url " | " text " | " username "      " 

		} (tmpArray.Length() && (list .= ListValues(tmpArray, srchKeys, true))) 
	} Return list
}

78

Re: AHK: Разбор ответа VK API или JSON

Можно оставить всего один "For", перебирающий элементы "edges", но тогда, как упоминалось ранее, нужно будет обращаться к каждому искомому элементу по его пути, например:

v.node.edge_threaded_comments.page_info.end_cursor

На каждой итерации, это вернёт "end_cursor" текущего элемента "edges".

Квалификация циклов выглядит так:


	For k, v in edges {	; перебирает "edges", извлекая его элементы в "v"
		tmpArray := []
		list .= Format("`n{}█ {}#{} `n", inner ? "`t" : "", inner ? "" : "", A_Index)
		For name, path in srchKeys {	; извлекает массивы в "path" из "srchKeys" с именами точек маршрута для "name"
			tmp := v.node
			For index, item in path { ; переходит на следующий уровень вложенности в элементе "v.node", по имени в "item", извлекаемому из массива "path"

Чтобы соблюдать определённый порядок, есть два очевидных пути. Первый, это как в Вашем примере, следовать относительным путём до искомого поля:


ListValues(edges) {
	list := ""
	For k, v in edges {
		end_cursor :=	v.node.edge_threaded_comments.page_info.end_cursor
		text :=			v.node.text
		id := 			v.node.id
		created_at := 	v.node.created_at
		username := 	v.node.owner.username
		; ...
		list .= Format("{} | {} | {} | {} | {}`n",end_cursor,text,id,created_at,username)
	} Return list
}

Либо, представить "sKeys" в виде массива, расположив его элементы в нужном порядке.


#Include <JSON>

ResponseText = {"data":{"shortcode_media":{"edge_media_to_parent_comment":{"count":224,"page_info":{"has_next_page":true,"end_cursor":"{\"cached_comments_cursor\": \"17988603055194856\", \"bifilter_token\": \"KC0BDABAABgAEAAQAAgACAB799_Lz77P7011eOpvf_W__wAUAAAAABAEQ0EgwBAA\"}"},"edges":[{"node":{"id":"18033126139045251","text":"cmt1","created_at":1549564430,"did_report_as_spam":false,"owner":{"id":"7147681468","is_verified":false,"profile_pic_url":"pic1","username":"uname1"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18035179396030512","text":"cmt2","created_at":1549564345,"did_report_as_spam":false,"owner":{"id":"9037884033","is_verified":false,"profile_pic_url":"pic2","username":"uname2"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17864531659321218","text":"cmt3","created_at":1549563973,"did_report_as_spam":false,"owner":{"id":"3881253436","is_verified":false,"profile_pic_url":"pic3","username":"uname3"},"viewer_has_liked":false,"edge_liked_by":{"count":1},"edge_threaded_comments":{"count":3,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[{"node":{"id":"18031519045002885","text":"cmt4","created_at":1549565442,"did_report_as_spam":false,"owner":{"id":"1514648096","is_verified":false,"profile_pic_url":"pic4","username":"uname4"},"viewer_has_liked":false,"edge_liked_by":{"count":3}}},{"node":{"id":"18014501047114258","text":"cmt5","created_at":1549622948,"did_report_as_spam":false,"owner":{"id":"3881253436","is_verified":false,"profile_pic_url":"pic5","username":"uname5"},"viewer_has_liked":false,"edge_liked_by":{"count":0}}},{"node":{"id":"18012364975121513","text":"cmt6","created_at":1549624991,"did_report_as_spam":false,"owner":{"id":"1514648096","is_verified":false,"profile_pic_url":"pic6","username":"uname6"},"viewer_has_liked":false,"edge_liked_by":{"count":1}}}]}}},{"node":{"id":"18014605018119580","text":"cmt7","created_at":1549563882,"did_report_as_spam":false,"owner":{"id":"1575737610","is_verified":false,"profile_pic_url":"pic7","username":"uname7"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18006807262092548","text":"cmt8","created_at":1549563710,"did_report_as_spam":false,"owner":{"id":"3451206464","is_verified":false,"profile_pic_url":"pic8","username":"uname8"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18014414656112658","text":"cmt9","created_at":1549563555,"did_report_as_spam":false,"owner":{"id":"3451206464","is_verified":false,"profile_pic_url":"pic9","username":"uname9"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17899732756291214","text":"cmt10","created_at":1549563119,"did_report_as_spam":false,"owner":{"id":"2330649029","is_verified":false,"profile_pic_url":"pic10","username":"uname10"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18030447571010198","text":"cmt11","created_at":1549562991,"did_report_as_spam":false,"owner":{"id":"5763461995","is_verified":false,"profile_pic_url":"pic11","username":"uname11"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18016886404100187","text":"cmt12","created_at":1549562982,"did_report_as_spam":false,"owner":{"id":"321345545","is_verified":false,"profile_pic_url":"pic12","username":"uname12"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17992787185168932","text":"cmt13","created_at":1549562672,"did_report_as_spam":false,"owner":{"id":"3267878847","is_verified":false,"profile_pic_url":"pic13","username":"uname13"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18014099035112644","text":"cmt14","created_at":1549562649,"did_report_as_spam":false,"owner":{"id":"7495332966","is_verified":false,"profile_pic_url":"pic14","username":"uname14"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17851892326346682","text":"cmt15","created_at":1549562460,"did_report_as_spam":false,"owner":{"id":"8692656309","is_verified":false,"profile_pic_url":"pic15","username":"uname15"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}}]}}},"status":"ok"}
			
sKeys := [["edge_liked_by"]
		 , ["edge_threaded_comments"]
		 , ["text"]
		 , ["id"]
		 , ["created_at"]
		 , ["owner", "username"]
		 , ["owner", "profile_pic_url"]
		 , ["edge_threaded_comments", "page_info", "end_cursor"]
		 , ["edge_threaded_comments"]
		 , ["edge_threaded_comments", "edges"] ]
		 
		 
edges := JSON.Parse(ResponseText).data.shortcode_media.edge_media_to_parent_comment.edges
res := % ListValues(edges, sKeys)
Gui,1: Margin, 10, 10
Gui,1: Font,,Consolas
Gui,1: Add, Edit,w700 r40 HScroll,% res
Gui,1: Font
Gui,1: Show,,JSON src
Return
GuiClose:
	ExitApp
ListValues(edges, srchKeys) {
	list := "", tmpArray := []
	For k, v in edges {
		For i, path in srchKeys {
			tmp := v.node
			For index, item in path
				tmp := tmp[ item ]
			list .= tmp " <|> "
		} (tmp.Length() && tmpArray.Push(tmp))
		list .= "`n"
	} For j, inner in tmpArray
		list .= ListValues(inner, srchKeys)
	Return list
}

Первый, проще и наглядней.

79 (изменено: DD, 2019-02-16 22:47:46)

Re: AHK: Разбор ответа VK API или JSON

Поскольку в формате в виде массива — блоки 4, 5, 6 переносятся в конец, а в таком — пропускаются —

edges := JSON.Parse(ResponseText).data.shortcode_media.edge_media_to_parent_comment.edges
MsgBox % ListValues(edges)
ListValues(edges) {
   list := ""
   For k, v in edges {
      text :=                    v.node.text
      end_cursor :=              v.node.edge_threaded_comments.page_info.end_cursor
      id :=                      v.node.id
      created_at :=              v.node.created_at
      username :=                v.node.owner.username
      profile_pic_url :=         v.node.owner.profile_pic_url
      edge_threaded_comments :=  v.node.owner.edge_threaded_comments
      edge_liked_by :=           v.node.owner.edge_liked_by
      edges :=                   v.node.edge_threaded_comments.edges
      ; ...
      list .= created_at " | " edge_liked_by " | " edge_threaded_comments " | " end_cursor " | " id " | " profile_pic_url " | " text " | " username "      "
   } Return list
}

— доделал предыдущий вариант:

sKeys := { "edge_liked_by":				["edge_media_to_parent_comment", "edges"]
		 , "edge_threaded_comments":	[]
		 , "text":						[]
		 , "id":						[]
		 , "created_at":				[]
		 , "username":					["owner"]
		 , "profile_pic_url":			["owner"]
		 , "end_cursor":				["edge_threaded_comments", "page_info"]
		 , "edge_threaded_comments":	[]
		 , "edges":						["edge_threaded_comments"] }
			
edges := JSON.Parse(ResponseText).data.shortcode_media.edge_media_to_parent_comment.edges
res := % ListValues(edges, sKeys)
Gui,1: Margin, 10, 10
Gui,1: Font,,Consolas
Gui,1: Add, Edit,w700 r40 HScroll,% res
Gui,1: Font
Gui,1: Show,,JSON src
Return
GuiClose:
	ExitApp


ListValues(edges, srchKeys, inner := false) {
loop, 8
{
	list := ""
	For k, v in edges {
		tmpArray := []
		list .= Format("`n{}█ {}{}) ", inner ? "`t" : "", inner ? "" : "", A_Index)
		For name, path in srchKeys {
			tmp := v.node
			For index, item in path {
				tmp := tmp[ item ]
			}
			if (IsObject(val := tmp[ name ])) {
				tmpArray := val
			}


			If InStr(name, "created_at") 
				created_at := val
			If InStr(name, "edge_liked_by") 
				edge_liked_by := val
			If InStr(name, "edge_threaded_comments") 
				edge_threaded_comments := val
			If InStr(name, "end_cursor") 
				end_cursor := val
			If InStr(name, "id") 
				id := val
			If InStr(name, "profile_pic_url") 
				profile_pic_url := val
			If InStr(name, "text") 
				text := val
			If InStr(name, "username") 
				username := val
}
			;list .= Format("{}{}. - {} = {}`n", inner ? "`t" : "", A_Index, name, IsObject(val) ? "[]" : val ? val : "NoValue" )
			list .= "<br>" created_at " | " edge_liked_by " | " edge_threaded_comments " | " end_cursor " | " id " | " profile_pic_url " | " text " | " username
			list .=  (tmpArray.Length() && (list .=  "`n<DD>" ListValues(tmpArray, srchKeys, true) "`n</DD>"))


		} 

	} Return list
}

80

Re: AHK: Разбор ответа VK API или JSON

Но вот с иерархией "edge_liked_by"/"edge_threaded_comments" так и не удалось разобраться.

81

Re: AHK: Разбор ответа VK API или JSON

DD пишет:

Поскольку

Вы не совсем правильно меня понимаете. Я предлагаю не решение, а способ и поступаю так намеренно, потому как следуя аналогии, которую этот способ описывает, решается вся задача. Если решить её за Вас, велика вероятность и дальше встречать Ваши вопросы рождённые на этой почве.

Внимательно проследите соответствия позволяющие решить часть задачи. Поймёте, как это работает, решите и остальное.

82

Re: AHK: Разбор ответа VK API или JSON

Касаемо "поскольку" вопрос уже счастливо решен (не без Вашего добродетельного участия). Нерешаемым остается вопрос по полям "edge_liked_by"/"edge_threaded_comments", по которым уже испробованы различные комбинации иерархии.

83

Re: AHK: Разбор ответа VK API или JSON

Это объекты, с нулевым уровнем вложенности, они находятся там же где "id" и "text" и об этом уже было сказано. Чтобы извлечь из них данные - иерархию их расположения нужно поместить в "sKeys"

84

Re: AHK: Разбор ответа VK API или JSON

А слово "count" надо указывать в иерархии?

85

Re: AHK: Разбор ответа VK API или JSON

Зависит от того, нужно ли Вам его значение. Самый лучший способ это проверить - попробовать. Например, "text", нужен, поэтому его расположение не обращается ни к каким полям, запрашивая из корня:

"text": []

Значит, если потребуется значение поля "count", расположенного, например, в "edge_threaded_comments", то выглядеть это будет так:

"count": ["edge_threaded_comments"]

Но тут можно столкнуться с проблемой дубликатов имён, потому как в "edge_liked_by" оно тоже есть и если потребуется получать и его тоже, то в этом месте, альтернативой может быть только выборка по относительным путям, на чём я таки настаиваю, потому что это проще и наглядней, или массивы. Оба способа в есть в 78 сообщении.

86

Re: AHK: Разбор ответа VK API или JSON

Я уже все вариации исчерпал. Это вообще возможно для второго кода из 79 поста?

87

Re: AHK: Разбор ответа VK API или JSON

Только если нет необходимости получать поля с одинаковым именем, иначе, значения таких полей будут перезаписаны в "sKeys":

obj := {"count": 30, "count": "ноль"}
MsgBox % obj.count

88

Re: AHK: Разбор ответа VK API или JSON

А для Вашего кода из 78-го поста? —

ListValues(edges) {
	list := ""
	For k, v in edges {
		end_cursor :=	v.node.edge_threaded_comments.page_info.end_cursor
		text :=			v.node.text
		id := 			v.node.id
		created_at := 	v.node.created_at
		username := 	v.node.owner.username
		; ...
		list .= Format("{} | {} | {} | {} | {}`n",end_cursor,text,id,created_at,username)
	} Return list
}

89

Re: AHK: Разбор ответа VK API или JSON

Абсолютно.
На этом исполнении, кстати, я настаивал с самого начала. Оно ведь наглядней, проще. На каждой итерации выбираете одни и те же поля, как и в любом другом случае, но всякий раз, обращаетесь "по адресу", сохраняя в промежуточных переменных искомые значения, чтобы перед началом следующей их было удобно поместить в любой вид "контейнера", который отправит собранные данные из функции. В этом случае "list", но Вы можете сразу формировать строку с тегами, заполняя значениями из переменных, которые не нужно вновь "добывать".

90 (изменено: DD, 2019-02-19 17:56:59)

Re: AHK: Разбор ответа VK API или JSON

В смысле, там не достаточно указать иерархию для "edge_liked_by" и под-комментариев (по отработке не выводятся три комментария), а надо еще операции дописывать?

91

Re: AHK: Разбор ответа VK API или JSON

Не понимаю суть последнего вопроса.
Приведённый пример = пример. Решения основанные на примерах, всегда подразумевают собственную реализацию. "edge_liked_by" - объект, как не единожды об этом упоминалось, следовательно, обращаясь по его имени Вы никогда не получите данных из него, если следом за этим обращением, через точку, не указывать имя поля внутри этого объекта содержащее нужные данные:

obj := {"count": {"counter": 11}}
MsgBox % "Data = '" obj "'"
MsgBox % "Data = '" obj.count "'"
MsgBox % "Data = '" obj.count.counter "'"

Автор - Вы, Вам и решать, какие данные из объекта = нужны.

92

Re: AHK: Разбор ответа VK API или JSON

Да, имелась в виду иерархия через точку (включая "count") для вывода "edge_liked_by" и под-комментариев. Достаточно указать в этом скрипте такую валидную иерархию через точку, или надо еще что-то "на каждой итерации выбирать", "сохраняя в промежуточных переменных искомые значения" и т. д.?

93

Re: AHK: Разбор ответа VK API или JSON

Я не могу этого знать. Цель получить что-то ставите перед собой Вы, значит и знать, что получать, должны Вы.
На каждой итерации, Вам доступен весь контент текущего элемента, массива "edges". Всё что нужно для получения значения из конкретного поля в этом элементе - полностью квалифицированное имя этого поля, относительно элемента. В нашем случае, относительно "v.node":

end_cursor :=	v.node.edge_threaded_comments.page_info.end_cursor
text :=			v.node.text
; ...

94 (изменено: DD, 2019-02-19 21:19:16)

Re: AHK: Разбор ответа VK API или JSON

Так я и говорю вторую страницу, что хочу получать: значения "edge_liked_by.count", а также — для последнего скрипта — под-комментарии (то, что выше в скриптах отбивалось табуляцией от основных комментариев). Не могли бы Вы подсказать правильную последовательность иерархии, потому что я несколько раз за последние два дня уже безуспешно занимался комбинаторикой?

95

Re: AHK: Разбор ответа VK API или JSON

Пользуетесь редактором с подсветкой? Если да, то наверняка он должен так же подсвечивать пару для выделенной скобки.

+ открыть спойлер

https://b.radikal.ru/b13/1902/79/162dc7f43dff.gif

Таким образом можно выделить весь интересующий участок JSON-строки для анализа. Находите начало интересующего Вас блока, выделяете его весь вместе со скобками, которые его обозначают, копируете в отдельное место. Получается, например, так:

"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}

Если это ещё не помогает понять структуру внутри, например, потому, что участок кода может быть большим, разбираете его для удобочитаемости, пользуясь самыми обычными отступами и переносом строки:

"edge_threaded_comments":
	{
		"count":0,
		"page_info":
			{
				"has_next_page":false,
				"end_cursor":null
			},
		"edges":[]
	}

Так, можно визуализировать любую иерархию. Поищите в гугле, плагины для браузера(наверняка есть), в который можно поместить такой JSON и он его представит в виде раскрывающегося дерева, на подобии эксплорера. Возможно есть ещё какие-либо аналоги. На дворе 2к19, было бы странно, если бы повсеместно используемый компонент не обзавёлся чем-то подобным.

+ DD

96

Re: AHK: Разбор ответа VK API или JSON

Если сохранить JSON в файл с расширением .json, то Firefox открывает его в виде дерева без всяких плагинов:

+ открыть спойлер

https://i.imgur.com/cYlCHtb.png

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

97

Re: AHK: Разбор ответа VK API или JSON

Есть куча онлайн сервисов, например этот:
https://jsonformatter.org/json-viewer

98

Re: AHK: Разбор ответа VK API или JSON

Благодарю!
То, что нужно.

99

Re: AHK: Разбор ответа VK API или JSON

Так ведь я более-менее полную иерархию пытался прописывать, а там последних ключей оказалось достаточно). Вы бы хоть записку оставили). Но это касаемо edge_liked_by/edge_threaded_comments. А под-коменты по логике как-то так должны выводиться, но это не срабатывает —


      edges :=                   v.node.edge_threaded_comments.edges.node
      edges :=                   v.node.edge_threaded_comments.edges

Целиком:


ResponseText = {"data":{"shortcode_media":{"edge_media_to_parent_comment":{"count":224,"page_info":{"has_next_page":true,"end_cursor":"{\"cached_comments_cursor\": \"17988603055194856\", \"bifilter_token\": \"KC0BDABAABgAEAAQAAgACAB799_Lz77P7011eOpvf_W__wAUAAAAABAEQ0EgwBAA\"}"},"edges":[{"node":{"id":"18033126139045251","text":"cmt1","created_at":1549564430,"did_report_as_spam":false,"owner":{"id":"7147681468","is_verified":false,"profile_pic_url":"pic1","username":"uname1"},"viewer_has_liked":false,"edge_liked_by":{"count":3},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18035179396030512","text":"cmt2","created_at":1549564345,"did_report_as_spam":false,"owner":{"id":"9037884033","is_verified":false,"profile_pic_url":"pic2","username":"uname2"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17864531659321218","text":"cmt3","created_at":1549563973,"did_report_as_spam":false,"owner":{"id":"3881253436","is_verified":false,"profile_pic_url":"pic3","username":"uname3"},"viewer_has_liked":false,"edge_liked_by":{"count":1},"edge_threaded_comments":{"count":3,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[{"node":{"id":"18031519045002885","text":"cmt4","created_at":1549565442,"did_report_as_spam":false,"owner":{"id":"1514648096","is_verified":false,"profile_pic_url":"pic4","username":"uname4"},"viewer_has_liked":false,"edge_liked_by":{"count":3}}},{"node":{"id":"18014501047114258","text":"cmt5","created_at":1549622948,"did_report_as_spam":false,"owner":{"id":"3881253436","is_verified":false,"profile_pic_url":"pic5","username":"uname5"},"viewer_has_liked":false,"edge_liked_by":{"count":0}}},{"node":{"id":"18012364975121513","text":"cmt6","created_at":1549624991,"did_report_as_spam":false,"owner":{"id":"1514648096","is_verified":false,"profile_pic_url":"pic6","username":"uname6"},"viewer_has_liked":false,"edge_liked_by":{"count":1}}}]}}},{"node":{"id":"18014605018119580","text":"cmt7","created_at":1549563882,"did_report_as_spam":false,"owner":{"id":"1575737610","is_verified":false,"profile_pic_url":"pic7","username":"uname7"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18006807262092548","text":"cmt8","created_at":1549563710,"did_report_as_spam":false,"owner":{"id":"3451206464","is_verified":false,"profile_pic_url":"pic8","username":"uname8"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18014414656112658","text":"cmt9","created_at":1549563555,"did_report_as_spam":false,"owner":{"id":"3451206464","is_verified":false,"profile_pic_url":"pic9","username":"uname9"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17899732756291214","text":"cmt10","created_at":1549563119,"did_report_as_spam":false,"owner":{"id":"2330649029","is_verified":false,"profile_pic_url":"pic10","username":"uname10"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18030447571010198","text":"cmt11","created_at":1549562991,"did_report_as_spam":false,"owner":{"id":"5763461995","is_verified":false,"profile_pic_url":"pic11","username":"uname11"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18016886404100187","text":"cmt12","created_at":1549562982,"did_report_as_spam":false,"owner":{"id":"321345545","is_verified":false,"profile_pic_url":"pic12","username":"uname12"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17992787185168932","text":"cmt13","created_at":1549562672,"did_report_as_spam":false,"owner":{"id":"3267878847","is_verified":false,"profile_pic_url":"pic13","username":"uname13"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"18014099035112644","text":"cmt14","created_at":1549562649,"did_report_as_spam":false,"owner":{"id":"7495332966","is_verified":false,"profile_pic_url":"pic14","username":"uname14"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}},{"node":{"id":"17851892326346682","text":"cmt15","created_at":1549562460,"did_report_as_spam":false,"owner":{"id":"8692656309","is_verified":false,"profile_pic_url":"pic15","username":"uname15"},"viewer_has_liked":false,"edge_liked_by":{"count":0},"edge_threaded_comments":{"count":0,"page_info":{"has_next_page":false,"end_cursor":null},"edges":[]}}}]}}},"status":"ok"}

edges := JSON.Parse(ResponseText).data.shortcode_media.edge_media_to_parent_comment.edges
MsgBox % ListValues(edges)
ListValues(edges) {
   list := ""
   For k, v in edges {
      text :=                    v.node.text
      end_cursor :=              v.node.edge_threaded_comments.page_info.end_cursor
      id :=                      v.node.id
      created_at :=              v.node.created_at
      username :=                v.node.owner.username
      profile_pic_url :=         v.node.owner.profile_pic_url
      edge_threaded_comments :=  v.node.edge_threaded_comments.count
      edge_liked_by :=           v.node.edge_liked_by.count
      edges :=                   v.node.edge_threaded_comments.edges.node
      ; ...
      list .= created_at " | " edge_liked_by " | " edge_threaded_comments " | " end_cursor " | " id " | " profile_pic_url " | " text " | " username " | " edges
   } Return list
}

class JSON
{
   static JS := JSON._GetJScripObject()
   
   Parse(JsonString)  {
      try oJSON := this.JS.("(" JsonString ")")
      catch  {
         MsgBox, Wrong JsonString!
         Return
      }
      Return this._CreateObject(oJSON)
   }

   _GetJScripObject()  {
      VarSetCapacity(tmpFile, (MAX_PATH := 260) << !!A_IsUnicode, 0)
      DllCall("GetTempFileName", Str, A_Temp, Str, "AHK", UInt, 0, Str, tmpFile)
      
      FileAppend,
      (
      <component>
      <public><method name='eval'/></public>
      <script language='JScript'></script>
      </component>
      ), % tmpFile
      
      JS := ObjBindMethod( ComObjGet("script:" . tmpFile), "eval" )
      FileDelete, % tmpFile
      JSON._AddMethods(JS)
      Return JS
   }

   _AddMethods(ByRef JS)  {
      JScript =
      (
         Object.prototype.GetKeys = function () {
            var keys = []
            for (var k in this)
               if (this.hasOwnProperty(k))
                  keys.push(k)
            return keys
         }
         Object.prototype.IsArray = function () {
            var toStandardString = {}.toString
            return toStandardString.call(this) == '[object Array]'
         }
      )
      JS.("delete ActiveXObject; delete GetObject;")
      JS.(JScript)
   }

   _CreateObject(ObjJS)  {
      res := ObjJS.IsArray()
      if (res = "")
         Return ObjJS
      
      else if (res = -1)  {
         obj := []
         Loop % ObjJS.length
            obj[A_Index] := this._CreateObject(ObjJS[A_Index - 1])
      }
      else if (res = 0)  {
         obj := {}
         keys := ObjJS.GetKeys()
         Loop % keys.length
            k := keys[A_Index - 1], obj[k] := this._CreateObject(ObjJS[k])
      }
      Return obj
   }
}

100

Re: AHK: Разбор ответа VK API или JSON

Тоже пользовался Notepad++, но с разворотом конечно лучше).