Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How can I save an object's properties (serialize), then restore them later (deserialize)?

Classes and Objects

How can I save an object's properties (serialize), then restore them later (deserialize)?

by  wgcs  Posted    (Edited  )
Serializing an object simply means taking its properites and storing them in a string (a serial, or linear, state), that can be later restored into a property-based object.

While objects can contain other objects, this greatly complicates the serialization/deserializing process. This code only supports objects that don't contain other objects.

_ACCESS and _ASSIGN methods can also become problematic.

Code:
USE anyTable
SCATTER NAME oRec MEMO
cRec = serializeobject(oRec)
* do anything with the character data cRec...
*  ...say store it in a text file,
*  ...or send it through an email
*  ...or send it through TCP/IP
*  ...or pass it across a COM boundary
*  ...or, well, you get the picture!

oNewRec = deserializeobject(cRec)

* now examine oNewRec in the Debug Watch Window to see that it resembles oRec!


PROCEDURE SerializeObject
LPARAMETERS toObj
* Written by William GC Steinford
*  Input: toObj is a subclass of Empty (or a SCATTER NAME object)
* Output: a string representing toObj
LOCAL lnMem, laMem[1], lcOut, lcProp, lvData, lnI
lnMem = AMEMBERS(laMem,toObj,0)
SET TEXTMERGE TO MEMVAR lcOut ON
\\<? version="1.0" encoding="UTF-8" ?>
\<object class="empty">
FOR lnI = 1 TO lnMem
  lcProp = laMem[lnI]
  \  <property name="<<laMem[lnI]>>"
  lvData = EVALUATE('toObj.'+lcProp)
  * from lexRegistry.AnyTypeToC
  do case
    case varType(lvData)='T'
      \\ type="DATETIME">
      if empty(lvData)       
        \\{/:}
      ELSE
        lcData = "{^" + Transform(Year(  lvData)) + '/' ;
                      + Transform(Month( lvData)) + '/' ;
                      + Transform(Day(   lvData)) + ' ' ;
                      + Transform(hour(  lvData)) + ':' ;
                      + Transform(Minute(lvData)) + ':' ;
                      + Transform(Sec(   lvData)) ;
                      + '}'
        \\<<lcData>>
      endif
    case varType(lvData)='D'
      \\ type="DATE">
      if EMPTY(lvData)
        \\{}
      else
        lcData = '{^ '+ alltrim(Str(Year(lvData))) + '/' ;
                      + alltrim(Str(Month(lvData))) + '/' ;
                      + alltrim(Str(Day(lvData))) + '}'
        \\<<lcData>>
      endif
    case varType(lvData)='L'
      \\ type="LOGICAL"><<iif( vData, '.T.', '.F.' )>>
    case varType(lvData)='N'
      \\ type="NUMERIC"><<Transform(lvData)>>
    case varType(lvData)='C'
      \\ type="CHARACTER">
      * UrlEncode dangerous characters:
      lcData = StrTran(lvData,'%',    '%25')
      lcData = StrTran(lcData,'"',    '%22')
      lcData = StrTran(lcData,['],    '%27')
      lcData = StrTran(lcData,'[',    '%5B')
      lcData = StrTran(lcData,']',    '%5D')
      lcData = StrTran(lcData,'<',    '%3C')
      lcData = StrTran(lcData,'>',    '%3E')
      lcData = StrTran(lcData,chr(13),'%0D')
      lcData = StrTran(lcData,chr(10),'%0A')
      \\<<lcData>>
    case varType(lvData)='O'
      * Skip sub objects.
      * We could recursively call SerializeObject to package this member.
  endcase  
  \\</property>
ENDFOR
\</object>
SET TEXTMERGE TO
RETURN lcOut

PROCEDURE DeSerializeObject
LPARAMETERS tcObj
* Written by William GC Steinford
*  Input: tcObj is a string representing a subclass of Empty (or a SCATTER NAME object)
* Output: an actual object representing tcObj
* Example tcObj Value:
*  <? version="1.0" encoding="UTF-8" ?>
*  <object class="empty">
*    <property name="TEXT" type="CHARACTER">There     </property>
*    <property name="TEXT2" type="CHARACTER"></property>
*  </object>
*
LOCAL lnProp, laProp[1], lcObj, lnStrt, lnStop, loOut, lnI
lnStrt = ATC('<property',  tcObj )
lnStop = RATC('</object>', tcObj )
lcObj  = SUBSTR( tcObj, lnStrt, lnStop-lnStrt )
lnProp = ALINES(laProp, STRTRAN(lcObj,'</property>',CHR(13)) )
loOut  = CREATEOBJECT('Empty')
FOR lnI = 1 TO lnProp
  lvVal  = .NULL.
  lcName = .NULL.
  TRY
    lcType = UPPER( SUBSTR(laProp[lnI], ATC('type="',laProp[lnI])+6) )
    lcName =        SUBSTR(laProp[lnI], ATC('name="',laProp[lnI])+6)
    IF NOT '"'$lcName
      lcName = .NULL.
      THROW "bad name"
    ENDIF
    lcName = LEFT(lcName,AT('"',lcName)-1)
    lcVal  =        SUBSTR(laProp[lnI], ATC('>',     laProp[lnI])+1)
    DO CASE
      CASE lcType='DATETIME' AND TYPE(lcVal)='T'
        lvVal = EVALUATE(lcVal)
      CASE lcType='C'        AND TYPE('['+lcVal+']')='C'
        lvVal = EVALUATE('['+lcVal+']')
      CASE TYPE(lcVal)=LEFT(lcType,1)
        lvVal = EVALUATE(lcVal)
    ENDCASE
  CATCH TO oExc
    * Ignore errors... lvVal=.NULL. will signify errors.
  ENDTRY
  
  IF NOT ISNULL(lcName)
    TRY
      ADDPROPERTY(loOut, lcName, lvVal)
    CATCH TO oExc
      * Ignore errors
    ENDTRY
  ENDIF
ENDFOR
RETURN loOut
Register to rate this FAQ  : BAD 1 2 3 4 5 6 7 8 9 10 GOOD
Please Note: 1 is Bad, 10 is Good :-)

Part and Inventory Search

Back
Top