You are on page 1of 5

CLASSE JSON EM VSUALFOX - PARTE 1#INCLUDE "json.

h"

DEFINE CLASS json AS custom


*-- Specifies what should be used in VFP as Undefined. Chr(0) is the default.
undefined = ""
*-- Specifies the class to use when deserializing JSON objects. The Empty
class is the default.
defaultclass = "Empty"
*-- Specifies the module to get the class from when deserializing JSON
Objects.
defaultmodule = ""
*-- Determines the format to use when parsing dates: 1 = ISO 8601 (default),
2 = new Date(), 3 = MS JSON Date
parsedatetype = 1
usejsonfll = .T.
trimstrings = .T.
*-- JSON key to be used when identifying cursors.
keyforcursors = "VFPData"
*-- JSON key to be used when identifying collection items.
keyforitems = "items"
*-- If .T. then the class and classlibrary keys/properties will be taken into
consideration when parsing an object. If .F. then the defaults are used.
parserespectclass = .F.
*-- Target year last time GetTimezoneOffset was called.
PROTECTED _tzyear
_tzyear = .NULL.
*-- Start datetime for daylight saving last time GetTimezoneOffset was
called.
PROTECTED _tzdaylightstart
_tzdaylightstart = .NULL.
*-- Start datetime of standard last time GetTimezoneOffset was called.
PROTECTED _tzstandardstart
_tzstandardstart = .NULL.
*-- Setting for tlUTCDatetime parameter last time GetTimezoneOffset was
called.
PROTECTED _tzutc
_tzutc = .F.
*-- Standard offset last time GetTimezoneInformation was called.
PROTECTED _tzoffset
_tzoffset = .NULL.
*-- Daylight saving offset last time GetTimezoneInformation was called.
PROTECTED _tzdloffset
_tzdloffset = .NULL.
Name = "json"

*-- If .T. then all datetimes will be serialized to UTC equivalents and
deserialized as UTC. If .F. then all datetimes will be conversely treated as Local
datetimes.
useutcdatetime = .F.
PROTECTED name
PROTECTED classlibrary
PROTECTED addobject
PROTECTED addproperty
PROTECTED baseclass
PROTECTED class
PROTECTED cloneobject
PROTECTED comment
PROTECTED controlcount
PROTECTED controls
PROTECTED destroy
PROTECTED error
PROTECTED height
PROTECTED helpcontextid
PROTECTED newobject
PROTECTED objects
PROTECTED parent
PROTECTED parentclass
PROTECTED picture
PROTECTED readexpression
PROTECTED readmethod
PROTECTED removeobject
PROTECTED resettodefault
PROTECTED saveasclass
PROTECTED showwhatsthis
PROTECTED tag
PROTECTED whatsthishelpid
PROTECTED width
PROTECTED writeexpression
PROTECTED writemethod

PROCEDURE stringify
LPARAMETERS tvValue, tvReplacer, tvSpace, tnLevel, tcKey

