Example Klip: Parsing Two Items
To show how process() updates the Klip, the following sample Klip uses Klip.trace() to output incoming items in the Debug Window as they are processed by the XML parser.
<klip>
<identity>
<title>
API: Engines.Data
</title>
</identity>
<locations>
<contentsource>
http://support.klipfolio.com/files/demo/demo.xml
</contentsource>
<icon>
http://www.klipfolio.com/static/klips/klipfolio/sample_icon.png
</icon>
<banner>
http://www.klipfolio.com/static/klips/klipfolio/sample_banner.png
</banner>
</locations>
<style>
alert {
type: item;
}
sender {
itemcol: 2;
noterow: 1;
label: 'Sender';
emphasis: strong;
}
summary {
itemcol: 3;
noterow: 4;
wrap: false;
notelabel: false;
}
date {
itemcol: 4;
noterow: 2;
label: 'Date';
}
category {
noterow: 3;
label: 'Category';
}
level {
itemcol: 1;
noterow: 5;
notelabel: false;
type: image;
}
url {
type: link;
}
id {
key: override;
}
</style>
<klipscript>
<![CDATA[
function onRefresh()
{
// Define XML Parser callbacks
Engines.Data.onCreate = myCreate;
Engines.Data.onUpdate = myUpdate;
_t( "onRefresh () -- " + Prefs.contentsource );
var result = Engines.Data.process ( Prefs.contentsource );
show_state();
return result;
}
//
// Support functions -----------------------------------------------
//
function myCreate( new_item )
{
_t( "myCreate() --- Got an XML Callback for new item" );
return modify (new_item);
}
function myUpdate( current_item, properties )
{
_t( "myUpdate() --- Got an XML Callback for updated item" );
return modify (properties);
}
function modify( pending )
{
// Place your code here to modify incoming/updating items
_t( " sender: " + pending.getData( "sender" ));
_t( " summary: " + pending.getData( "summary" ));
_t( " date: " + pending.getData( "date" ));
_t( " level: " + pending.getData( "level" ));
_t( " category: " + pending.getData( "category" ));
_t( " id: " + pending.getData( "id" ));
_t( " " );
return true;
}
//
// Useful Debug Code -----------------------------------------------
//
function show_state()
{
show_items ();
}
function show_items()
{
if (Items.length == 0)
{
trace ("There are no items in the Items[] array\r\n");
return;
}
for( i = 0; i < Items.length; i++ )
{
trace ("Items[" + i + "]: \r\n");
queryItem (Items[i]);
}
}
function queryItem( item )
{
trace( "-----------------\r\n" );
trace( " .text = \"" + item.text + "\" (string)\r\n" );
trace( " .url = \"" + item.url + "\" (string)\r\n" );
trace( " .note = \"" + item.note + "\" (string)\r\n" );
trace( " .iid = \"" + item.iid + "\" (string)\r\n" );
trace( " .extra = \"" + item.extra + "\" (string)\r\n" );
trace( " .hidden = " + item.hidden + " (boolean)\r\n" );
trace( " .visited = " + item.visited + " (boolean)\r\n" );
trace( " .canpurge = " + item.canpurge + " (boolean)\r\n" );
trace( " .alerting = " + item.alerting + " (boolean)\r\n" );
trace( " .creation = " + item.creation + " (double)\r\n" );
trace( " .pubdate = " + item.pubdate + " (double)\r\n" );
trace( " .lastmodified = " + item.lastmodified + " (double)\r\n" );
// Output the current value of each defined element in an item
trace( " .getData( \"sender\" ) = \"" + item.getData( "sender" ) + "\" (string)\r\n" );
trace( " .getData( \"summary\" ) = \"" + item.getData( "summary" ) + "\" (string)\r\n" );
trace( " .getData( \"date\" ) = \"" + item.getData( "date" ) + "\" (string)\r\n" );
trace( " .getData( \"url\" ) = \"" + item.getData( "url" ) + "\" (string)\r\n" );
trace( " .getData( \"level\" ) = \"" + item.getData( "level" ) + "\" (string)\r\n" );
trace( " .getData( \"category\" ) = \"" + item.getData( "category" ) + "\" (string)\r\n" );
trace( " .getData( \"id\" ) = \"" + item.getData( "id" ) + "\" (string)\r\n" );
trace( "\r\n" );
}
var gTrace = true;
function _t( s )
{
if ( gTrace ) {
trace( s + "\r\n" );
}
}
]]>
</klipscript>
</klip>
XML Callbacks
The process() function does all work of extracting items and creating an Item object from the data. Sometimes you need to modify the properties of the Item before they are added to the Items object.Klipfolio Dashboard provides hooks that you can define handler functions that calls your JavaScript function with the Item before it's added to the Klip. In addition to modifying any of the Item's properties, you can tell process() to discard the item by returning false from the callback.
The following figure shows the callbacks available.
Figure: XML callbacks from Engines.Data.process()
| Properties Summary | |
integer |
autosort
Specifies whether process() should automatically sort processed items according to pubdate value (if available) in source (default true). |
String |
format
Specifies the format of the input source as CSV or TSV. |
boolean |
ignoreencoding
Specifies that Klipfolio Dashboard's XML processor should ignore the encoding when processing data. |
integer |
itemdepth
Used within onCreate() and onUpdate() to determine the depth of the currently matching item as defined in the Klip's <style>. |
String |
stylesheet
Specifies the stylesheet for this Klip. |
| Function Summary | |
function
|
applyStyle( <String> URL_or_data, <String> stylesheet )
Parses the specified data according to a stylesheet without creating items and returns an array of items. |
String
|
getScratch( <String> xml_element )
Returns the latest data for xml_element, an XML element defined as type: scratch in the Klip's <style> block. |
String
|
onBeginProcess( <String> text )
Defines a JavaScript callback that process() will be called before the XML parser begins to process data using the specifications in <style>. |
boolean
|
onCreate( <Item> new_item )
Assigns a JavaScript function to call just before adding a new item to the Items array. |
boolean
|
onEndProcess( boolean | string )
Defines a JavaScript callback that process() will call just before it exits. |
boolean
|
onUpdate( <Item> existing_item, <String> properties )
Defines a JavaScript callback just before process() updates an existing Item object with incoming data. |
boolean
|
process( <String> URL_or_data | <Engines.HTTP.HTTPRequest> httpRequestObject | <Engines.HTTP.HTTPResponse> httpResponseObject [, <integer> index] )
Parses XML and adds the results to the Klip. |
| Properties Detail |
autosort
integer autosort
-
Specifies whether process() should automatically sort processed items according to pubdate value
(if available) in source (default true).
format
String format
-
Specifies the format of the input source as CSV or TSV.
Not available for Klipfolio Personal Dashboard.
Be sure to add <enterprise>true</enterprise> in your <setup> block in order to use this property
in Klipfolio Personal Dashboard.
Pass "csv" to this property and place it in the onRefresh method before the call to Engines.Data.process(); for CSV data.
Likewise, pass "tsv" to this property for TSV data.
For example,
Engines.Data.format = "csv";
ignoreencoding
boolean ignoreencoding
-
Specifies that Klipfolio Dashboard's XML processor should ignore the encoding when processing data. XXX
itemdepth
integer itemdepth
-
Used within onCreate() and onUpdate() to determine the depth of the currently matching item
as defined in the Klip's <style>. XXX
stylesheet
String stylesheet
-
Specifies the stylesheet for this Klip.
This property lets you dynamically change Klip's stylesheet. Typically, you use this when you want to show different message in the Klip on startup, such as a welcome message inviting the user to open the Klip's Customize window, then, after the user has set up the Klip with their preferences, restore the stylesheet to what is defined in <style>.
To restore the stylesheet, assign @import klip to stylesheet.
Engines.Data.stylesheet = "@import klip";
| Function Detail |
applyStyle
function applyStyle( <String> URL_or_data, <String> stylesheet )
- Parses the specified data according to a stylesheet without creating items and returns an array of items.
This function can be used instead of using onCreate() and onUpdate() methods that return false.
Example:
The following Klip specifies the content of <contentsource> as the data to parse and <datastyle> as the stylesheet to parse it with.
The returned array of items is output into the Debug Window.
<?xml version="1.0" encoding="UTF-8" ?>
<klip>
<identity>
<title>
API: Engines.Data.applyStyle
</title>
<version>
1.0
</version>
<description>
A very simple example using Engines.Data.applyStyle()
</description>
</identity>
<locations>
<defaultlink>
http://www.klipfolio.com/
</defaultlink>
<contentsource>
<![CDATA[
<item>
<apples>apple1</apples>
<bananas>banana1</bananas>
<oranges>orange1</oranges>
</item>
<item>
<apples>apple2</apples>
<bananas>banana2</bananas>
<oranges>orange2</oranges>
</item>
<item>
<apples>apple3</apples>
<bananas>banana3</bananas>
<oranges>orange3</oranges>
</item>
]]>
</contentsource>
<icon>
http://www.klipfolio.com/static/klips/klipfolio/sample_icon.png
</icon>
<banner>
http://www.klipfolio.com/static/klips/klipfolio/sample_banner.png
</banner>
<kliplocation>
http://www.serence.com/developer/api/klips/api_engines_data_applystyle.klip
</kliplocation>
</locations>
<content>
<datastyle>
item {
type: item;
definition: all;
}
apples {
itemcol: 1;
}
oranges {
itemcol: 2;
}
bananas {
itemcol: 3;
}
</datastyle>
</content>
<style>
display {
type: item;
}
description {
itemcol: 1;
}
</style>
<klipscript>
<![CDATA[
function onRefresh()
{
var dataArray = Engines.Data.applyStyle(Prefs.contentsource, Prefs.getContent("datastyle"));
// or,
// var dataArray = Engines.Data.applyStyle(Prefs.contentsource,
// "item{ type: item;} apples { itemcol: 1;} oranges { itemcol: 2; } bananas { itemcol: 3;}");
if(!dataArray)
{
// If the data processing fails for some reason, return false to dim the Klip
return false;
}
// dataArray is structured in the order that the items appear in the source,
// not in the order they appear in the stylesheet:
// [i][0] or [i].apples - apples
// [i][1] or [i].bananas - bananas
// [i][2] or [i].oranges - oranges
// See the <datastyle> section in <content> above.
var i;
for(i = 0; i < dataArray.length; i++) {
trace( "dataArray[" + i + "].apples = " + dataArray[i].apples + "\r\n" );
}
trace( "\r\n\r\n" );
for(i = 0; i < dataArray.length; i++) {
trace( "dataArray[" + i + "][1] = " + dataArray[i][1] + "\r\n" );
}
trace( "\r\n\r\n" );
for(i = 0; i < dataArray.length; i++) {
trace( "dataArray[" + i + "].oranges = " + dataArray[i].oranges + "\r\n" );
}
trace( "\r\n\r\n" );
var xml = "<xml><display><description>" +
"(See Debug Window for output)" +
"</description></display></xml>";
return Engines.Data.process( xml );
}
]]>
</klipscript>
</klip>

