Kinesis SoftwareKineticFusion

[Show Table of Contents]

10 RVML Reference

[Hide Table of Contents]



10.4 Constructing Dynamic RVML Content

KineticFusion supports the ability to specify dynamic data from both internal and external data sources and use this information within RVML documents. RVML documents can be dynamically configured with external data sources defining values that can be used as repository locations, styles, languages, symbol definitions or scripts.

10.4.1 Introduction to the Data Model

The data model is implicitly available for all RVML documents and can be accessed within attribute values or externally from template definitions. Additional data sources can be specified for each individual RVML document and these automatically augment the data model for the document.

For example, if we have defined width and height in the global data source, we can reference these values dynamically from within RVML using:

<Movie width="${width}" height="${height}"...>

Data in the data model is aggregated from five difference sources:

The data in the global source is added to the data model at the root level - that is, it is not does not need to be qualified with any other variable e.g. width, height. Data from an RVML data source is always qualified by a data source name e.g. rowset.numRows, rowSet.columnName[1]

10.4.2 External DataSource Types

KineticFusion currently supports three different source types that can provide external data for a data model.

10.4.2.1 Java Property files

Java property files can be used as external data sources for an RVML document. To define an external property file, the RVML PropertyDataSource element is used. The DTD fragment for this element is:

<!ELEMENT PropertyDataSource EMPTY >
<!ATTLIST PropertyDataSource
        name     CDATA #REQUIRED
        location CDATA #REQUIRED
        type     (file | url) #IMPLIED
>

The PropertyDataSource defines an external property file to be added to the data model under the specified name. The location specifies the location of the file to load. If relative, then the file is assumed to be relative to the location of the processed RVML document. Alternatively, the properties can be loaded from a URL in which case the location must contain the full canonical name of the URL and the type attribute must be set to 'url'. For example, this loads all the Java properties from the file data.properties into the data model under the name 'myData':

<PropertyDataSource name="myData" location="c:\data\data.properties" type="file"/>

If the file contained a property defined as:

Width=100

Then it can be used inside RVML as:

${myData.Width}

Once defined, all property data is loaded from the specified Java properties file into the data model.

The contents of the property file are a list of properties and values: the property name is used to specify the full path of the value inside the data model.

For example, given the following property file contents:

Width=400
Height=200
Shape.x=20
Shape.y=40

Then the code to access the values inside an attribute expression is:

${Width}
${Height}
${Shape.x}
${Shape.y}

It is illegal to specify both a value for a property and also to specify child values under that element. In this situation, the value for the element is discarded. E.g. the following is illegal and the value specified for Shape is discarded:

Shape=25
Shape.x=20

When the property location is modified the properties file will be re-read and all data within the data model is refreshed automatically.

10.4.2.1.1 Specifying non-string types

All values stored in the data model have a default type of String. To indicate that specified values are non-string values the property names can be directly suffixed with the actual type of the value.

Currently support types are:

Type

Property Suffix

Description

String

/s (default)

Standard string value type

Number

/n

Full floating point number formatted according to locale rules

Boolean

/b

Boolean true/false

Date

/d

Date value formatted according to default locale

DateTime

/dt

Date/Time value formatted according to default locale

Time

/t

Time value formatted according to default locale

For example, in order to evaluate arithmetic expressions using properties then, using the default representation, they would be defined and used as:

Width=400
Height=200

Used as:

<Movie width="${Width?number/2}...>

To automatically variables with their correct type, they would be be suffixed by a '/n' and defined and used as:

Width/n=400
Height/n=200

Used as:

<Movie width="${Width/2}...>

10.4.2.2 XML Documents

XML documents can also be used as data sources. The entire hierarchy of the XML document is represented within the data model with the exception of Programming Instructions and Comments. Validation is optional, but can be carried out to instantiate entities with the XML data source before loading. To define an external XML file, the RVML XMLDataSource element is used. The DTD fragment for this element is:

<!ELEMENT XMLDataSource EMPTY >
<!ATTLIST XMLDataSource
        name              CDATA #REQUIRED
        location          CDATA #REQUIRED
        type              ( file | url ) #IMPLIED
        resolveNamespaces ( true | false ) #IMPLIED
        validate          ( true | false ) #IMPLIED