*********************************************************************
*!* PURPOSE
*********************************************************************
*!* Serialize VFP objects, values, arrays and cursors to JSON
*********************************************************************
*!* PARAMETERS
*********************************************************************
*!* tvValue: (required)
*!* Either an instance of a VFP object/value/array or an
Alias that will be stringified.
*!* Arrays must be sent in byref...
JSON.Stringify(@MyArray)... otherwise only the first
*!* element of the array will be stringified
*!* tvReplacer: (optional)
*!* The optional tvReplacer parameter is either a string
specifying a Function/Object.Method,
*!* a byref Array or a string containing a comma-
delimited list of keys.
*!* If cFunction/cMethod is sent in it will be used via
Evaluate. It is sent the parent object
*!* and each of the member keys and value pairs.
Evaluate(m.tcReviver(parent, membername, value)'s
*!* return value is then serialized instead of the
original object.
*!* If the return value equals This.Undefined, then the
object is not serialized.
*!* If Array/CSV is sent in then it contains a list of
keys (member names) that should be serialized.
*!* All other keys (members) will be ignored.
*!* tvSpace: (optional)
*!* A string to be used with line-breaks to indent the
JSON produced, or it can be numeric specifying
*!* the number of spaces to use for indention. It simply
makes the JSON easier to read by beautifying it.
*!* tnLevel: (internal-use)
*!* Tracks the hierarchy levels used for proper indention
of JSON when tvSpace is sent in.
*!* tcKey: (internal-use)
*!* Allows the keys (member names) to be sent in when
stringifying key/value pairs.
*********************************************************************
*!* RETURN
*********************************************************************
*!* String - JSON representation of tvValue sent in
*********************************************************************

LOCAL lcTypeOfValue, lcReturnJSON, lvValue, lcIndent, lcKey


LOCAL lcPointSettingWas, lcSeparatorSettingWas

m.lcReturnJSON = THIS.Undefined && default considered to be undefined

IF VARTYPE(m.tnLevel, .F.) != "N"


m.tnLevel = 0
ENDIF

IF m.tnLevel > 58 && Avoid nesting too deep error


RETURN (m.lcReturnJSON)
ENDIF

IF VARTYPE(m.tcKey) = "C"
m.lcKey = ["] + m.tcKey + [": ]
ELSE
m.lcKey = ""
ENDIF

m.lcTypeOfValue = TYPE("m.tvValue", 1)
IF m.lcTypeOfValue != "A" && if it's not an array then let's get the
Type
m.lcTypeOfValue = VARTYPE(m.tvValue, .F.)
IF m.lcTypeOfValue = "O"
*!* ToJSON() method shouldn't serialize, simply pass back a
value or undefined
IF PEMSTATUS(m.tvValue, "tojson", 5) && if object has a
ToJSON() method then use it to get value to serialize
m.lvValue = EVALUATE("m.tvValue.tojson()")
ELSE
m.lvValue = m.tvValue
ENDIF
ELSE
m.lvValue = m.tvValue
ENDIF
ENDIF

*!* save settings - handle localization


m.lcPointSettingWas = SET("Point")
m.lcSeparatorSettingWas = SET("Separator")
IF m.lcPointSettingWas != "."
SET POINT TO "."
ENDIF
IF m.lcSeparatorSettingWas != ","
SET SEPARATOR TO ","
ENDIF
DO CASE
CASE m.lcTypeOfValue = "A" && Array
m.lcReturnJSON = THIS.SerializeArray(@m.tvValue,
@m.tvReplacer, tvSpace, tnLevel)
CASE m.lcTypeOfValue = "C" && Character, Memo, Varchar, Varchar
(Binary)
*!* are we on the first pass (cursor serialization would
never be nested in an array/object) and is it an alias?
IF m.tnLevel = 0 AND USED(m.lvValue)
m.lcReturnJSON = THIS.Serializecursor(m.lvValue,
@m.tvReplacer, m.tvSpace, m.tnLevel)
ELSE && then it must be a string
IF THIS.TrimStrings
m.lcReturnJSON =
THIS.SerializeString(ALLTRIM(m.lvValue))
ELSE
m.lcReturnJSON =
THIS.SerializeString(m.lvValue)
ENDIF
ENDIF
CASE m.lcTypeOfValue = "D" && Date
m.lcReturnJSON = THIS.SerializeDate(m.lvValue)
CASE m.lcTypeOfValue = "G" && General
m.lcReturnJSON = THIS.Undefined
CASE m.lcTypeOfValue = "L" && Logical
m.lcReturnJSON = THIS.SerializeLogical(m.lvValue)
CASE INLIST(m.lcTypeOfValue, "N", "Y") && Numeric, Float, Double,
Integer, or Currency
m.lcReturnJSON = THIS.SerializeNumber(m.lvValue)
CASE m.lcTypeOfValue = "O" && Object
m.lcReturnJSON = THIS.SerializeObject(@m.lvValue,
@m.tvReplacer, tvSpace, tnLevel)
CASE m.lcTypeOfValue = "Q" && Blob, Varbinary
m.lcReturnJSON = THIS.Undefined
CASE m.lcTypeOfValue = "T" && DateTime
m.lcReturnJSON = THIS.SerializeDatetime(m.lvValue)
CASE m.lcTypeOfValue = "U" && Unknown or variable does not exist
m.lcReturnJSON = THIS.Undefined
CASE m.lcTypeOfValue = "X" && Null
m.lcReturnJSON = THIS.SerializeNull()
OTHERWISE
m.lcReturnJSON = THIS.Undefined
ENDCASE

*!* revert settings if applicable - handle localization


IF m.lcPointSettingWas != "."
SET POINT TO (m.lcPointSettingWas)
ENDIF
IF m.lcSeparatorSettingWas != ","
SET SEPARATOR TO (m.lcSeparatorSettingWas)
ENDIF

IF !THIS.IsUndefined(m.lcReturnJSON)
m.lcIndent = THIS.GetIndentChars(m.tvSpace, m.tnLevel)
IF m.tnLevel != 0
m.lcReturnJSON = m.lcIndent + m.lcKey + m.lcReturnJSON
ENDIF
ENDIF
RETURN (m.lcReturnJSON)

*********************************************************************
*!* ADDITIONAL NOTES AND COMMENTS
*********************************************************************
*!* Online JSON Validator
*!* http://www.jsonlint.com/
*********************************************************************
ENDPROC

You might also like