More Related Content
Similar to MediascriptLanguageOverview (20)
MediascriptLanguageOverview
- 2. try it now: /mediaframe/run?app=projects/Examples&mode=ColorBoxes
<style>
<white_text color="white" fontsize="24px" padding="4px" />
<red_cell background="red" />
<green_cell background="green" />
<blue_cell background="blue" />
</style>
<row>
<column style="red_cell">
<display text="red" style="white_text" />
</column>
<column style="green_cell">
<display text="green" style="white_text" />
</column>
<column style="blue_cell">
<display text="blue" style="white_text" />
</column>
</row>
This above script's output looks like this:
This example is not intended to exhibit a preferred means of displaying colored boxes with text. The intention is
merely to introduce the row and column paradigm in Mediascript, which is central to how HTML output is formatted
in the application.
Unlike standard HTML, there is no "table" construct in Mediascript because the existence of a table is implied if you
ever use the <row> and <column> keywords. Since all of the standard rules of CSS apply to styles used in
Mediascript, it is necessary to keep in mind the restrictions for HTML constructs <tr> and <td>, such as the inability
to set the width on a row. More details about the behavior of rows and columns can be found in the MediaScript
Keyword Reference.
Parameterized Data Access
Data values in Mediascript are accessed by a particularly unambiguous declaration syntax, which will be called the
$CAPS$ notation. When Mediascript encounters a pattern of uppercase text between '$' symbols, an attempt will be
made to replace that series of characters with a named value that exists on the stack frame.
Basic Format
The basic format for stack parameters (or "params" for short) uses the keyword <param> and always contains the
attribute name. Additionally, based on the type of data access required, attributes relating to the param's value are
also declared. The most basic form looks like this:
<param name="color_red" value="#AA0000" />
In order to access a param value, its name is converted to uppercase and bracketed with '$'. So, to draw a red cell
as in the previous example, the Mediascript kernel will substitute #AA0000 upon encountering the string
$COLOR_RED$ :
<style>
<white_text
color="white"
fontsize="24px"
padding="4px"
/>
- 4. <param name="fullpath" value="$$SELECTED_FILE$$" />
<param name="table_name" value="$SQL:TABLES_IN_$DB_NAME$$" />
<display text="$SQL:$FOREACH_VALUE$$" style="data_text" />$
When the Mediascript kernel encounters a nested parametric evaluation, the innermost quantity will always be
evaluated first. After all internal params are evaluated, the Mediascript kernel begins again with new values
substituted which are supposedly intended to progress the evaluation even further. This process continues until all
evaluations are complete.
The most frequently encountered form of parameter nesting occurs when accessing a single parameter with multiple
levels of indirection. For example, as in the first instance above, a selected file can be identified by a uniquely
hashed identifier, which in turn can refer to the full path name of the selection itself. This form of indirection is can
referred to as $$DUBCAPS$$ notation (if necessary).
Parameter nesting is supported to 20 levels at most, but for practical purposes there is rarely a need to nest params
beyond three, and with the proliferation of multiple consecutive ‘$’ characters within a single expression, script
readability could be compromised for those who must maintain the script logic over time.
Custom <param> Operations
Many applications within the Framework define and make use of customized PHP scripts that obtain results from
available Application Program Interfaces (APIs). Any Mediascript param can reference these custom PHP functions
by using the op attribute. For example, the text microservice provides a "strlen" operation that can be used within
any param declaration as follows:
<param name="string_length" op="strlen" target="$TEST_STR$" />
<display text="string '$TEST_STR$' is $STRING_LENGTH$ chars long." />
Complete documentation on the set of required parameters for each operation is a reasonable expectation of any
application’s consumer base, but in the worst case the script implementation itself may be examined to determine
the expected inputs.
Pattern Assembly
Using the Mediascript <pattern> construction, <param> values can be expressed as compound entities with
various inputs and mixed styles that require common formatting across a document. For example, a bullet list might
have a single leading phrase that is styled in bold followed by text with a normal font weight, all of which is indented.
Using patterns, such a format can be designed once so that each <param> can access it by name.
<pattern name="keyword_label" keyword_name="(keyword_name not set)">
<value>
<![CDATA[[code][lt][color:#000088]$KEYWORD_NAME$[/color][gt][/code]]]>
</value>
</pattern>
...
<param name="keyword_style" pattern="keyword_label" keyword_name="style" />
<param name="keyword_param" pattern="keyword_label" keyword_name="param" />
<param name="keyword_macro" pattern="keyword_label" keyword_name="macro" />
<param name="keyword_pattern" pattern="keyword_label" keyword_name="pattern" />
The above example shows how pattern assembly works with a number of params that are used often on these
pages. The purpose of the "keyword_"” declarations is to automate a complicated formatting task involving an
embedded color variation and a font change. This is done by encapsulating the pattern logic in one location, which is
the pattern declaration named "keyword_label".
Iteration Over Data Sets
Iteration in Mediascript is supported using structured datasets that are defined within the XML script itself. In
addition, sql queries, file system elements, PHP arrays, and commaseparated lists can also be processed in a
stepwise manner.
- 5. try it now: /mediaframe/run?app=projects/Examples&mode=ForeachList
Stepwise Iteration With <foreach>
The most basic use of iteration would be the use of the <foreach> keyword, as in the following script:
<foreach list="values" elements="red,green,blue">
<column style="$FOREACH_VALUE$_cell">
<display text="$FOREACH_VALUE$" style="white_text" />
</column>
</foreach>
Two substitutions occur in the loop listed above, first for for the style attribute of the <column> block and then in
the text attribute of the <display> element. For every member of the list "red,green,blue" the Mediascript
kernel makes the appropriate substitutions at the time the script is executed, and provides access to each value in
turn as $FOREACH_VALUE$.
Clearly, the iterative version of this simple script is less verbose. However, the output of the <foreach> version is
slightly different than the previous example because three separate 1x1 tables are being displayed instead of one
3x1 table. This could be corrected by adding float="left" on the column styles, but for the purpose of
demonstration this is the actual result of running the script:
Iteration on Param Sets
Mediascript also supports iteration over sets of params. Along with the "color_boxes" <param> described there,
more control can be exercised over the details of each box in turn:
<style>
<white_text color="white" fontsize="24px" />
<red_cell background="$COLOR_RED$" />
<green_cell background="$COLOR_GREEN$" />
<blue_cell background="$COLOR_BLUE$" />
</style>
<param name="color_red" value="#AA0000" />
<param name="color_green" value="#00AA00" />
<param name="color_blue" value="#0000AA" />
<param name="color_boxes">
<color_box label="Red" color_style="red_cell" box_width="200px" />
<color_box label="Green" color_style="green_cell" box_width="300px" />
<color_box label="Blue" color_style="blue_cell" box_width="150px" />
</param>
<foreach params="$COLOR_BOXES$">
<column style="$FOREACH:COLOR_STYLE$" minwidth="$FOREACH:BOX_WIDTH$">
<display text="$FOREACH:LABEL$" style="white_text" />
</column>
</foreach>
This example shows how a Mediascript <foreach> keyword can use nested params to implement a variation on the
color boxes example. When iterating over a nested param set, the list of params is specified in its $CAPS$ notation,
(in this case as $COLOR_BOXES$) because the value of the param named "color_boxes" is being iterated over,
and the Mediascript kernel requires evaluation of the param in order to access the list as intended.
NOTE: both <param> names and the attributes defined within param sets are never case sensitive, so that conversion
- 6. try it now: /mediaframe/run?app=projects/Examples&mode=StackParams
of attribute names to uppercase can occur without ambiguity. As a best practice, <param> names and attributes should
always be expressed in lower case form. Attribute values on the other hand, such as the values "Red" "Green" and
"Blue" above are completely case sensitive and compliant with the code page specified in each script's XML header.
This version of the script is much more configurable than the previous since any changes to the definition of the
boxes will take place in the abstract data structure rather than the script where that data is used. Running this
version produces the following output:
The <not_found> Declaration
Should iteration fail for any reason, Mediascript provides a way to declare a contingency:
<sql command="select"
table="mf_states"
limit="25"
orderby="timestamp DESC">
<row style="no_wrap">
// operate on query results, if any
</row>
<not_found>
<display text="no states found" />
</not_found>
</sql>
The above example demonstrates a typical use of the <not_found> block, which is used widely throughout the
Mediaframe script base to handle extraordinary conditions, both expected and unusual. In this case it is used to
handle the situation when no records are found, but the construction is also supported in <foreach> and <select>
pattern matching.
Pattern Matching
Mediascript supports a set of selection mechanisms that can be used to conditionally branch on a state variable or
to target a data element in an array of possible matches. Aside from MySQL select queries, the keywords used to
conditionally act using pattern matches are <switch> and <select>.
Conditional Branching With <switch>
The most basic form of pattern matching is available by use of the <switch> keyword, which operates very much
like its counterpart in PHP, JavaScript and C/C++. Unlike those traditional languages however, Mediascript does not
support the basic "if/else" mechanism, which can be handled in all cases by the <switch> keyword.
<param name="table_exists"
op="table_exists"
table_name="mf_users" />
<switch value="$TABLE_EXISTS$">
<case value="1">
// action to take if the table exists
</case>
<default>
// action to take otherwise
</default>
- 7. </switch>
Within each <switch> block there should be at least one <case> or <default> block as indicated by the script
logic. In the above example, the op named "table_exists" is evaluated to obtain information about the existence
of a MySQL table, and if the return value is "1" then the first script block is run. When no match is made, indicating
that the table in question is not found, the script within the <default> block will be executed instead.
An alternative to the example above would be to add a second <case> block that matched the value "0" instead of
declaring <default>. However, that implementation ignores the possibility that the param op named
"table_exists" returns the value "1" which would indicate a serious MySQL error, such as a connection loss.
A variant on the <switch> declaration shown above references a param by its name instead of its $CAPS$ value:
<param name="table_exists"
op="table_exists"
table_name="mf_users" />
<switch param="table_exists">
// cases and default blocks as before ...
</switch>
In this example the param name is simply stated instead of being referenced by the evaluation $TABLE_EXISTS$,
but the outcome will be the same as between the two forms. The advantage to this approach is that the name of the
param itself can be expressed as a state variable in $CAPS$ notation, providing an extra layer of indirection if
required.
Form Data Pattern Matching
Two other variations of the <switch> statement are supported, to compare against HTTP request and post data:
<switch post="login_name">
// cases and default blocks as before ...
</switch>
<switch request="user_id">
// cases and default blocks as before ...
</switch>
These two forms will perform conditional branching based on the values found in the PHP variables $_GET and
$_POST. The previous example can be expressed in "value" form as well, since all GET and PUT/POST data is pushed
onto the initial stack frame by the Mediascript kernel, before any script statements are run:
<switch value="$LOGIN_NAME$">
// cases and default blocks as before ...
</switch>
<switch value="$USER_ID$">
// cases and default blocks as before ...
</switch>
Direct Selection Within <param> Sets
A classic use of the <select> construct is found in the application routing sequence, which is a conventionover
configuration interaction between an app's declaration file and a simple script found in the file run.xml:
// The application provides these linkages
<param name="app_routings">
<routing command="tree" imported_file="$DATA_DIR$/datatree.xml" />
<routing command="list" imported_file="$DATA_DIR$/datalist.xml" />
</param>
// The routing sequencer selects the routing based on $COMMAND$
<select
- 8. Three separate params are defined, and <display> is called three
times, with each of the param values.
params="app_routings"
key="routing"
attribute="command"
value="$COMMAND$">
// load and run the script found in $SELECT:IMPORTED_FILE$
</select>
This example shows a parameterized list with two entries, each declaring a file to be imported for different values of
$COMMAND$. The <select> keyword is then used to specify which of those "app_routings" will be providing the
file path of the intended routing.
Direct Selection On PHP Arrays
Using the <select> keyword on a PHP array requires the attribute named key to make the match:
<param name="cookies" eval="$_SERVER['cookies']" />
<select array="$COOKIES$" key="$SELECTED_COOKIE$">
<display text="$SELECT_KEY$=" />
<display text="$SELECT_VALUE$" />
<not_found>
<display text="cookie named '$SELECTED_COOKIE$' not found!" />
</not_found>
</select>
This above script will display both the key and value after accessing the array of server cookies with the desired
name parameterized as $SELECTED_COOKIE$. In the event that the requested cookie isn’t found by name, the
developer is provided a failsafe mechanism in the <not_found> block.
Imports and Macros
The first operation performed by the Mediascript kernel when fielding an HTTP request is to invoke the <import>
keyword on a bootstrap script. As its name implies, <import> causes one or more script files to be loaded into
memory, then parsed and compiled into a binary format that is ready for execution. Launching that script means
invoking the first operable keyword (if any are declared) and proceeding stepwise through all remaining statements
in the file to its end.
When modularity is required in script logic, <macro> declarations can be created and launched with use of the
<invoke> keyword. Very often all of the logic in a script file is encapsulated in one or more <macro> blocks which
then become specific shared interfaces that can be invoked by the outside caller.
Macro Invocation
Macro scripts are executed by using the <invoke> keyword, which specifies the macro to be invoked with the
attribute name. Referring back to the original "Hello Mediascript" example, the two approaches are demonstrated
here:
<param name="user_name_1" value="Mediascript" />
<param name="user_name_2" value="welcome guest" />
<param name="user_name_3" value="John Q. User" />
<display text="Hello, $USER_NAME_1$!" />
<display text="Hello, $USER_NAME_2$!" />
<display text="Hello, $USER_NAME_3$!" />
<macro name="say_hello" user_name="do I know you?">
<display text="Hello, $USER_NAME$!" />
</macro>
- 9. The keyword <display> occurs just once within the macro, and the
macro is invoked three times, each with a different name param. The
4th time the macro is invoked, user_name is not specified and the default
value is used in its place.
try it now: app=projects/Examples&mode=SayHello
<invoke name="say_hello" user_name="Mediascript" />
<invoke name="say_hello" user_name="welcome guest" />
<invoke name="say_hello" user_name="John Q. User" />
<invoke name="say_hello" />
The abstraction and fault tolerance features of macros make them the preferred means of implementing complex
Mediascript logic. In fact, the routing infrastructure used by the Mediaframe Application Framework routinely uses a
"convention over configuration" methodology when importing application files and calling specific macros within
them.
Here’s the result of running the "SayHello" example script, based on the macro design above:
Configuration Imports
Configuration settings required by certain scripts can be directly obtained by importing files that provide nothing
more than configuration data. One example of this design is found in a file named file_types.xml which lists all known
extensions and the MIME types associated with them. For example, the GIF file type is defined like this:
// GIF
<file_type
file_type_ext="gif"
file_type_description="Graphics Interchange Format"
file_type_small_icon="$ICONS_DIR$/32px/camera_32.png"
file_type_medium_icon="$ICONS_DIR$/48px/camera_48.png"
file_type_large_icon="$ICONS_DIR$/64px/camera_64.png"
file_type_render_app="media"
file_type_render_mode="image"
/>
Configuration importing works by first importing the configuration file, and then adding script within the import block
to process elements of the configuration. The following example outlines the technique in its basic form:
<import file="$CONFIG_DIR$/file_types.xml">
<foreach params="$FILE_TYPES$">
<display image="$FOREACH:FILE_TYPE_SMALL_ICON$" />
<display text="$FOREACH:FILE_TYPE_EXT$" />
<display text="$FOREACH:FILE_TYPE_DESCRIPTION$" />
</foreach>
</import>
This shows how a configuration file is imported and then iterated upon with the <foreach> keyword against the
param set named $FILE_TYPES$, which is known to exist within the imported file. This design has the advantage
that the display script is not aware of changes being made to the configuration data, and likewise the data can be
changed without any knowledge of how that data is rendered.
Keyword Invocation
In some cases it is necessary to mix keywords within a nesting level, which means more than one keyword type will
exist within one stack frame. This can be avoided in general by thoughtful design; for example taking care not to mix
<row> and <column> definitions within the same stack frame, which could produce undesirable results.