AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

JSON read/write parser
Goto page 1, 2  Next
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
Titan



Joined: 11 Aug 2004
Posts: 4975
Location: /b/

PostPosted: Mon Aug 11, 2008 2:15 pm    Post subject: JSON read/write parser Reply with quote

I wrote this to help with automated hacking of my xulrunner/prism code. Others may also find it useful as a faster and more compact alternative to XML or INI.

Code:
; JSON string:
j = {"version":"1","window":{"state":3,"screenX":25,"screenY":25,"width":790,"height":605,"test":{"nested":"object"}},"sidebar":{"visible":false,"width":"200"}}
MsgBox, % json(j, "version") ; returns "1"
MsgBox, % json(j, "window.width", 800) ; returns 790, sets window->width to 800

r = { "a" : true, "b" : [ 1, [ 2.1, 2.2, { "sub" : false, "test" : [ null, "pass" ] } ], 3 ] }
MsgBox, % json(r, "b[1][2].test[1]") ; array support


Download
_________________


Last edited by Titan on Fri Sep 18, 2009 4:03 am; edited 5 times in total
Back to top
View user's profile Send private message Send e-mail Visit poster's website
heresy



Joined: 11 Mar 2008
Posts: 291

PostPosted: Mon Aug 11, 2008 3:51 pm    Post subject: Reply with quote

it reminds me Python's dictionary data type too. good for handling large variables.
i think it would be comfortable if we can skip first parameter and it creates a global variable automatically.
which would look like below
Code:
json("Screen.Width", A_ScreenWidth) ;set
MsgBox % ("Screen.Width") ;get

Thanks for sharing
_________________
Easy WinAPI - Dive into Windows API World
Benchmark your AutoHotkey skills at PlayAHK.com
Back to top
View user's profile Send private message
n-l-i-d
Guest





PostPosted: Mon Aug 11, 2008 4:38 pm    Post subject: Reply with quote

Impressive! Cool
Back to top
Titan



Joined: 11 Aug 2004
Posts: 4975
Location: /b/

PostPosted: Tue Aug 12, 2008 11:10 am    Post subject: Reply with quote

heresy wrote:
i think it would be comfortable if we can skip first parameter and it creates a global variable automatically
Good idea, you can use static variable too. The main version will stay the same so you can modify external objects.
_________________
Back to top
View user's profile Send private message Send e-mail Visit poster's website
haichen



Joined: 05 Feb 2007
Posts: 174
Location: Osnabrück, Germany

PostPosted: Wed Sep 10, 2008 4:33 pm    Post subject: Reply with quote

There is a problem with spaces after the :.
Would be nice if you (or someone else) could include this.
I tried to figure the problem and I think if there is Whitespace after : z is too small. But the RegexMatch with backreferences ist to complicated for me. Very Happy

edit: Forgot to say: there's only a problem when changing values like ..."width": 790,...

Thanks for this nice piece of code.
Back to top
View user's profile Send private message
BIG_RED_TEXT



Joined: 12 Jan 2008
Posts: 129

PostPosted: Wed Sep 10, 2008 8:50 pm    Post subject: Reply with quote

it seems to be a kickass function imho, think I'll use it
Back to top
View user's profile Send private message
haichen



Joined: 05 Feb 2007
Posts: 174
Location: Osnabrück, Germany

PostPosted: Thu Sep 11, 2008 12:45 am    Post subject: Reply with quote

I changed the function a little bit. Now it works with structured json files and with spaces after the :.
Code:
json(ByRef js, s, v = "") {
   j = %js%
   Loop, Parse, s, .
   {
      p = 2
      RegExMatch(A_LoopField, "([+\-]?)([^[]+)(?:\[(\d+)\])?", q), q3 := q3 ? q3 : 0
      Loop {
         If (!p := RegExMatch(j, "(""|')([^\1]+?)\1\s*:\s*((""|')?[^\4]*?\4|(\{(?:[^{}]*+|(?5))*\})|[+\-]?\d+(?:\.\d*)?|true|false|null?)\s*(?:,|$|\})", x, p))
            Return
         Else If (-1 == q3 -= x2 == q2 or q2 == "*") {
            j = %x3%
            z += p + StrLen(x2) - 2
            Break
         }
         Else p += StrLen(x)
      }
   }

  z-=StrLen(x)
  If (v !="" ) {
    NewStr := RegExReplace(x, x3 , v)
    js := RegExReplace(js, x , NewStr,"",1,z)
  }


   Return, x3 == "false" ? 0 : x3 == "true" ? 1 : x3 == "null" or x3 == "nul" ? "" : SubStr(x3, 1, 1) == "" ? SubStr(x3, 2, -1) : x3
}


Example:
Code:
j=
(
{
   "intl": {
      "app_locale": "de"
   },
   "options_window": {
      "last_tab_index": "2"

   }
}
)


test="1212"
MsgBox, % json(j,"options_window.last_tab_index", test)
MsgBox, % json(j,"options_window.last_tab_index")
Back to top
View user's profile Send private message
Titan



Joined: 11 Aug 2004
Posts: 4975
Location: /b/

PostPosted: Thu Sep 11, 2008 10:35 am    Post subject: Reply with quote

