Question
· Jun 1, 2016

What is the best way to serialize object/list/array/etc to string?

Hello!

Are there any short ways of serializing COS entity to the string? I am searching for something like .$toJSON() , but I need Caché 2013.* support.

The one way I supposed to work is to use $listbuild:

 

set str = $LISTTOSTRING($LB(1,2,3,",",5))
set list = $LISTFROMSTRING(str,",")
zw list
list=$lb("1","2","3","","","5")

 

But the problem is that $listbuild does not escape delimiters, and it is not possible to deserialize serialized string. The structure I need to serialize may contain any characters.

Are there any short ways to do this in Caché to avoid writing custom parser?

Discussion (15)2
Log in or sign up to continue

Now it becomes clear!

I had wondered if your requirement for "string" was that it contained only printable characters. In such a case one solution could be to base64-encode the result of $listbuild. On a Unicode instance of Caché you'd need to convert it to UTF8 first.

USER>s list=$lb($c(0),$c(1),"Hello",",","World")
 
USER>s printable=$system.Encryption.Base64Encode($zconvert(list,"O","UTF8"))
 
USER>w printable
AwEAAwEBBwFIZWxsbwMBLAcBV29ybGQ=
USER>s list2=$zconvert($system.Encryption.Base64Decode(printable),"I","UTF8")
 
USER>w list2=list
1
USER>w $a($li(list2,1))
0
USER>w $a($li(list2,2))
1
USER>w $li(list2,3)
Hello
USER>w $li(list2,4)
,
USER>w $li(list2,5)
World
USER>

Note that Base64Encode adds a CRLF after every 76 characters, so if you want to remove these from your "printable" you can either $TR(printable,$c(13,10)) or on 2015.2 or later you can pass a second argument to Base64Encode.

Thanks John, the above terminal transcript is not correct showing what I wanted to show. I've fixed this.

Why can't you understand the purpose of this?

I can only transfer strings by some channel (f.e. interprocess communication). Now I need to send the array of strings (list, object, etc) from sender to receiver. To send this array, I must convert it to the string and then, after receiving, convert it back to array to read it's elements. How to do this in Caché 2013.*? The strings in array can contain any characters, so it is not possible to specify any delimiter character.

Finally I got why the question is pretty confusing for you. Just imagine, I didn't know that $lb() returns the simple string. I didn't know that I can write this string to file, read it from file, and then apply $LISTGET function to it. I didn't know $LISTGET function takes string type. I thought that $LIST is something more than just a string.

So the solution:

set string = $LB(1,2,3,",",5)
/* send this string anywhere */
set element = $LISTGET(string, 4) // = ","

[UPD fixed] Got you. Incredible! It seems that this is what I needed:

USER>set string = $lb($C(1),$c(2),$c(3),",",$c(0))
USER>w $a($LISTGET(a,1))
1
USER>w $a($LISTGET(a,2))
2
USER>w $a($LISTGET(a,3))
3
USER>w $LISTGET(a,4)
,
USER>w $a($LISTGET(a,5))
0

Until the list values may contain any set of characters here this is the best solution, thank you, Jon!

You can use %SerialObject for that:

Class Utils.Serial Extends %SerialObject
{

Property Payload As %String;

/// zw ##class(Utils.Serial).Test()
ClassMethod Test(input As %String = {$lb(1,2,3,",",5)}) As %String
{
    
    set obj = ##class(Utils.Serial).%New()
    set obj.Payload = input
    do obj.%SerializeObject(.str)
    kill (str)
    
    set obj = ##class(Utils.Serial).%Open(str)
    return obj.Payload
}
}

For example:

zw ##class(Utils.Serial).Test("1,2,3,,,5")
>"1,2,3,,,5"

zw ##class(Utils.Serial).Test($lb(1,2,3,",",5))
>$lb(1,2,3,",",5)