ValueTree - Advanced Use
ValueTrees, along with the ValueTreeSerializeParameter and ValueTreeDeserializeParameter commands, are used within web services to convert data between a variable of a known data type (simple, array, or struct) and a standard format (the ValueTree). Because the format of the ValueTree is known, it can be generically converted to XML or JSON.
This is an advanced technique, and these commands and the entire process have always been private. However, a number of developers have been working with these commands to create ways to serialize and deserialize data in their objects. As part of an effort to turn these into public interfaces, we have made changes to make these commands more robust and flexible. When used properly, these commands can perform powerful tasks.
As part of making these commands more robust, we have improved error checking and done a better job of initializing parameter values. To enhance flexibility, we now support serializing from and deserializing to variant complex data types. In particular, a struct or an array stored in a variant can be serialized and deserialized using the underlying data type. This makes it possible to create generic methods that can serialize and deserialize any data type.
Serializing to a ValueTree
When serializing to a ValueTree, you may use a variant type, and the variant’s underlying type will be used. The following two examples are equivalent:
ValueTreeSerializeParameter MyArrayOfStructs to MyValueTree
Move MyArrayOfStructs to vVariant
ValueTreeSerializeParameter vVariant to MyValueTree
Deserializing from a ValueTree
When deserializing, the destination data type must be known. If the destination data type is a variant, it must be initialized with an instance of the underlying type (probably an empty instance). The following two examples are equivalent:
ValueTreeDeserializeParameter MyValueTree to MyArrayOfStructs
tSomeStruct[] MyArrayOfStructs
Move MyArrayOfStructs to vVariant // this initializes the destination variable
ValueTreeDeserializeParameter MyValueTree to vVariant
Move vVariant to MyArrayOfStructs
Doing this within a single method provides little advantage. The power of using variants is that you can assign any variable to a variant, pass that variant as a parameter, and use this to create generic serialize and deserialize methods.
Example: Generic Serialization and Deserialization
The following shows how this could be used to write generic methods that can serialize and deserialize any object property to/from a ValueTree. That ValueTree could then be converted to XML or JSON and stored as needed, providing a mechanism for creating persistent objects.
Use ui
Use tValueTree.pkg
Struct tWinPoint
DWord x
DWord y
End_Struct
Object o1 is a cObject
Property String psName "John"
Property tWinPoint pPt
Property tWinPoint[] ppts
Function SerializeProp Handle hmProp Returns tValueTree
tValueTree vt
Variant Val
Get hmProp to Val
ValueTreeSerializeParameter Val to vt
Function_Return vt
End_Function
Procedure Set SerializeProp Handle hmGetProp Handle hmSetProp tValueTree vt
Variant val
Get hmGetProp to Val
ValueTreeDeSerializeParameter vt to Val
Get hmSetProp to Val
End_Function
End_Object
Procedure Test
String sN
tValueTree vt vts vtsa
tWinPoint pt pt2
tWinPoint[] pts pts2
Variant vsa val
Move 5 to pt.x
Move 10 to pt.y
Set pPt of o1 to pt
Get psName of o1 to sN
Get SerializeProp of o1 (RefFunc(psName)) to vt
Move "xxxxx" to vt.sValue
Set psName of o1 to "aa"
Set SerializeProp of o1 (RefFunc(psName)) (RefProcSet(psName)) to vt
Get psName of o1 to sN
Move 100 to pt.x
Move 200 to pt.y
ValueTreeSerializeParameter pt to vts
Set SerializeProp of o1 (RefFunc(pPt)) (RefProcSet(pPt)) to vts
Get pPt of o1 to pt
Integer i
For i from 0 to 100
Move pt to pts[i]
Loop
ValueTreeSerializeParameter pts to vtsa
Set SerializeProp of o1 (RefFunc(pPts)) (RefProcSet(pPts)) to vtsa
Move (ResizeArray(pts, 0)) to pts
Get pPts of o1 to pts
End_Procedure
Send Test