haichen wrote:
I changed the function a little bit. Now it works with structured json files and with spaces after the :.
Thanks for writing a fix. This function is not standards compliant with array handling, the wildcard selector is also a custom extension. I had planned to release a fully conformant update but left AutoHotkey to use C# in my toolchain for which I wrote SimpleJSON. I'll look at the ahk code again tonight and will try to make the final adjustments.
_________________
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Titan



Joined: 11 Aug 2004
Posts: 4975
Location: /b/

PostPosted: Thu Sep 11, 2008 9:46 pm    Post subject: Reply with quote

For those who are interested version 2a is what I currently use. It includes a few bug fixes and supports complex nested arrays:

Code:
j = { "a" : true, "b" : [ 1, [ 2.1, 2.2, { "sub" : false, "test" : [ null, "pass" ] } ], 3 ] }
MsgBox, % json(j, "b[1][2].test[1]")


The only problem is an odd quirk in pcre which causes a failure to match {"v":"1"} where "1" could be any one or two digit number, with or without quotes. I think this is due to conflicting atomic alternations; if anyone can write better regex please post them.
_________________
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Rabiator



Joined: 17 Apr 2005
Posts: 283
Location: Sauerland

PostPosted: Thu Sep 11, 2008 10:04 pm    Post subject: Reply with quote

Unfortunately the example in your first post doesn't work any more.
Back to top
View user's profile Send private message
Titan



Joined: 11 Aug 2004
Posts: 4975
Location: /b/

PostPosted: Thu Sep 11, 2008 10:55 pm    Post subject: Reply with quote

Rabiator wrote:
Unfortunately the example in your first post doesn't work any more.
Yes, v2 has a bug I previously mentioned - notice "version":"1" in the example and "last_tab_index": "\"1212\"" haichens code.
_________________
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Lexikos



Joined: 17 Oct 2006
Posts: 4367
Location: Qld, Australia

PostPosted: Sun Dec 21, 2008 10:33 am    Post subject: Reply with quote

Titan wrote:
The only problem is an odd quirk in pcre which causes a failure to match {"v":"1"} where "1" could be any one or two digit number, with or without quotes.
Has this been fixed? I see no such problem, but it does fail to match any quoted string containing the character 1. What is the purpose of the 1 in the highlighted character classes below?
Code:
         If (!p := RegExMatch(j, "(?<!\\)(""|')([^\-1]+?)(?<!\\)(?-1)\s*:\s*((\{(?:[^{}]++|(?-1))*\})|(\[(?:[^[\]]++|(?-1))*\])|"
            . "(?<!\\)(""|')[^\-1]*?(?<!\\)(?-1)|[+\-]?\d+(?:\.\d*)?|true|false|null?)\s*(?:,|$|\})", x, p))
Back to top
View user's profile Send private message Visit poster's website
Titan



Joined: 11 Aug 2004
Posts: 4975
Location: /b/

PostPosted: Sun Dec 21, 2008 11:16 am    Post subject: Reply with quote

Lexikos wrote:
it does fail to match any quoted string containing the character 1.
After some testing I came to the same conclusion, perhaps I didn't check well enough when I made my earlier claim.

Lexikos wrote:
What is the purpose of the 1 in the highlighted character classes below? ... [^\-1]
\-1 is a relative reference to a captured subpattern - see SUBPATTERNS AS SUBROUTINES in pcre(3). I replaced the relative references with absolute ones to work around the bug and the parser works! Thanks for drawing my attention to this.

Version 2 has been committed to the SVN. The old version can be downloaded for historic reasons.
_________________
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Lexikos



Joined: 17 Oct 2006
Posts: 4367
Location: Qld, Australia

PostPosted: Sun Dec 21, 2008 1:06 pm    Post subject: Reply with quote

Titan wrote:
\-1 is a relative reference to a captured subpattern
I believe that is incorrect.
pcre(3) wrote:
BACKREFERENCES

\n reference by number (can be ambiguous)
\gn reference by number
\g{n} reference by number
\g{-n} relative reference by number
\k<name> reference by name (Perl)
\k'name' reference by name (Perl)
\g{name} reference by name (Perl)
\k{name} reference by name (.NET)
(?P=name) reference by name (Python)

Anyway, thanks for the prompt update.

Another thing... should ' be equivalent to "?
  • "string' is valid, but doesn't seem like it should be. Using \g{-1} instead of (?-1) would invalidate it.
  • Using "string", both " are omitted from the return value.
  • Using 'string', both ' are included in the return value.
  • Using "string', both are omitted.
  • Using 'string", both are kept.
Back to top
View user's profile Send private message Visit poster's website
Titan



Joined: 11 Aug 2004
Posts: 4975
Location: /b/

PostPosted: Sun Dec 21, 2008 2:01 pm    Post subject: Reply with quote

Lexikos wrote:
\g{-n} relative reference by number
I must have missed that when converting (?-1) to a character class.

Lexikos wrote:
should ' be equivalent to "?
No, JSON doesn't define ' as a string token, only ". This is just a quirk in my parser - (""|') isn't matched up with SubStr(j, 1, 1) == """" on line 55 for performance reasons.
_________________
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group