>

The XMLDataSource defines an external XML file to be added to the data model under the specified name. The location specifies the location of the document to load. If relative, then the file is assumed to be relative to the location of the processed RVML document. Alternatively, the XML can be loaded from a URL in which case the location must contain the full canonical name of the URL and the type attribute must be set to 'url'.

If resolveNamespaces is set to true (default value is false) then the XML nodes in the data model must also be referenced by their qualified node names. This needs to be defined in FreeMarker using the <#ftl ns_prefixes={ Put mapping here}>. There is generally no need to resolve namespaces since all elements should be uniquely identifiable.

If validate is set to true (default value is false) then KineticFusion will attempt to validate the input XML document before adding it to the data model. If validation fails, then processing of the entire document fails. It is the repsonsibilty of the XML document author to ensure sufficient information is available to validate the document.

The data in the document is added to the data model under the specified top-level name by attaching all the child elements of the root node to the specified element. This means that the root element of the document is not addressable. For example, given the following document:

<book title="Test Book">
  <chapter title="Ch1">
    <para>p1.1</para>
    <para>p1.2</para>
    <para>p1.3</para>
  </chapter>
</book>

And the following RVML data source declaration:

<XMLDataSource name="ledger" location="book.xml">

Then the chapter element can be referenced from within an expression using:

${ledger.chapter.@title}

And not:

${ledger.book.chapter.@title} <-- This is wrong

XML data sources in the data model should be accessed using the specialised syntax for XML documents. This syntax is very similar to the syntax used for XPath expressions and, indeed, full XPath syntax is supported.

The XML document above can be referenced within a data model as follows (assumes the XML document is loaded under the 'books' top-level variable):

${books.book.@title}

resolves to "Test Book"

${books.chapter[0].@title}

resolves to "Ch1" - note that the '[0]' selector is unnecessary here since there is only a single chapter

${books.chapter[0].para[2]}

resolves to "p1.3" - without the '[2]' selector the text of the first 'para' element would be printed.

For more information on accessing XML data from within attributes or Template elements refer to the FreeMarker reference guide.

10.4.2.2.1 Using XPath

KineticFusion is installed with the Jaxen library. This provides full support for XPath expressions that can used in both the Attribute Expression Language and Template support of KineticFusion.

For more information on using XPath expressions from within attributes or Template elements refer to the FreeMarker reference guide.

10.4.2.3 User-defined JavaBeans

KineticFusion supports arbitrary Java objects as data sources providing they comply with the JavaBeans naming conventions. To instantiate a user-defined JavaBean, the RVML JavaDataSource element is used. The DTD fragment for this element is:

<!ELEMENT JavaDataSource (Argument*) >
<!ELEMENT Argument (#PCDATA)>
<!ATTLIST JavaDataSource
        name       CDATA #REQUIRED
        className  CDATA #REQUIRED
>

This defines a single Java class that is to be instantiated, initialized and added to the data model under the specified name. The class must be able to be loaded by the KineticFusion class loader. If arguments are required, then multiple child Argument elements can be specified.

All bean properties and methods of the object are automatically made available in the data model.

10.4.2.3.1 Required constructor

All JavaBean data source objects must have an empty constructor. The JavaBean is immediately instantiated once defined within an RVML document. If it is necessary to initialize the JavaBean, then initialization parameters can be passed as outlined in the next section.

10.4.2.3.2 Passing initialization parameters

They can optionally implement the com.kinesis.interfaces.datasource.JavaDataSourceType interface that allows a new instance of the object to be initialized with arguments specified in RVML. This interface is shown below and specifies a single method:

/********************************************************************
 * Copyright (c) 2005 Kinesis Software Ltd, All rights reserved
 ********************************************************************/
package com.kinesis.interfaces.datasource;
 

/**
 * Interface for all classes capable of being used as data sources in RVML. The 
 * classes must have a default empty constructor.
 */
public interface JavaDataSourceType {

    /**
    * Initialise the data data source with the optional string arguments defined
    * within RVML. If no arguments are defined the method is called with an empty
    * array.
    *
    * @param arguments taken from additional argument elements specified in RVML
    */
    public void initialize( String[] arguments);
}

The contents of the sequence of specified Argument elements are copied into an array and passed to the initialize() method of the new Java object.

10.4.2.3.3 Accessing properties

Once a JavaBean is defined then all public properties of the JavaBean are directly available within the model. For example, if a JavaBean has the following accessor method:

public int getWidth();

Then this can be accessed as:

${myJavaBean.width}

10.4.2.3.4 Calling methods

Once a JavaBean is defined then all methods of the JavaBean are directly available within the model. For example, if a JavaBean has the following method:

public int scaleWidth(int scaleFactor);

Then this can be accessed as:

${myJavaBean.scaleWidth(2)}

10.4.3 The Global Data Source

In addition to the external data source that can be specified for an individual RVML document, KineticFusion also supports a single global data source. The global data source defines a single data source whose data is added to the data model for every RVML document processed. Currently, only a Java Properties file can be used as a global data source. The location of the file can be specified using either an absolute file or URL using the kinesis.datasources.globalLocation configuration property. An additional property kinesis.datasources.globalType must be defined as 'url' if the specified location is a URL instead of a file.

All properties from the global data source are added to the very top level of a data model.

10.4.3.1 Defining Global Variables

Each RVML document can specify defaults for global variables and override defined global values. The DTD fragment for this element is:

<!ELEMENT GlobalDataSource (Variable*) >
<!ELEMENT Variable EMPTY >
<!ATTLIST Variable
        name      CDATA #REQUIRED
        value     CDATA #REQUIRED
        override  (true | false) #IMPLIED
>

The GlobalDataSource permits the definition of default values that may not always be available in the Global Data Source model.

It is also possible to override the existing value specified in the global model by setting the override attribute to 'true' (default is 'false'). This will always override any value stored in the Global Data Source or specified on the command line.

10.4.3.2 Overriding on the Command Line

t is also possible to create new model variables and override defined global variables values for a particular run of KineticFusion by specifying properties on the command line. These property names must be prefixed by the 'global' source name followed by a period '.'.

For example, the following example defines the numeric width variable as 200 for all documents processed in the current session:

java -Dglobal.Width/n=200 -jar KFDeveloper.jar

10.4.4 Predefined Model Variables

KineticFusion provides a number of predefined model variables that are available to all RVML documents.

10.4.4.1 movie Variable

It is possible to access the current movie model as its being built from the data model. KineticFusion adds a top-level variable, 'movie', to the data model. The 'movie' variable can be interrogated to extract global movie properties, symbols properties, and timeline properties. Currently the following properties are available:

Data Model Variable

Type

Description

movie.width

Number

The specified width of the movie, in pixels

movie.height

Number

The specified height of the movie, in pixels

movie.rate

Number

The defined frame rate of the movie

movie.version

Number

The defined SWF output version

movie.metadata

XML

The XML fragment defined as meta data for the movie

movie.title

String

The defined title of the movie

movie.symbols

Symbol Map

A map of symbols for te movie. Defined symbols must be referenced as properties of the returned object e.g. movie.symbols.Button.

Currently, all symbols make the following information available:

  • x
  • y
  • width
  • height
  • bottomx
  • bottomy

movie.timeline

Frame array

Returns an array of frames. The total number of currently defined frames can be found from movie.timeline.size().

We welcome any requests to increase the scope of information available in the movie model.

10.4.4.2 Math Variable

A Math top-level element is made available to provide necessary mathematical functions. Currently the following functions are provided:

Data Model Variable

Usage

Math.cos

${Math.cos( angle )}

Math.sin

${Math.sin( angle )}

Math.tan

${Math.tan( angle )}

Math.acos

${Math.acos( value )}

Math.asin

${Math.asin(value)}

Math.atan

${Math.atan(value)}

Math.exp

${Math.exp(value)}

Math.log

${Math.log(value)}

Math.pow

${Math.pow(value, pow)}

Math.sqrt

${Math.sqrt(value)}

Math.round

${Math.round(value)}

10.4.4.3 store Variable

Traditionally, it has not been possible to write values into a data model for later use. The KineticFusion data model has been extended with a top-level 'store' element that contains a single method 'put ( name, value)' that associates a value with the specified name. The value can be retrieved using the name at any later stage e.g. ${store.put("important", 5)} associates the number 5 with Store.important

Now we can retrieve later using ${store.important}.

10.4.4.4 Using Attribute Expression Language Extensions

Attributes values in RVML can be created dynamically using a built-in attribute expression language. This permits the use of dynamic expression values within attribute values that are resolved automatically by KineticFusion before creating an SWF movie.

The attribute expression language used by KineticFusion uses the full FreeMarker template language engine and each attribute can be interpreted as a small, inline piece of template code.

An attribute value is interpreted as an expression if is contains the special evaluation syntax, '"${expression here}". Multiple attributes expressions can be used inside a single attribute value and text can freely occur around attribute expressions.

For example:

<Movie width="4${2 - 2}0"...>

that becomes:

<Movie width="400" ...>

FreeMarker supports a wide range of numeric and text-based operations on constants but the main purpose of the attribute template language is to evaluate expressions from external data. Every RVML document has an associated hierarchical data model that can be accessed directly with attribute expressions. Text references within attribute expressions are automatically assumed to be references to data model elements.

For example, if we have defined a numeric variable in the data model called width with value 400, we can write:

<Movie width="${width /2}"...>

that becomes:

<Movie width="200" ...>

Variables can be generally be thought of as either numeric variables, or text variables. Numeric operations are not applicable to text variables but variable values can be converted between types using many of the predefined mechanisms in FreeMarker e.g.

<Movie width="${textWidth?number / 2}"...>

Variables can also be used as containers for other variables providing encapsulation for different parts of the data model. Dot syntax is used to access the elements of a variable container, and there are no limits to the depths of nesting permitted. For example, to represent the dimensions of a shape object, the data model could be specified as:

<Shape bounds="bounds(${ shape.topX}, ${shape.topY}, ${shape.bottomX}, $shape.bottomY})"...>

In this example, the four shape bounding values are contained within the shape variable.

10.4.4.5 Using Template Extensions

KineticFusion also support full-blown FreeMarker templates for the creating of dynamic RVML and text block processing. The entire data model as described above is available for all templates. The content of a Template element is processed by the template processor and the output of the template processor is then inserted back into the RVML document and parsed as either text or XML. For more information on FreeMarker templates see the FreeMarker user documentation.

Template code is specified using the Template element. A Template element is permitted, by KineticFusion, anywhere within an RVML document, though the RVML DTD does not currently contain Template element references. The DTD fragment for the Template element is shown below:

<!ELEMENT Template (#PCDATA)>
<!ATTLIST Template
        src       CDATA #IMPLIED
        type      ( file | url ) #IMPLIED
        isXML     ( true | false ) #IMPLIED
        hasRoot   ( true | false ) #IMPLIED
        encoding  NMTOKEN #IMPLIED
        locale    NMTOKEN #IMPLIED
>

A Template element can be specified either inline or as an external resource. If external, the src attribute defines the relative location of the template file under the configured template root folder (set using the kinesis.templates.templateRoot configuration property) or a URL pointing to the template (if a URL is used, then the type attribute must be set to 'url').

If an inline template is used, then the src attribute is optional. If both inline template code and a src attribute is specified then the inline content is ignored.

The output of a template can be RVML (which can include recursive calls to the Template element) or text. When the isXML attribute is 'true' the output of the template is assumed to be XML and will be included in the RVML document at the location of the Template element. KineticFusion treats all XML templates as full XML documents and each is parsed separately. If is is necessary to create a sequence of RVML elements without a root element then the hasRoot attribute should be set to 'false' and KineticFusion will automatically wrap the XML with a 'root' root element - this will be automatically discarded on processing.

It is also possible to specify the encoding and locale of the template if it is read from an external location. If no encoding attribute is specified on the element, the encoding is taken from the global configuration value kinesis.templates.defaultEncoding. If no locale element is specified on the element, the locale is taken from the global configuration value kinesis.templates.defaultLocale.

10.4.5 Dynamic RVML Examples

KineticFusion can supply dynamic data to an RVML document from a number of data sources. Here we will look at using both the Attribute Expression Language and inline templates for accessing external data.

10.4.5.1 Simple Example Using Command Line Parameters

Each RVML document has implicit access to a global data model. Data in the global model is loaded from a configured global model file and the data is available to all processed documents.

Command-line Java properties can be used to to define or override a variable in the global model.

java -Dglobal.width=400 com.kinesis.KineticFusion

This makes the global variable 'width' available to all RVML documents. Here is an example of using this variable in a RVML document by rescaling a shape depending on the width variable (note: this has a different effect from using the _scale property as it maintains the actual line widths of the shape):

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
lt;Movie version='7' width='${width}' height='200' rate='23' compressed='Yes' 
    backgroundColor="grey" xmlns='http://www.kineticfusion.org/RVML/1.0'>
   <Definitions>
       <Shape id="Rectangle">
           <LineStyles>
               <LineStyle index='1' width='0.2' color='black' />
           </LineStyles>
           <FillStyles>
               <ColorFill index='1' color='blue' />
           </FillStyles>
           <Edges>
               <SetStyle line='1' mainFill="1" />
               <Rect x='0.0' y='0.0' width='${width?number/2}' height='100.0' />
           </Edges>
       </Shape>
   </Definitions>
   <Timeline>
       <Frame>
           <Place name='Rectangle' depth='1' 
                   x='${width?number/4}'  
                   y="${(movie.height - movie.symbols.Rectangle.height)/2}"/>
       </Frame>
   </Timeline>
lt;/Movie>

Here is the resulting SWF: Open in New Window

By default, all variables are text values so to use them in numeric expressions they must be explicitly converted to numbers e.g. width?number. Alternatively, model variables can be explicitly specified as numbers by adding an appropriate type suffix to the property e.g. for numeric properties, add a '/n' suffix:

java -Dglobal.width/n=400 com.kinesis.KineticFusion

Now the width variable can be used in an arithmetic expression without conversion e.g.

<Place name='Rectangle' depth='1' x='${width/4}'/>

Also, in this example, you can see how to access the bounds of local movie symbols using the predefined 'movie' variable.

10.4.5.2 Simple Example Using XML Data Source

The following example illustrates how to use an external XML document to populate the values in a ComboBox component at initialization time. The following sample document is used:

<People>
    <person>
        <surname>Blogs</surname>
        <fullname>Joe Blogs</fullname>
        <job>Coffee maker</job>
    </person>
    <person>
        <surname>Murphy</surname>
        <fullname>Michael Murphy</fullname>
        <job>Sandwich maker</job>
    </person>
    <person>
        <surname>Weston</surname>
        <fullname>Charlie Weston</fullname>
        <job>Hacker</job>
    </person>
</People>
  

In the following example we will extract all person elements from this document except for those whose job is 'Hacker'. We will then use this information to populate a single ComboBox component:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<Movie version='7' width='${width}' height='200' rate='23' compressed='Yes' 
    backgroundColor="grey" xmlns='http://www.kineticfusion.org/RVML/1.0'>
    <DataSources>
       <XMLDataSource name="people" location="People.xml"/>
   </DataSources>
   <Components>
       <Component id="ComboBox"/>
       <!-- not strictly necessary as already included in ComboBox -->
       <Component id="Label"/> 
   </Components>
    <Timeline>
        <Frame>
            <Place name='ComboBox' depth='3' instanceName='myCombo' x='50.0' y='50.0'>
                <MovieClipActions>
onClipEvent(load)
{
    // This template populates combo box with non-hacker people
    <Template isXML="false"><![CDATA[
        <#list people["*[not(job='Hacker')]"] as person>
            addItem( {label:"${person.surname}", data:"${person.fullname}"});
        </#list>
        ]]>
    </Template>
    // Update the label on selection
    this.addEventListener("change", function ( event)
        {
            _level0.myLabel.text = this.selectedItem.data;
        });
}
                </MovieClipActions>
            </Place>
            <Place name='Label' depth='4' instanceName='myLabel' x='200.0' y='50.0'>
                <MovieClipActions>on(construct){text = "";}</MovieClipActions>        
            </Place>        
    </Frame>
    </Timeline>
</Movie>

You can see the resulting combo-box SWF here (about 57K).