<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[Серый форум &mdash; AHK: Класс для работы с JSON]]></title>
		<link>http://forum.script-coding.com/viewtopic.php?id=14437</link>
		<atom:link href="http://forum.script-coding.com/extern.php?action=feed&amp;tid=14437&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[Недавние сообщения в теме «AHK: Класс для работы с JSON».]]></description>
		<lastBuildDate>Mon, 24 Dec 2018 10:15:29 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[AHK: Класс для работы с JSON]]></title>
			<link>http://forum.script-coding.com/viewtopic.php?pid=130551#p130551</link>
			<description><![CDATA[<h5>Класс JSON для работы со строкой в формате <a href="https://ru.wikipedia.org/wiki/JSON">JSON</a></h5><p>Принципиальное отличие от <a href="https://github.com/cocobelgica/AutoHotkey-JSON/blob/master/JSON.ahk">такого</a> и подобных в том, что для десериализации JSON-строки (т. е. для превращения её в AHK-объект) не используется парсинг. Вместо этого создаётся способом, описанным <a href="http://forum.script-coding.com/viewtopic.php?pid=78770#p78770">здесь</a>, JScript-объект, и выполняется метод eval() с JSON-строкой в качестве аргумента; далее JScript-объект превращается в AHK-объект. Такой подход позволяет избежать некоторых ошибок парсинга, а также делает код более компактным.<br /></p><div class="codebox"><pre><code>class JSON
{
   static JS := JSON._GetJScripObject()
   
   Parse(JsonString)  {
      try oJSON := this.JS.(&quot;(&quot; JsonString &quot;)&quot;)
      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 ? &quot;&quot; : &quot;,&quot; ) . ( isArray ? &quot;&quot; : this.Stringify(k) . &quot;:&quot; ) . this.Stringify(v)

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

   _GetJScripObject()  {
      VarSetCapacity(tmpFile, ((MAX_PATH := 260) - 14) &lt;&lt; !!A_IsUnicode, 0)
      DllCall(&quot;GetTempFileName&quot;, Str, A_Temp, Str, &quot;AHK&quot;, UInt, 0, Str, tmpFile)
      
      FileAppend,
      (
      &lt;component&gt;
      &lt;public&gt;&lt;method name=&#039;eval&#039;/&gt;&lt;/public&gt;
      &lt;script language=&#039;JScript&#039;&gt;&lt;/script&gt;
      &lt;/component&gt;
      ), % tmpFile
      
      JS := ObjBindMethod( ComObjGet(&quot;script:&quot; . tmpFile), &quot;eval&quot; )
      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) == &#039;[object Array]&#039;
         }
      )
      JS.(&quot;delete ActiveXObject; delete GetObject;&quot;)
      JS.(JScript)
   }

   _CreateObject(ObjJS)  {
      res := ObjJS.IsArray()
      if (res = &quot;&quot;)
         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
   }
}</code></pre></div><p>Пример использования. Методом <em>GetFromUrl()</em> получаем JSON-строку с сайта <a href="https://www.coindesk.com/">https://www.coindesk.com/</a> с курсом биткойна, затем методом <em>Parse()</em> превращаем её в AHK-объект, далее методом <em>Stringify()</em> снова преращаем AHK-объект в JSON-строку (порядок ключей не сохранится, станет в алфавитном порядке).<br /></p><div class="codebox"><pre><code>jsonStr := JSON.GetFromUrl(&quot;https://api.coindesk.com/v1/bpi/currentprice.json&quot;)

if IsObject(jsonStr)  {
   MsgBox, % jsonStr[1]
   Return
}
if (jsonStr = &quot;&quot;)
   Return

MsgBox, 64, JSON, % jsonStr

obj := JSON.Parse(jsonStr)
MsgBox, 64, Bitcoin Price
      , % &quot;upd: &quot; . obj.time.updated . &quot;`n`n&quot;
        . &quot;USD: &quot; . obj.bpi.USD.rate . &quot;`n&quot;
        . &quot;GBP: &quot; . obj.bpi.GBP.rate . &quot;`n&quot;
        . &quot;EUR: &quot; . obj.bpi.EUR.rate
        
MsgBox, 64, JSON From Obj, % jsonStr := JSON.Stringify(obj)</code></pre></div><p><a href="http://forum.script-coding.com/viewtopic.php?id=14438"><strong>Связанная тема</strong></a> для вопросов.</p>]]></description>
			<author><![CDATA[null@example.com (teadrinker)]]></author>
			<pubDate>Mon, 24 Dec 2018 10:15:29 +0000</pubDate>
			<guid>http://forum.script-coding.com/viewtopic.php?pid=130551#p130551</guid>
		</item>
	</channel>
</rss>
