Expression Language: Difference between revisions

From wiki.jriver.com
Jump to navigation Jump to search
No edit summary
Line 496: Line 496:
[[Category:Frequently Asked Questions]]
[[Category:Frequently Asked Questions]]
[[Category:Developer]]
[[Category:Developer]]
[[Category:Expression Language]]

Revision as of 05:59, 24 January 2016

Media Center provides a simple programming language that enhances and enriches its overall user interface and usability. This language, commonly called the expression language, is simple to learn, simple to use, and can greatly enhance your experience using Media Center.

Expressions are ubiquitous throughout Media Center, used in areas such as:

  • The categories in a view
  • File list expression columns
  • Theater View
  • Customized view headers, grouping and sort criteria
  • The library field manager (fields with data type Calculated data)
  • File and folder location definitions
  • Auto-import rules
  • Custom DLNA titles
  • The player's display
  • Captions and thumbnail text
  • The link manager (expressions help format link URLs)
  • Rename, Move, & Copy tool
  • Tag assignment
  • Complex search queries

An expression is a mixture of ordinary text, pre-defined functions, and a few reserved characters and constructs that have special meaning. An expression is evaluated by Media Center's expression engine and textual output is produced. This output is then used by Media Center to customize the user interface and affect its method of operation.

The Anatomy of an Expression

As mentioned above, an expression is a mixture of text and function calls (and some reserved stuff described shortly). The simplest expression would be some basic, literal text, such as A good movie. The expression engine evaluates this expression, finds nothing special, and then outputs the result: A good movie. Simple.

But simple text only has so much utility. The ability to transform or generate content is much more interesting and useful. And this is when functions are employed. Media Center provides many functions, which when called, produce some output. Most functions require some form of input, called arguments, and most functions generate output. By supplying a function with various arguments, the function will return some output value which is just more text. And this output text can be the used by other functions, and so on. Each function has a unique name, and calling upon a function to do some work requires little more that using its name anywhere in the expression.

A function call looks like this:

functionname(argument 1, argument 2, ...)

The syntax of the function call is the function's case-insensitive name, immediately followed by an opening parenthesis character, one or more comma-separated arguments, and a closing parenthesis character. Whitespace after the commas is optional, but helps readability and formatting. And each argument itself is also just an expression. And some arguments are optional. If an argument is optional, it can be omitted and its default value will be used. If the argument is omitted, a comma-separator will still be required if additional arguments follow. The following example uses the FixCase() function to change its input to Title Case:

fixcase(A good movie)

The result is A Good Movie.

A slightly more complex expression example consists of both text and a nested function call:

Wow! fixcase(replace(A good movie, good, great))

Inner functions are called before outer functions, so the Replace() function is call first:

replace(A good movie, good, great)

and its output is then supplied as the input to the FixCase() function. Replace() does its work substituting good with great, and returns A great movie. This output is then supplied as the argument to FixCase() which sees only the text A great movie (it knows nothing about how it was produced). So the function call:

fixcase(A great movie)

in turn outputs A Great Movie. Now that the functions have produced their output, the final output, including the literal Wow! leading text is

Wow! A Great Movie

Fields

The expression examples thus far have been limited to static literal text. Expressions have much more utility when they use data from other sources, such as a file's metadata. Media Center maintains this metadata in its defined fields. This data is accessed using the Field() function, and its first argument is the case-insensitive name of the field to be accessed. For example, the function call field(album) will return the current* file's value for the album field (* more will be said later about the current file). If the album field contained the value After Hours, the expression:

fixcase(field(album), 3)

would produce AFTER HOURS. First field(album) is evaluated, returning After Hours. The FixCase() function is supplied with this output as its first argument, and its second argument is 3, which happens to specify that it should perform upper-casing.

Because fields are so frequently used in expressions, an abbreviated form called square bracket notation exists for accessing their values. This makes it easier to both read and write expressions. Nonetheless, both forms are equivalent. The abbreviated form is simple: immediately surround the field's name with opening and closing square brackets, for example, [album]. The previous example is now written more simply as:

fixcase([album], 3)

Field Values

For the sake of simplicity and clarity, the section above glossed over an important detail regarding how Media Center outputs field values. Recall that Field() is the function used to return the value of a specified field. But Field() also has a second argument that indicates the format of the value that it returns. Because field values are used in a variety of situations, the Field() function can produce output suitably formatted for the requirements. There are two forms of output: one is a nice, friendly human-readable format suitable for use in views or other display locations; the other is a raw format which returns the representation stored internally by Media Center which is useful when uninterpreted values are necessary.

By default, Media Center always outputs the friendly format, so expressions sometimes need to take this into account and chose the format accordingly.

Not used earlier because it is optional, the second argument to the Field() function selects the mode of output: the value 0 selects the raw mode, and the default value of 1 selects the friendly mode. Here are two examples using the date field, the first one outputs the date value in raw format, the second in the friendly format:

field(date, 0)
field(date, 1)

Field Values: Empty, 0, and 1

The Media Center expression language does not strongly differentiate between the numeric value zero 0 and emptiness for numeric field types Integer and Decimal. And in some cases, the numeric value of 1 is treated similarly to the empty value.

When a value of 0 is entered as a numeric field's value, the raw value will be shown as 0, but the display format (as in the file list) will be shown as empty. The empty display allows for less visual noise in the user interface, since a column full of 0 values is not usually helpful. In fact, if you attempt to set a numeric field's value to 0 in the file list, it will immediately be displayed as empty.

Generally this difference is unimportant, except when testing numeric values with IsEmpty() or IsEqual(). It is easy to be fooled when testing such a value if the value shown in a file list is empty. The values shown in the Tag Action Window will reveal the actual raw value, as will an expression column using the field's raw format.

Another consideration for integer fields is that when sorting, a 1 value can sometimes sort indistinguishably from an empty value. The Integer type disc # field is typically empty when an album consists of only one disc, and as such, Media Center will sort the disc # values of empty (0) and 1 identically.

The friendly output of a field can differ, depending on context. For example, in a file list, and empty field will be shown as blank, but in the Rename, Move & Copy tool, it will be output as Unknown Disc # (this ensures no blank values are generated as path components). To test such a field, always use and test against the raw format, and then expressions will be context agnostic.

Field Assignment

The output of an expression can be used to assign a value to a tag. This is accomplished by preceding the expression with an = character. The = character causes the tagging engine to invoke the expression evaluator first, and then to use its output as the value to assign to the field.

Field Assignment with Expression.png

Without the prepended = character, the literal expression text itself and not its evaluated value would be stored in the tag. The expression can refer to the field's own value to modify itself, and this offers a convenient way to perform complex transformations on field values. For example, the assignment expression

=removeleft([name], 4)

entered into an edit cell for the name field would remove four characters from the left of the name field's current value. An assignment expression can be entered into the Tag Action Window, or by using inline editing in the file list or a pane entry. The image on the right shows in-place field assignment.

Note: Undo is supported, reverting each tag to its value prior to the assignment. Redo is also supported, reapplying the most recent Undo.

Expression Language Syntax

Now that the basics have been covered, the more rigorous rules of the expression language syntax can be described.

  • An expression is any sequence of literal text and any number of function calls.
  • Expressions are read and evaluated left to right. Literal text is output unmodified, function calls are evaluated and their return values output.
  • Fields designated using square bracket notation are expanded into the equivalent Field() function call.
  • Nested function calls are evaluated from the innermost function to outermost function, and again, left to right when one function follows another.
  • A function is evaluated and its returned value contextually replaces the function call in the expression
  • Within a function's argument list, whitespace is ignored before and after commas, after an opening parenthesis, and before a closing parenthesis.
  • The forward-slash escape character / disables the special meaning of the character that follows it.
  • The escape sequence /# followed by #/ escapes everything inside.
  • To use a literal parenthesis, comma, or whitespace inside of function argument lists, escape them. Whitespace within an argument's value is literal and does not need to be escaped when it is surrounded by other non-whitespace text.
  • An expression may be split into multiple lines, but when it does not satisfy the conditions above regarding whitespace around function parenthesis and commas, use a forward-slash escape as the last character before the newline. Extraneous newlines in the expression editor will produce a trailing ellipsis (...) in the output.

