The RPG Maker Resource Kit

RMRK RPG Maker Creation => VX Ace => VXA Scripts Database => Topic started by: game_guy on February 27, 2012, 06:29:44 AM

Title: [VXA] JSON Encoder/Decoder
Post by: game_guy on February 27, 2012, 06:29:44 AM
JSON Encoder/Decoder
Authors: game_guy
Version: 1.1
Type: Script Utility


Introduction

QuoteJSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate.
This is a simple JSON Parser or Decoder. It'll take JSON thats been formatted into a string and decode it into the proper object. You can also encode certain Ruby objects into JSON.

This is a scripter's utility and isn't meant to add any new functionality or prove usefulness to non-scripters.


Features



Screenshots

N/A


Demo

No demo.


Script

[SPOILER]
#===============================================================================
# JSON Encoder/Decoder
# Version 1.1
# Author: game_guy
#-------------------------------------------------------------------------------
# Intro:
# JSON (JavaScript Object Notation) is a lightweight data-interchange
# format. It is easy for humans to read and write. It is easy for machines to
# parse and generate.
# This is a simple JSON Parser or Decoder. It'll take JSON thats been
# formatted into a string and decode it into the proper object.
# This script can also encode certain ruby objects into JSON.
#
# Features:
# Decodes JSON format into ruby strings, arrays, hashes, integers, booleans.
#
# Instructions:
# This is a scripters utility. To decode JSON data, call
# JSON.decode("json string")
# -Depending on "json string", this method can return any of the values:
#  -Integer
#  -String
#  -Boolean
#  -Hash
#  -Array
#  -Nil
#
# To Encode objects, use
# JSON.encode(object)
# -This will return a string with JSON. Object can be any one of the following
#  -Integer
#  -String
#  -Boolean
#  -Hash
#  -Array
#  -Nil
#
# Credits:
# game_guy ~ Creating it.
#===============================================================================
module JSON
 
  TOKEN_NONE = 0;
  TOKEN_CURLY_OPEN = 1;
  TOKEN_CURLY_CLOSED = 2;
  TOKEN_SQUARED_OPEN = 3;
  TOKEN_SQUARED_CLOSED = 4;
  TOKEN_COLON = 5;
  TOKEN_COMMA = 6;
  TOKEN_STRING = 7;
  TOKEN_NUMBER = 8;
  TOKEN_TRUE = 9;
  TOKEN_FALSE = 10;
  TOKEN_NULL = 11;
 
  @index = 0
  @json = ""
  @length = 0
 
  def self.decode(json)
    @json = json
    @index = 0
    @length = @json.length
    return self.parse
  end
 
  def self.encode(obj)
    if obj.is_a?(Hash)
      return self.encode_hash(obj)
    elsif obj.is_a?(Array)
      return self.encode_array(obj)
    elsif obj.is_a?(Fixnum) || obj.is_a?(Float)
      return self.encode_integer(obj)
    elsif obj.is_a?(String)
      return self.encode_string(obj)
    elsif obj.is_a?(TrueClass) || obj.is_a?(FalseClass)
      return self.encode_bool(obj)
    elsif obj.is_a?(NilClass)
      return "null"
    end
    return nil
  end
 
  def self.encode_hash(hash)
    string = "{"
    hash.each_key {|key|
      string += "\"#{key}\":" + self.encode(hash[key]).to_s + ","
    }
    string[string.size - 1, 1] = "}"
    return string
  end
 
  def self.encode_array(array)
    string = "["
    array.each {|i|
      string += self.encode(i).to_s + ","
    }
    string[string.size - 1, 1] = "]"
    return string
  end
 
  def self.encode_string(string)
    return "\"#{string}\""
  end
 
  def self.encode_integer(int)
    return int.to_s
  end
 
  def self.encode_bool(bool)
    return (bool.is_a?(TrueClass) ? "true" : "false")
  end
 
  def self.next_token(debug = 0)
    char = @json[@index, 1]
    @index += 1
    case char
    when '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-'
      return TOKEN_NUMBER
    when '{'
      return TOKEN_CURLY_OPEN
    when '}'
      return TOKEN_CURLY_CLOSED
    when '"'
      return TOKEN_STRING
    when ','
      return TOKEN_COMMA
    when '['
      return TOKEN_SQUARED_OPEN
    when ']'
      return TOKEN_SQUARED_CLOSED
    when ':'
      return TOKEN_COLON
    end
    @index -= 1
    if @json[@index, 5] == "false"
      @index += 5
      return TOKEN_FALSE
    elsif @json[@index, 4] == "true"
      @index += 4
      return TOKEN_TRUE
    elsif @json[@index, 4] == "null"
      @index += 4
      return TOKEN_NULL
    end
    return TOKEN_NONE
  end
 
  def self.parse(debug = 0)
    complete = false
    while !complete
      if @index >= @length
        break
      end
      token = self.next_token
      case token
      when TOKEN_NONE
        return nil
      when TOKEN_NUMBER
        return self.parse_number
      when TOKEN_CURLY_OPEN
        return self.parse_object
      when TOKEN_STRING
        return self.parse_string
      when TOKEN_SQUARED_OPEN
        return self.parse_array
      when TOKEN_TRUE
        return true
      when TOKEN_FALSE
        return false
      when TOKEN_NULL
        return nil
      end
    end
  end
 
  def self.parse_object
    obj = {}
    complete = false
    while !complete
      token = self.next_token
      if token == TOKEN_CURLY_CLOSED
        complete = true
        break
      elsif token == TOKEN_NONE
        return nil
      elsif token == TOKEN_COMMA
      else
        name = self.parse_string
        return nil if name == nil
        token = self.next_token
        return nil if token != TOKEN_COLON
        value = self.parse
        obj[name] = value
      end
    end
    return obj
  end
 
  def self.parse_string
    complete = false
    string = ""
    while !complete
      break if @index >= @length
      char = @json[@index, 1]
      @index += 1
      case char
      when '"'
        complete = true
        break
      else
        string += char.to_s
      end
    end
    if !complete
      return nil
    end
    return string
  end
 
  def self.parse_number
    @index -= 1
    negative = @json[@index, 1] == "-" ? true : false
    string = ""
    complete = false
    while !complete
      break if @index >= @length
      char = @json[@index, 1]
      @index += 1
      case char
      when "{", "}", ":", ",", "[", "]"
        @index -= 1
        complete = true
        break
      when "0", "1", "2", '3', '4', '5', '6', '7', '8', '9'
        string += char.to_s
      end
    end
    return string.to_i
  end
 
  def self.parse_array
    obj = []
    complete = false
    while !complete
      token = self.next_token(1)
      if token == TOKEN_SQUARED_CLOSED
        complete = true
        break
      elsif token == TOKEN_NONE
        return nil
      elsif token == TOKEN_COMMA
      else
        @index -= 1
        value = self.parse
        obj.push(value)
      end
    end
    return obj
  end
 
