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"]