How Expressions Are Evaluated

Expressions are evaluated in the context where they are used. For example, an expression column in a file list is evaluated relative to those files in the file list. And the general flow is that for each file in the list, the expression is evaluated and produces output. The expression only has access to the fields available for the file currently being evaluated. This is important to remember, so it bears repeating. One file after another, an expression is evaluated against that single file, its output is produced and stored away for use later, and then the result of that evaluation is entirely forgotten before the next file is evaluated. This means, the expression evaluator cannot use the results from one file's evaluated expression with the results of another file's evaluation.

Expressions and Locales

Media Center will respect the Windows locale setting for output values produced by certain functions, and within the values of certain fields. This is important to consider when writing expressions that consume such values. Under most circumstances, such values cause no harm. However special care must be taken with functions that require the use of period as the decimal point. One such function is Math(), which always uses period as the decimal point. If your locale uses some other character such as comma, these characters will have to be converted into periods before the critical function is called. Handling this problem is not difficult. Before passing to Math() any floating point number, use Replace() first when necessary to convert the locale's decimal character into a period. Fields that cause problems are any fields that produce floating-point values, such as any Date type field in raw format (e.g. [date,0], [last played,0], [date modified,0], and [date imported,0]), or any textual field that contains floating-point values that will be used for various calculations (e.g. any of the Dynamic Range variants). Certain functions such as Now() and ConvertTime() also return localized floating-point values. Consider also that the expression parser uses comma as the argument separator. Any literal numeric values specified as a function argument must have any embedded commas escaped.

A Complex Expression Example

Expression Editor.png

Here is a more complex expression example that illustrates the various rules discussed above regarding expressions:

if( IsEmpty( [Disc #] ),
Disc number is empty,
Delimit(
field(disc #) ,
/) ,
DISC /(
)
)

The expression demonstrates that

  • whitespace before and after commas or opening and closing parenthesis is ignored
  • expressions can be safely split into multiple lines using the whitespace rules just mentioned
  • function and field names are case insensitive
  • forward slash is used and required to escape parenthesis (see inside the Delimit() function)
  • whitespace does not require escapement when surrounded by other characters (see after the C in DISC)
  • literal text is output unmodified (Disc number is empty)
  • functions can be nested (Both IsEmpty() and Delimit() are nested within the If() function, and the Field() function is nested within Delimit()

When the expression is run, files that have no disc number will produce Disc number is empty, and files that have, say, a disc number value of 3 will produce DISC (3).

Functions

Functions enable you to transform or generate content automatically. For background information on how functions are used in expressions, refer to The Anatomy of an Expression section above.

This section describes all the various functions provided by Media Center's Expression Language.

Function Arguments

As discussed above, a function call consists of the function's case-insensitive name, immediately followed by an opening parenthesis character, one or more comma-separated arguments, and a closing parenthesis character:

functionname(argument 1, argument 2, ...)

Functions may have one or more arguments. In some cases, these arguments are optional, and will automatically use a default value if omitted. For example, these two expressions are equivalent because the mode argument for IsEmpty() is optional and defaults to 0:

isempty([comment], 0)
isempty([comment])

In this case, a comma-separator will still be required if additional arguments follow the optional one. Whitespace after the commas is also optional, but helps readability and formatting. However, if any extra arguments are included in a function call which are not valid for that function, they are dropped and omitted from output. This is of particular importance when using string-manipulation functions on text. If the text you enter contains any commas, these must be escaped or the expression engine will consider text after the comma to be additional arguments.

The arguments themselves are also just expressions, and you can nest multiple functions to achieve complex logic:

if(isequal([artist], [album], 1), Eponymous, [album])

Nested function calls are always treated as a single argument when used as the input to another function (so that commas in the output of one function do not need to be escaped to be used as input in another function). This includes fields, since they are expanded to the equivalent Field() function call.

Please Note: In some cases below, such as with Unswap(), we have ignored this detail in order to simplify the examples. If you enter any text manually into a function, all commas must be escaped in order to achieve the correct result. This detail is unimportant in most real-world usages, however, because you will typically use either field values or the output of other functions as the arguments in your expressions. However, if you need to include commas in a string literal argument to a function, you need to escape every one, or block escape the entire argument.

Function Index

Accessing and Storing Functions

Conditional Functions

Test and Comparison Functions

Formatting Functions

String Manipulation Functions

  • Clean(…): Clean a string to be used for various operations
  • FixCase(…): Changes the case of a given string
  • FixSpacing(…): Intelligently splits adjacent camel-cased words
  • Hexify(…): Hexifies a string to make it suitable for web usage
  • Left(…): Retrieves a specified number of characters from the left of a string
  • Length(…): Returns the number of characters in a string
  • Mid(…): Retrieves specified characters from a string
  • Regex(…): Regular expression pattern matching and capture
  • RemoveCharacters(…): Removes a list of characters from a string
  • RemoveLeft(…): Trims characters from the beginning of a string
  • RemoveRight(…): Trims characters from the end of a string
  • Replace(…): Replace or remove a string segment
  • Right(…): Retrieves a specified number of characters from the right of a string
  • Swap(…): Takes Firstname Lastname and swaps to Lastname, Firstname.
  • Unswap(…): Takes Lastname, Firstname and reverses it to Firstname Lastname.

List Manipulation Functions

Date and Time Functions

  • ConvertDate(…): Converts a human-readable date to the internal format required for use in date fields
  • FormatDate(…): Formats a date value in a specified manner
  • Now(…): Retrieve and display the system date

File Path and Identifier Functions

Miscellaneous Functions

Data Types

It was mentioned already that the Media Center expression language is primarily a textual language - it consumes and produces text. Nonetheless, certain areas of Media Center are influenced by the type of data used or presented, and sometimes it is useful or necessary to coerce expression output into one data type or another. Each Media Center field is defined to be of a certain data type, listed in the Field Data Types table. These types influence how values are output, sorted, and interpreted on input. And expressions always output data of type String. By coercing the data type of an expression, output formatting and sorting can be controlled in various ways.

Data types are forced by appending to an expression the string:

&datatype=[type]

where type is one of the following values:

listA list of strings, separated by semicolons
stringSorts as strings (with smart number handling)
numberSorts values as numbers (decimal or integer)
integerSorts values as integers
pathSorts using a smart filename compare style
monthSorts string month names (i.e. January, February, etc.)

Calculated Fields and Search

Media Center's Search Language supports some simple numeric comparison operators. Because expressions always evaluate as a String type, these operators would be unavailable for use in a search query to compare numeric values from a calculated expression field. In order to use the numeric comparison operators, a calculated expression field can be cast into one of the numeric types. In your numeric calculated fields, to allow the use Search's numeric comparison operators, add either of the casts:

&datatype=[integer]
&datatype=[number]

to the end of the field's calculated expression.

Lists and Trees

Datatype List.png

The list of output in view categories and pane columns can be modified by forcing the data type to a List type. Two things happen when the data type is List: The values within a List type are split into their individual (semicolon-separated) list items The backslash character takes on a special meaning and becomes another form of separator that creates tree-like hierarchies, collapsible in panes columns and creates drill-down categories in any category view type (Standard View > Categories, Theater View, DLNA, Gizmo/WebGizmo). Forcing an expression's type to list causes this list item separation and hierarchy generation. Alternatively, forcing a List type to string defeats this. Add the cast:

&datatype=[list]

to the end of an expression to force an expression's output to be considered as a List type. Conversely, a List type may be forced into a String type by adding the cast:

&datatype=[string]

to the end of an expression.

Sort Order

Datatype Month.png

Normally strings are sorted ASCII-betically with some smart numeric sorting. But this form of sort may not always be desired.

Sorting by Month

Generally it is more useful to see month names sorting such that January sorts before April, instead of alphabetically where April would sort before January. Forcing an expression's type to Month forces string month values to be treated instead as their equivalent numerical month numbers. For example, the first month January and the third month March sort before the fourth month April. Add the cast:

&datatype=[month]

to the end of an expression to force an expression's output to be sorted by numeric month values.

Sorting by Path

Path data types sort using smart filename comparisons.

XXX: Note: This section is incomplete. I cannot distingish any difference between using a datatype of path vs. string. It seems path sort order is always engaged.

Add the cast:

&datatype=[path]

to the end of an expression to force an expression's output to be smart-sorted by path components.

Expressions and Search

The expression language is fully available to the search query engine (Search, Set rules for file display, etc.). This allows creation of more complex search queries than would otherwise be possible. An expression-based search query is any valid expression that produces a zero or non-zero numeric output. The syntax of the query is:

[=expression]=numval

where expression is any valid expression, and numval is the expected numeric output produced by the expression. The expression is evaluated against the current list of available files and the expression output numerically compared against numval. All files for which the comparison is true are returned as part of the file list produced by the query and all files that fail the comparison are winnowed from the file list.

The following example illustrates an expression-based search query:

[=ismissing([filename (path)]\Folder.jpg)]=1

The IsMissing() function is run using the file name argument [filename (path)] appended by \Folder.jpg, and returns a Boolean value 1 for files that are missing, and this 1 is compared against the value numval. All these files where there was a successful comparison are returned in the file list, and all those for which the expression produced 0 are filtered from the file list. By inverting the comparison and using a 0 numval, the set of files remaining in the file list would be those that did not match.

HTML Font Properties

The expression language recognizes a limited set of HTML font properties and attributes. These can be used to set font styles in most text drawing areas, such as captions, thumbnail text and in the configuration of Theater View. HTML tags are used by surrounding the desired content with an opening and closing tag, in the form of:

<tag>desired content<//tag>

The supported HTML tags are:

<b>Bold
<i>Italics
<u>Underline
<font>Font properties (see attributes below)

The font tag supports the following attributes:

alphaSets alpha-blending percentage (0 - 100)
colorSets the foreground color (RGB hex values from 00 to ff in the form of rrggbb)
bgcolorSets the background color (same values as color)
faceSets the font face (a font name)
sizeSets the font size (a percentage scaling value)

Any combination of HTML tags and font attributes can be used. An HTML tag must have an opening and closing tag. Nesting is allowed, but be sure to properly balance like opening and closing tags. Attribute values must be double quoted. The closing tag's forward slash requires escapement with an extra forward slash. The following examples illustrate using HTML font properties:

<i>This is in italics<//i>
<i><b>And this is bold and italic<//b><//i>
<b>The<font color="ff0000" size="80" alpha="50"> Great <//font>Gatsby<//b>

Expression Editors

There are a couple of variations of dialog or edit field used to enter expressions. Some allow multi-line expressions, while others are single line, but can be expanded to multi-line editors. Unfortunately, some single-line editors flatten multi-line expressions into a single line, replacing the newlines with spaces.

Acknowledgements

A big tip of hat to marko who tackled the enormous challenge of documenting the MC Expression Language in detail. His work was instrumental and through which has brought clarity and great assistance to Media Center users worldwide.

Also, a huge thanks to user MrC who built the amazing and long-lived previous version of this page, upon which this is still heavily based.

The current caretaker of this documentation is forever in their debts.