end
[/SPOILER]


Instructions

Its recommended to place this script at the top, then it can be used in any script below it. To call the parsing method, use
[spoiler=JSON Decode Example]
JSON.decode(json)
Returns any of the following depending on "json":
-Integer
-String
-Boolean
-Hash
-Array
-Nil


Example:
json = '{"result":true,"profile":{"id":23,"display_name":"game_guy","group":{"id":"1","name":"Administrator","color":"#FF0000"}},"array":[0,1,2,3]}'
data = JSON.decode(json)


Output
data = {'result' => true, 'profile' => {'id' => 23, 'display_name' => 'game_guy', 'group' => {'id' => 1, 'name' => 'Administrator', 'color' => '#FF0000'}}, 'array' => [0, 1, 2, 3]}
As you can see, it supports multi-level hashes and the method returned a hash object since the string started with a "{". The first character is what defines what object its going to return.[/spoiler]

[spoiler=JSON Encode Example]This can encode the following Ruby objects into JSON format.
Integer
Boolean
String
Hash
Array
Nil

Here's your input.
data = {'result' => true, 'profile' => {'id' => 23, 'display_name' => 'game_guy', 'group' => {'id' => 1, 'name' => 'Administrator', 'color' => '#FF0000'}}, 'array' => [0, 1, 2, 3]}
json = JSON.encode(data)


Output
'{"result":true,"profile":{"id":23,"display_name":"game_guy","group":{"id":"1","name":"Administrator","color":"#FF0000"}},"array":[0,1,2,3]}'[/spoiler]


Compatibility

Should work with anything.


Credits and Thanks



Author's Notes

Enjoy! :) You guys are lucky that VX Ace uses Ruby 1.9, or else this script wouldn't have been released. With the example code I posted, it takes a few seconds for Ruby 1.8 to parse it all.
Title: Re: [VXA] JSON Parser
Post by: modern algebra on February 27, 2012, 10:46:06 PM
Seems like it could be pretty neat!

P.S. I don't know what this says about my character, but I've always wanted to write a script that started with "J", but have never been able to do so. It, "X", "Y", and "Z" have all proven elusive.
Title: Re: [VXA] JSON Encoder/Decoder
Post by: game_guy on February 28, 2012, 02:53:51 AM
Ha, thanks! You might wanna update the Script Index, I changed the name and updated to 1.1. I added the encoder implementation. Whats great about JSON is that its data easily readable by humans and there are several languages that have an encoder/decoder. Its essentially cross-language way to serialize data.

And maybe to toss an idea out, if you wanted to create a script that started with a Y, you could create a YAML Encoder/Decoder.