dataArray[0].apples = apple1 dataArray[1].apples = apple2 dataArray[2].apples = apple3 dataArray[0][1] = banana1 dataArray[1][1] = banana2 dataArray[2][1] = banana3 dataArray[0].oranges = orange1 dataArray[1].oranges = orange2 dataArray[2].oranges = orange3
applyStyle() returns items as it finds them in the source, not according to the order they appear in the stylesheet.
-
Parameters:
URL_or_data - location of the content source. May be data or a URL.
stylesheet - string containing the stylesheet with which to parse the content. You may use Prefs.getContent() to get the stylesheet or pass the stylesheet itself directly.
-
Returns:
-
an array that contains the items
getScratch
String getScratch( <String> xml_element )
- Returns the latest data for xml_element, an XML element defined as type: scratch in
the Klip's <style> block.
As Engines.Data.process() is processing the XML, it will keep a 'scratch' area of the raw XML of the last extracted data value for any XML tag defined as type: scratch. You can then use Engines.Data.getScratch() to retrieve the latest value.
Example:
The following Klip extracts the value of from the data (shown below).
<klip>
<identity>
<title>
API: Engines.Data.getScratch()
</title>
</identity>
<locations>
<contentsource>
http://www.serence.com/support/samples/scratch.xml
</contentsource>
<icon>
http://www.klipfolio.com/static/klips/klipfolio/sample_icon.png
</icon>
<banner>
http://www.klipfolio.com/static/klips/klipfolio/sample_banner.png
</banner>
</locations>
<style>
my_title {
type: scratch; /* scratch */
name: 'my_title';
}
my_icon {
type: scratch; /* scratch */
name: 'my_icon';
}
item {
type: item;
definition: 'book,author';
}
book {
itemcol: 1;
noterow: 1;
}
author {
itemcol: 2;
noterow: 2;
}
</style>
<klipscript>
<![CDATA[
function onRefresh() {
var result;
result = Engines.Data.process (Prefs.contentsource);
trace( "my_icon: "+Engines.Data.getScratch( "my_icon" )+"\r\n" );
trace( "my_title: "+Engines.Data.getScratch( "my_title" )+"\r\n" );
Items.icon = Engines.Data.getScratch( "my_icon" );
Prefs.title = Engines.Data.getScratch( "my_title" );
}
]]>
</klipscript>
</klip>
<?xml version='1.0' ?> <content> <my_title>Book Library</my_title> <my_icon>http://www.serence.com/serence_klips/pics/feedviewer_3/4-4.png</my_icon> <item> <book>A Tale of two Cities</book> <author>Charles Dickens</author> </item> <item> <book>Charlotte's Web</book> <author>E.B. White</author> </item> </content>
Notice that <my_title> and <my_icon> occur outside repeating block enclosed by <item> tags, but the call to Engines.Data.getScratch( "my_icon" ) can extract the last parsed value regardless. Engines.Data.process() will maintain make this value available until it parses a new <my_title> element.
Contrast these XML elements to those in the Klip's <style> that are not defined as scratch. These elements are cleared each time Engines.Data.getScratch() encounters the start of a new item block.
-
Parameters:
xml_element - XML element defined in <style> as <item>
onBeginProcess
String onBeginProcess( <String> text )
- Defines a JavaScript callback that process() will be called before the XML parser begins to process data
using the specifications in <style>.
Use this callback to modify the incoming XML before Klipfolio Dashboard's XML processor begins to parse it. No callback will occur if the data is empty.
-
Parameters:
text - of XML data
-
Returns:
-
Your function can return either a boolean true to indicate that XML processing should proceed, a boolean false to cause process() to exit, or a string containing the updated XML to process.
onCreate
boolean onCreate( <Item> new_item )
- Assigns a JavaScript function to call just before adding a new item to the Items array.
Return true to add the item Item; otherwise, return false to discard it.
Example:
The following Klip shows how using a definition list and onCreate() can dynamically add a new field to the Klip.
<?xml version='1.0' ?>
<klip>
<identity>
<title>
API: Engines.Data.onCreate
</title>
</identity>
<locations>
<contentsource>
http://support.klipfolio.com/files/demo/demo.xml
</contentsource>
<icon>
http://www.klipfolio.com/static/klips/klipfolio/sample_icon.png
</icon>
<banner>
http://www.klipfolio.com/static/klips/klipfolio/sample_banner.png
</banner>
</locations>
<setup>
<refresh>
1
</refresh>
</setup>
<style>
alert {
type: item;
definition: 'sender,summary,date,category,level,url,id,new_property';
}
sender {
itemcol: 2;
noterow: 1;
label: 'Sender';
emphasis: strong;
}
summary {
itemcol: 3;
noterow: 4;
wrap: false;
notelabel: false;
}
date {
itemcol: 4;
noterow: 2;
label: 'Date';
}
category {
noterow: 3;
label: 'Category';
}
level {
itemcol: 1;
noterow: 5;
notelabel: false;
type: image;
}
new_property {
noterow: 6;
label: 'New Property';
}
url {
type: link;
}
id {
key: override;
}
</style>
<klipscript>
<![CDATA[
function onRefresh() {
Engines.Data.onCreate = myCreate;
Engines.Data.onUpdate = myUpdate;
return Engines.Data.process (Prefs.contentsource);
}
function myCreate( new_item )
{
modify (new_item);
return true; // Create the item
}
function myUpdate( current_item, properties )
{
modify (properties);
return true; // Apply properties to current_item
}
function modify( pending )
{
switch (pending.getData ("category"))
{
case 'Category 1':
pending.setData ("new_property", "First");
break;
case 'Category 2':
pending.setData ("new_property", "Second");
break;
case 'Category 3':
pending.setData ("new_property", "Third");
break;
}
return true;
}
]]>
</klipscript>
</klip>
-
Parameters:
new_item - new item to be added to the Klip
onEndProcess
boolean onEndProcess( boolean | string )
- Defines a JavaScript callback that process() will call just before it exits.
This callback gives symmetry for onBeginProcess().
onUpdate
boolean onUpdate( <Item> existing_item, <String> properties )
- Defines a JavaScript callback just before process() updates an existing Item object with incoming data.
-
Parameters:
existing_item - new item to be added to the Klip.
properties - a properties object is a special 'holding' object for the incoming properties. You can use Item.getData() and Item.setData() on the object, but you cannot define any new properties.
process
boolean process( <String> URL_or_data | <Engines.HTTP.HTTPRequest> httpRequestObject | <Engines.HTTP.HTTPResponse> httpResponseObject [, <integer> index] )
- Parses XML and adds the results to the Klip.
- Make a HTTP (GET) request to <contentsource>.
- Checksfor a valid response (with data) from the web server.
- Processe data using specifications in <style> parameter.
- Display the results in the Klip’s window.
- Adds the Item to top of Items[] array if it does not already exist.
- Updates an existing Item in the Items[] array if already exists.
- Discards the item (no changes to Items[]) array if already exists in Items.Deleted.
- URL_or_data string containing a valid http:// address
- If provided a string containing a valid URL, such as 'http://www.serence.com/support/samples/sample.food', the Data engine will download the file at that URL and process the data.
- URL_or_data string containing a valid file:// address
- If provided a string containing a valid file:// URL,
such as 'file:///C:/temp/sample.xml' (and this c:\temp\sample.xml exists),
then Data engine will open the local file and process the data.
Note: Klipfolio Dashboard must either be in developer mode or the Klip must be digitally signed or encrypted by Klipfolio Inc. for the file:// protocol to work.
- URL_or_data string containing XML
- Another common operation is to fetch some data using Engines.HTTP.HTTPRequest, the modify the XML before passing it to process as a string.
- HTTPRequest object
- If provided an Engines.HTTP.HTTPRequest object as a target, the Data engine will automatically send the request
and process the response accordingly.
Note: Klipfolio Dashboard will only execute the Engines.HTTP.HTTPRequest.send() the request if called from within an Klip.onRefresh() handler.
- HTTPResponse object
- If provided an Engines.HTTP.HTTPResponse object as a parameter, the Data engine will process te contents of the Engines.HTTP.HTTPResponse.data property.
The most common use of Engines.Data is to call process() with URL to a remote content source. Many times in the source for a Klip, you'll see the line:
Engines.Data.process( Prefs.contentsource );
To process incoming data, Klipfolio Dashboard uses its built-in (and very fast) non-validating XML parsing engine. The parser iterates through the incoming data, looking for items (as defined in the Klip's <style>), and for each item does one of the following operations:
If your Klip omits a <style> definition, Klipfolio Dashboard will use its built-in style definition that can parse RSS (0.90, 0.91, 0.92, and 2.0), ATOM, or RDF data.
You don't have to pass process() function a URL. This function can take one of five possible parameters for the data source:
-
Parameters:
URL_or_data - a valid URL or file location (see above)
httpRequestObject - (see above)
httpResponseObject - (see above)
index - for starting point of insertion of new items. For example, a value of 0 will insert new items at the top of the Klip's Items array. [optional]
-
Returns:
-
true if the specified source was successfully processed.
|
Klipfolio Dashboard 5 API | ||||||||
| PREV OBJECT NEXT OBJECT | FRAMES NO FRAMES | ||||||||
| SUMMARY: PROPERTY | FUNCTION | DETAIL: PROPERTY | FUNCTION | ||||||||
© 2009 Klipfolio Inc. All Rights Reserved.

