XML - From object to stream to database and back

Posted by Admin on 13-Apr-2009 10:17

I would like to be able to take XML data and write/read it to a Progress database without saving to an OS file. I believe I understand how to get the XML to a stream, but I'm not quite sure how to get it from the stream into a CLOB/Longchar or from the CLOB/Longchar back to the stream.

I have a couple of different XML files that are used for saving settings within the application. For example, I use the SaveAsXML method for an UltraExplorerBar to write the current settings when the app is closing, and then LoadFromXML to read them when restarting. There are also some settings that are not object specific that are managed via a dataset, and those I write out using the dataset's WRITE-XML method and read back using READ-XML. In both cases, the XML is just a file on the OS. These now need to be stored in the database and I would prefer to not use an intermediate OS file.

Can anyone provide some sample code for converting the stream to a CLOB/Longchar and back. It would really be appreciated.

Thanks,

Jim

All Replies

Posted by Peter Judge on 13-Apr-2009 10:38

I would like to be able to take XML data and write/read it to a Progress database without saving to an OS file. I believe I understand how to get the XML to a stream, but I'm not quite sure how to get it from the stream into a CLOB/Longchar or from the CLOB/Longchar back to the stream.

What kind of stream are you working with? An ABL STREAM, or a .NET Stream object?

If the former, then you have the XML in a non-OS file-based form (ie the ProDataSet or buffer object).

-- peter

Posted by Admin on 13-Apr-2009 10:53

Oops, I should have been more clear.

This would be a .Net object...


DEFINE VARIABLE myMemoryStream AS System.IO.MemoryStream NO-UNDO.


ASSIGN
    myMemoryStream = NEW System.IO.MemoryStream()
.


ultraExplorerBar1:SaveAsXml(myMemoryStream).


/* Now assign a Clob or LongChar variable or database field. */

And then of course, back again.

Thanks,

Jim

Posted by Peter Judge on 13-Apr-2009 14:42


DEFINE VARIABLE myMemoryStream AS System.IO.MemoryStream NO-UNDO.


ASSIGN
    myMemoryStream = NEW System.IO.MemoryStream()
.


ultraExplorerBar1:SaveAsXml(myMemoryStream).


/* Now assign a Clob or LongChar variable or database field. */

Thanks to something Patrick Tallman said over at

http://communities.progress.com/pcom/message/54023#54023

I came up with the following:

def var obj1 as System.Text.UTF8Encoding.
def var longc as longchar.
       
obj1 = new System.Text.UTF8Encoding().
       
longc = obj1:GetString(myMemoryStream:ToArray()).

A question I have is whether this performs better than using a file-based operation such as the untested code below (I'm assuming that performance is the reason why you don't want to write to disk).

ultraExplorerBar1:SaveAsXml('c:\temp\my.xml').
copy-lob from 'c:/temp/my.xml' to longc.

And then of course, back again.

... left as an exercise for the reader

-- peter

Posted by Admin on 13-Apr-2009 15:18

Peter,

Thanks for the example...

I will be testing performance between the stream and OS file methods. Our app is going to be able to be run on a Term Server, so I was trying to limit the number of OS files as much as possible. If performance is noticeably better writing to the OS, I may elect to go that route.

Given that, I'm still not quite sure of the reverse method from what you posted. I need to take XML from a Longchar and assign it to a stream and then load into the object. I found an example on the Infragistics site but I'm not sure of the syntax in Progress, particularly the first two lines. The example there is using a grid, but the methods should be similar...

byte[ bt = System.Text.Encoding.UTF8.GetBytes(layout.xmlGridSettings);
MemoryStream stream = new MemoryStream(bt, 0, bt.Length);

gridDocuments.DisplayLayout.LoadFromXml(stream, PropertyCategories.All);

Thanks,

Jim

Posted by Peter Judge on 13-Apr-2009 15:32

I will be testing performance between the stream and OS file methods. Our app is going to be able to be run on a Term Server, so I was trying to limit the number of OS files as much as possible. If performance is noticeably better writing to the OS, I may elect to go that route.

That makes sense.

Given that, I'm still not quite sure of the reverse method from what you posted. I need to take XML from a Longchar and assign it to a stream and then load into the object. I found an example on the Infragistics site but I'm not sure of the syntax in Progress, particularly the first two lines. The example there is using a grid, but the methods should be similar...

byte[ bt = System.Text.Encoding.UTF8.GetBytes(layout.xmlGridSettings);
MemoryStream stream = new MemoryStream(bt, 0, bt.Length);

gridDocuments.DisplayLayout.LoadFromXml(stream, PropertyCategories.All);

Thanks,

Jim

Based on the IG example, the ABL should look something like the below. The xmlGridSettings LONGCHAR can be populated from the TT.

def var myEnc as System.Text.UTF8Encoding.
def var myStream as System.IO.MemoryStream.
def var xmlGridSettings as longchar.

myEnc = new System.Text.UTF8Encoding().

myStream = new MemoryStream(
    myEnc:GetBytes(xmlGridSettings),
    0,
    myEnc:GetByteCount(xmlGridSettings) ).

/* this also looks to be supported.
myStream = new MemoryStream( myEnc:GetBytes(xmlGridSettings)).
*/

gridDocuments:DisplayLayout:LoadFromXml(myStream, PropertyCategories.All);

hth,

Peter

Posted by Admin on 13-Apr-2009 15:35

Excellent, Peter.

Thank you!

Posted by Admin on 14-Apr-2009 11:07

Sorry if I'm being dense...

I'm attempting to take the longchar variable which now contains my encoded xml and write it to a database Clob field. I'm using the COPY-LOB statement as so:


COPY-LOB xmlString to myTable.myClobField.

This throws the following error:

Could not update large object segment during copy. (11322)

I haven't found much information about this error. I did verify that the xmlString variable contains a valid XML file by using COPY-LOB to write to a text file. I did have to use NO-CONVERT when I did this however.

Any ideas?

Thanks,

Jim

Posted by Peter Judge on 14-Apr-2009 11:44

 

I'm attempting to take the longchar variable which now contains my encoded xml and write it to a database Clob field. I'm using the COPY-LOB statement as so:


COPY-LOB xmlString to myTable.myClobField.

This throws the following error:

Could not update large object segment during copy. (11322)

I haven't found much information about this error. I did verify that the xmlString variable contains a valid XML file by using COPY-LOB to write to a text file. I did have to use NO-CONVERT when I did this however.

Any ideas?

My first (and only, unfortunately) thought is that this has to do with codepage conversions (maybe try COLUMN-CODEPAGE UTF-8 on the TT def?). I'd contact TS and see if they can help you further.

-- peter

Posted by Admin on 14-Apr-2009 12:35

Unfortunately I haven't had to deal with much code page stuff. Maybe for the time being, I'll write to a file and see if I can get that to work.

I still think writing through a memory stream should be possible.

Thanks.

Jim

This thread is closed