Working with Binary Data using SXML

Release 1.3 - ...

Binaries in Smartsite iXperion are wrapped in DataTables, because Byte Arrays have not SXML equivalen.

In most scenarios however, SXML abstracts usage of binary data.

For example, when uploading and storing files on the server filesystem, you don't see anything of the byte array handling:

Smartsite SXML CopyCode image Copy Code
<form class="CoolForm" action="{request.location()}" method="post" enctype="multipart/form-data">
 <fieldset>
 <legend>Your images</legend> 
 <input class="Required MultiFile TextBox" id="files" type="file" name="files"/> <br />
 <input type="submit" value="Save"/>
 </fieldset>
</form>
<se:if expression="request.method()=='POST'" error="Error saving files: {this.error.message()}">
 Uploaded: 
 <se:format inputdata="{request.files()}" >
  <se:rowformat>
   {request.savefile(this.field(key), '/temp/'+this.field(filename))}
   Saved {this.field(filename)}
   <br />
  </se:rowformat>
 </se:format>         
</se:if>

Personalization/Global Storage

In personalization (and in Global Storage), file data is stored in profile properties, but again, no byte array handling is needed, since the code needed to do so abstracts it for you:

ShowForm() (see the My Profile Smartlet in personalization)

Smartsite SXML CopyCode image Copy Code
<se:format inputdata="{request.files()}" >
   <se:rowformat match="first">
      {personalization.set('', Avatar, request.getfiledata(this.field(key)))}
   </se:rowformat>
</se:format> 

The only place in which the actual byte array is used, is in the Image() translation within the My Profile Smartlet, because it needs to be sent accross the wire in the response.

Here, you can use the datatable.getbytes() viper method to give you the actual byte array stored inside the wrapping datatable:

XML CopyCode image Copy Code
{buffer.set(img, personalization.get('', 'Avatar'))}
{response.setlastmodified(datatable.getvalue($img, 'UploadDateTime'))}
{page.setforcedresult(datatable.getbytes($img), 'image/jpeg')}

Physical files on the server

With physical files on disk, it's practically the same story again: no byte array handling, but DataTable wrapping:

Smartsite SXML CopyCode image Copy Code
{buffer.set(file, filesystem.readbinarydata('/assets/images/ng/Clouds.jpg'))}

You can see that by simply outputting the buffer:

Smartsite SXML CopyCode image Copy Code
{buffer.get(file)}

You should see something like this:

Smartsite SXML CopyCode image Copy Code
SXMLDataTable (Name=FileContents; Rows=1; Columns=FileName,ContentLength,Bytes)

Item Data and Database query results

Now, when binary data is retrieved from the database (for instance using sqlquery), or indirectly using SXML (itemdata.field() vipers, itemdata macro), you get actual byte arrays:

Smartsite SXML CopyCode image Copy Code
{itemdata.field(binarydata, IMG_CLOUDS)}

This will output:

Smartsite SXML CopyCode image Copy Code
(object: System.Byte[])

You can use the convert.tobinarytable() viper to do the wrapping:

Smartsite SXML CopyCode image Copy Code
{buffer.set(file, convert.tobinarydatatable(itemdata.field(binarydata, IMG_CLOUDS)))}
{filesystem.writebinarydata("/temp/clouds.jpg", $file)}

Now, you can use any of the methods mentioned above to work with the binary data.

Storing data in the database

When storing binary data in the database, you have to get the byte array from a wrapping datatable:

Smartsite SXML CopyCode image Copy Code
{buffer.set(bin, datatable.getbytes($img))}

Now, using sqlquery.executenonquery(), you can store the binary data:

Smartsite SXML CopyCode image Copy Code
{sql.executenonquery("insert into BinTable (BinData) VALUES(?)", $bin)}

... or you can use the sqlquery macro (Note: 1.4+ needed for binary sql params):

Smartsite SXML CopyCode image Copy Code
<se:sqlquery mode="nonquery">
 <se:parameters>
  <se:parameter name="sql">
   UPDATE Contents SET CtSpecificBinary1=? WHERE Nr=?
  </se:parameter>
  <se:parameter name="params">
   <se:collection>
    <se:member type="binary">{buffer.get(bin)}</se:member>
    <se:member type="integer">{itemdata.number()}</se:member>
   </se:collection>
  </se:parameter>
 </se:parameters>
</se:sqlquery>

Binary data stored in Xml (base64 encoded)

In this example, you can see how to retrieve binary data from Xml using the this.extractbinary() local viper method of the xmlprocessor macro.