Welcome to the Simpler framework documentation index. Here you will find detailed written documentation to assist with your development needs. 

This is supplemental and detailed documentation, versus the overview found on the main Developer page.

 

Search for a topic:

Environment Setup

Overview

The following is a guide to help setup the initial environment for the Simpler platform for client-hosted sites, and/or a development workstation.

System Requirements

While the latest and greatest hardware and software are always recommended, the following are the minimum requirements to run the Simpler platform:

Hardware Requirements

The following hardware requirements* must be met:

  • 4GB of RAM or greater
  • 2 Logical CPU cores or more
  • 2GB of free disk space for temporary files (application binaries and templates are <100MB) 
  • Additional storage for synchronized tables (to be determined based on scope and data source(s))

* These are minimums. Additional CPU and RAM resources may be necessary based on usage.

Software Requirements

Simpler is developed in .NET, and runs on Windows Server. Requirements are:  

  • Windows Server 2008 R2 or higher (Server)
  • SQL Server 2008 R2 or higher
    • Database size set to 10% unlimited growth
    • Truncate transaction logs set to “Yes”
    • Scheduled weekly full backup – recommended
    • Create an application user with read/write privileges
  • .NET 4.0 or higher
    • automatically be installed with Microsoft Visual Studio
  • Text editor or IDE
    • Visual Studio IDE recommended
  • IIS 6.0 or higher (only required on web server)
  • Browser
  • Gurock SmartInspect Redistributable Console

.NET 4.0 or higher

Simpler Systems requires the full installation of .NET 4.0 framework. The desktop profile may not provide the full installation. For example, Windows 7 will have .NET but not the full components. Installing Microsoft Visual Studio as recommended in the next section will make sure that all components necessary for development are available.

Text Editor

While any text editor will work, including Notepad, Simpler Systems recommends Visual Studio 2010 (VS 2010 Express C#) or higher; .NET 4.0 will automatically be installed when we install Visual Studio. Whichever editor we choose, Simpler recommends an editor with an XML interpreter, so we will have access to the Intellisense and auto-complete functionality.

Internet Information Services (IIS) 6.0 or higher

Internet Information Services (IIS) is an extensible web server created by Microsoft for use with Windows servers. IIS supports HTTP, HTTPS, FTP, FTPS, SMTP and NNTP. IIS is not activated by default when Windows is first configured. The IIS Manager is accessed through the Microsoft Management Console or Administrative Tools in the Control Panel.

Gurock SmartInspect Redistributable Console

SmartInspect is a third party logging tool for debugging and monitoring .NET,
Java and Delphi applications. SmartInspect allows us to identify bugs faster,
and monitor applications in real-time, allowing us to find solutions to user-reported
issues. Go to www.gurock.com/smartinspect for more information.

  1. Download and install executable here (will prompt .exe file download).
  2. See Gurock Support page for FAQs and tutorials.

Installing Simpler Application

The following instructions will install the Simpler application on our workstation/server. The Simpler application has been developed to install and execute identically locally and on servers, with the only difference being IIS for web services.

Install

  1. With a valid license to use Simpler, we will receive a zip folder (simpler.zip) containing all the necessary default files and binaries to run the application. 
  2. Save simpler.zip to a directory of your choice. 
  3. Extract the contents of the zip file into the same folder. Voila!
    The Simpler application is installed. It’s that simple. There are no registry changes,
    and no security is needed at this point.

Uninstall

To uninstall, simply delete the entire contents of the /../Simpler folder from its root directory.

Updates

 

Folder Contents

The simpler.zip folder may actually contain more than the following, but the stripped down application folder described below reflects the required (or at least extremely convenient) contents to have with a fresh build.

rootfolder.PNG

Root folder

  • Configuration.xml - A configuration file for global application settings.
  • custom-frame.xml - The fully customizable frame banner at the top of the browser window
  • helloworld.xml - A simple template provided for Tutorial demonstration.
  • simpler.exe - An executable file that starts the Simpler Server (sssvr.exe) in /bin folder.
  • Template.xsd - Defines the template schema allowing xml editors to provide IntelliSense.
  • web.config - Contains configuration settings redirecting web pages to the simpler server for interpretation
    • only needed for "live" IIS applications

Bin folder

binfolder.PNG
  • dynamic link libraries (DLL files)
  • simpler.dll
  • other third party DLLs
  • executable files (.exe)
  • ss.exe – The “SS Server” is the core of the simpler platform. It handles the interpretation of the XML templates and generates the HTML pages. Ss.exe can be called from the command prompt with a URL parameter and output destination.
  • sssvr.exe – The “SS Server” console provides a graphic interface to control the server. When this file is executed, the console is started. The console allows you to enable or disable an instance of the “ss server”, set a port to use, and provides a link to the start page using that instance of the server. Running the templates from the console allows the web pages to run through the browser without setting up a website in IIS.
  • ssupdate.exe – The “SS Update” feature automatically downloads and updates the bin folder.
  • Zip folders - The bin folder contains several zip folders (about, build,configure, dynamic, source & start) 

Zip folders

zipfolders.PNG

The bin folder contains several zip folders (about, build, configure, dynamic, source & start), which contain the default versions of the various XML templates contained within. They can be overridden by creating a folder in the root folder with
the same name, and including any template files you wish to override.

  • about - about.zip contains default built-in reference framework documentation for "hello world!", scripting, script functions, and system architecture
  • build - the most frequently overridden zip folder, build.zip defines the default XML build structure for dynamically-generated select, compose and search templates of a datapp. 
  • configure - configure.zip contains templates for updating global configuration settings, if we prefer to make changes through browser interface, versus through Configuration.xml in the root folder. 
  • dynamic - dynamic.zip stores the templates that drive the dynamic templates defined in build.zip, serving as an intermediary between the data itself and the datapp XML build templates.
  • source - source.zip contains templates for viewing source code and syntax highlighting.
  • start - start.zip stores the default start.xml template, which serves as the developer "Start" page, or dashboard interface, for administering the application through the browser. 

Starting Simpler Application

Start-up

1. Run simpler.exe in your root directory, which will load a local server command prompt:

localhostunchecked.PNG

2. You will notice three "Options" along the top: 

localhostoptions.PNG

Leaving everything else as the default, check the Enabled checkbox.

  • Enabled checkbox - Checking this box initiates the local server development environment
  • Allow Remote Access checkbox - Checking this box allows the site to be accessible in the local network, without being directly logged in to the workstation or server where the application resides
  • Port - This textbox controls the port for the local server to run from, which defaults to port 180. You can have as many instances of simpler.exe running on the same machine, so long as the port is distinct for each application root directory. 

3. You will see that the localhost server is now running, and a hyperlink has appeared in the upper-right corner of the local server command prompt:

localhost.PNG

 

 

Click the localhost:180/start.html link. This will allow you to
view the Start page in its basic form.

The Start Page

The Start page is the browser interface for everything the developer does. It provides a place from which to manage global configuration settings, authentication settings, database connection strings and application passwords.

It appears with various headings and links to the dynamic template builders such as Select, Compose, and Present templates, which will be explained in further sections of this guide. In its default state, the Start page appears as follows:

startpage.PNG

Configuration 

Overview

As developers, we have the ability to administer global settings for the Simpler application, as well as maintain connection strings and application passwords. Depending on our preference, we can control most of these settings from the Start page, or the configuration.xml file that should be in the root directory. 

From the Start Page

You can add or change application configuration elements from the start page, if a browser interface is preferred. We will elaborate on how to do so for each respective configuration type below.

From Configuration.xml

Some will want to control configuration elements directly in the XML, in a text editor instead of a browser interface. We will ultimately have more control and visibility if editing the XML directly.

Settings

Built-in Settings

Custom Settings

 

Data Sources

From the Start Page

From Configuration.xml

Application Passwords 

From the Start Page

 

Hello, World!

The Simpler framework is programmed with XML templates, which are XML documents enhanced with SimplerScript. The following walkthrough will introduce the essentials of the framework scripting and general structure. The walkthrough will use the Tutorial layer, which provides a basic set of printing and iteration services.

Getting Started

Localhost

To begin this Hello World tutorial:

1. Run simpler.exe in your root directory, and check the "Enabled" box in the top left corner of the command prompt that opens.

localhost.PNG

2. Then, in your browser's address bar, go to http://localhost:180/helloworld.xml

3. Open the file, helloworld.xml in your root application directory, and follow along with the tutorial below.

helloworlddirectory.PNG


Tutorial Layer

Below is the <Tutorial> template in XML + SimplerScript:

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AllUsers" Description="Hello World Tutorial" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite ......\Template.xsd">
    <Tutorial>
        <Print>Hello World!</Print>
    </Tutorial>
</Template>

Result of this template:

The <Template> element declares that this is a Simpler XML template. The Access attribute specifies that this template is accessible by all users. There are also some required XML housekeeping attributes. The <Tutorial> element declares that this template will be using the services of the Tutorial layer. The <Print> element, when executed, writes its value to the output.


SimplerScript

Below is the Tutorial template enhanced with SimplerScript:

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AllUsers" Description="Hello World Tutorial" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite ......\Template.xsd">
    <Tutorial>
        <Print>{'Hello ', 'World', '!'}</Print>
    </Tutorial>
</Template>
The literal "Hello World!" text has been replaced by a script. Scripts are delimited by curly braces { }. They can be used in any attribute or element.

Scripts are lists of strings, numbers, dates, or booleans. The script in this example is a list of three strings: the literal 'Hello ', the literal 'World', and the literal '!'.

After scripts are evaluated, they are assigned to an attribute or an element's value. In many cases, this means "reducing" a list of several values to a single value. Lists of strings are reduced by concatenation, lists of numbers are reduced by addition, and lists of booleans are reduced by the logical and operation. In this example, the list {'Hello ', 'World', '!'} is reduced to 'Hello World!'.

Result of this template:

Notice, the result in this case is the same as the unscripted version.

 

Identifiers

Below is another version of the Tutorial template, in which the literal 'World' has been replaced by an identifier, Name.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AllUsers" Description="Hello World Tutorial" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite ......\Template.xsd">
    <Tutorial>
        <Print>{'Hello ', Name, '!'}</Print>
    </Tutorial>
</Template>
When this script is executed, the value of the Name identifier is determined by the query string:


/helloworld.xml?Name=Calvin


Result of this template with Name=Calvin as the query string:


Result of this template with Name=Hobbes as the query string:


The "When" Attribute

Below is yet another version of the Tutorial template, which has a second <Print> element, and When attributes with scripts. Every element in an XML template has a When attribute that determines whether or not the element is processed. The When attributes contain scripts that compare the value of the Direction identifier to a literal string. The first <Print> element is executed when the value of Direction is 'Coming', and the second <Print> element is executed when the value of Direction is 'Going'.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AllUsers" Description="Hello World Tutorial" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite ......\Template.xsd">
    <Tutorial>
        <Print When="{Direction = 'Coming'}">{'Hello ', Name, '!'}</Print>
        <Print When="{Direction = 'Going'}">{'Goodbye ', Name, '!'}</Print>
    </Tutorial>
</Template>
Result of this template with Name=Calvin&Direction=Coming as the query string:


Result of this template with Name=Calvin&Direction=Going as the query string:


Conditional Scripting 

The next version of the Tutorial template implements the same functionality as the previous version, but uses the SimplerScript when keyword instead of the When attribute. Every element in a list can be followed by a when clause. The expression following the when keyword determines whether or not the element is included in the list.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AllUsers" Description="Hello World Tutorial" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite ......\Template.xsd">
    <Tutorial>
        <Print>{'Hello ' when Direction = 'Coming', 'Goodbye ' when Direction = 'Going', Name, '!'}</Print>
    </Tutorial>
</Template>
Result of this template with Name=Calvin&Direction=Coming as the query string:


Result of this template with Name=Calvin&Direction=Going as the query string:


Complex Conditions

More complex conditional scripting can be achieved with the logical "and", as well as logical "or" operations.

The first <Print> element is executed when the value of Direction is 'Coming' AND the value of Greeting is 'Y', so both must be true to print the text.

The second <Print> element is executed when the value of Direction is 'Going' OR the value of Greeting is 'Y', so one identifier or the other must be true to print the text.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AllUsers" Description="Hello World Tutorial" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite ......\Template.xsd">
    <Tutorial>
        <Print>{'Hello World!' when Direction = 'Coming' and Greeting = 'Y'}</Print>
        <Print>{'Hello World!' when Direction = 'Coming' or Greeting = 'Y'}</Print>
    </Tutorial>
</Template>

Result of this template with Direction=Coming&Greeting=Y as the query string:


Result of this template with Greeting=Y as the query string:


Notice how both 'Hello World!' <Print> elements are executed in the first result, since both Direction=Coming and Greeting=Y, which satisfies both <Print> elements. However, in the second result, only Greeting=Y, so the <Print> statement with the "and" operation does not have both conditions satisfied, and is not executed.


The next <Print> element combines both "and" and "or" operations. It executes 'Hello ' followed by a name, if the Name identifier is not null ('Name!=null'), AND either Direction is equal to 'Coming', OR Greeting is equal to 'Y'. However, if Name is null (Name=null), 'World' will be executed instead, followed finally by an unconditional '!' at the end.
<?xml version="1.0" encoding="utf-8"?>
<Template Access="AllUsers" Description="Hello World Tutorial" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite ......\Template.xsd">
    <Tutorial>
        <Print>{'Hello ', Name when Name!=null and (Direction = 'Coming' or Greeting = 'Y'), 'World' when Name = null, '!'}</Print>
    </Tutorial>
</Template>

Result of this template with Name=Calvin&Greeting=Y as the query string:

Result of this template with Direction=Coming as the query string:


Another way to achieve more complex results is through nested scripting, where the results of a nested script are used to evaluate whether or not an item in the parent script is included in the list. This next <Print> element contains a number of nested scripts, delinieated with curly brackets "{}" embedded in the parent script.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AllUsers" Description="Hello World Tutorial" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite ......\Template.xsd">
    <Tutorial>
        <Print>{{{'Hello ' when Direction = 'Coming', 'Goodbye ' when Direction = 'Going'}, Name, '!'} when Direction !=null and Name!=null, {Name, ', are you coming or going?'} when Direction=null and Name!=null, else 'No one to greet'}</Print>
    </Tutorial>
</Template>
From left to right, the first nested script prints 'Hello ' when Direction is 'Coming', and 'Goodbye ' when Direction is 'Going':

{'Hello ' when Direction = 'Coming', 'Goodbye ' when Direction = 'Going'}

The result of this script is then concatenated with the contents of another nested script, that includes the Name identifier, and a literal '!'. However, this nested script is only returned if both Direction is not null and Name is not null:

{{'Hello ' when Direction = 'Coming', 'Goodbye ' when Direction = 'Going'}, Name, '!'} when Direction !=null and Name!=null

The next nested script is evaluated if the Direction is null, but the name was provided (Name!=null). It returns the Name concatenated with the string ', are you coming or going?', prompting the user to provide a direction:

{Name, ', are you coming or going?'} when Direction=null and Name!=null

Finally, the last component of the script is an else clause, that is the default reply if neither Name and Direction are assigned values, which prints No one to greet:

else 'No one to greet'

Result of this template with Name=Calvin&Direction=Going as the query string:

Result of this template with Name=Calvin as the query string:

Result of this template with no identifiers assigned as the query string:


The Script Element

Sometimes, when conditional scripts begin to get too complex, we will want to parse out the items of the script to make the code more readable and configurable, using the <Script> element.

The <Script> element can be placed as a child element of nearly any element in the framework. Besides making scripting more readable, they also serve a purpose of declaring global identifiers, to be used to evaluate the script throughout a template. Since they can be assigned nearly anywhere, they can be as global or as local to a given element or group of elements as needed.

In the following <Print> element, we produce the same results as the prior Tutorial example, however we opt instead to parse out the nested scripts using the <Script> element into different identifiers, replacing the longer <Print> script with these identifiers.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AllUsers" Description="Hello World Tutorial" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite ......\Template.xsd">
    <Tutorial>
        <Script>
          Greeting {'Hello ' when Direction = 'Coming', 'Goodbye ' when Direction = 'Going'}
          FullGreeting {Greeting, Name, '!'}
          GetDirection {Name, ', are you coming or going?'}
        </Script>
        <Print>{FullGreeting when Direction !=null and Name!=null, GetDirection when Direction=null and Name!=null, else 'No one to greet'}</Print>
    </Tutorial>
</Template>


Result of this template with Name=Calvin&Direction=Going as the query string:

Result of this template with Name=Calvin as the query string:

Result of this template with no identifiers assigned as the query string:

Template XML Schema Documentation (XSD)

Overview

The Template XML schema documentation (XSD) includes a list of the templates and all elements and attributes available in the framework.

The XSD is organized in a tree node format, with ancestor/descendant relationships displayed for each respective element, with Template types at the root of each tree. 

Get Template.xsd

To get a local copy of your environment's Template.xsd (if it doesn't already exist in the root directory), you can obtain it from your localhost server. This can be done through the following:

1. Run simpler.exe in your root directory.

localhost.PNG

2. Then, in your browser's address bar, go to: http://localhost:180/template.xsd

  • This should prompt you to save the file, which should then be placed in your root directory.
templatexsd.PNG

Reading Local Template.xsd

In our local copy of the Template.xsd file (in the root application directory), the documentation is organized in a standard tree node structure, where most IDEs will be able to have expandable nodes to see child elements and respective attributes for each element, as seen below: 

xsdvisualstudio.PNG

Clicking on Select.Query.CsvFile in Visual Studio will take you to the detailed XML schema location of this particular element of the framework, as seen here:

xsdexpanded.PNG

In this detailed view of the Select.Query.CsvFile element, you can see all of its available child elements (i.e. Column), as well as the element's available attributes (i.e. Path).


Interactive XSD 

In the Interactive XSD in the link below, the branches (descendant elements) are denoted with indentations.

For example, in the accompanying screenshot below, Query is a branch (or child descendant), of Select, and CsvFile is a child of Query. Therefore, CsvFile is a grandchild descendent of Select. The fully qualified notation of CsvFile would therefore be: Select.Query.CsvFile.

xsdlivenode.PNG

Clicking on CsvFile will take you to this child element's schema location, where you can see all it's Childen, Parents, and Attributes delineated with headers. Note that required element attributes are shown in red.

Whether we decide to use the local copy of template.xsd or the interactive XSD, this same tree node model can be used to explore all elements of the template schema. 
 

Interactive XML Schema Documentation (XSD)

The columnar Templates and Functions listed below are an up-to-date index of all the Simpler framework's schema elements, attributes, and functions.

 

Templates Column

The Templates column is laid out similar to a tree-node format, however instead of expandable tree nodes, indentation represents a child element of the parent that precedes it.

Clicking on an item from the "Templates" column will drill-down to its child elements, with description of the element and its available attributes.

When clicking into an element, we can click the Create button. With this, we'll be able to fill out the attributes for the respective element, and generate an XML snippet that we can use in an XML template file. 

 Functions Column

Clicking on an item from the "Functions" column will drill-down to a description of the function's usage. 

When clicking into a function, we again have a Create button that allows you to test the function's output with test arguments. 

Returning to Index

At any time while navigating the Interactive XSD, click "Back to Index" link to return to the main index.

For more on the XSD in general, see Template Schema documentation. 

SimplerScript

 

Overview

SimplerScript is the propriety framework language developed by Simpler Systems. The script is what allows the data to be drilled down into, to allow the data to be the user interface.

Script Notation

SimplerScript evaluates a list of items, separated by commas. Lists are delimited by curly braces: { }. The items in a list can be literals, identifiers, or expressions. They can be used in any attribute or element.

After scripts are evaluated, they are assigned to an attribute or an element's value. In many cases, this means "reducing" a list of several values to a single value. 

Lists

The items in a list can be literals, identifiers, or expressions.

  • The list {1, 2, 3} contains three items.

  • The list {'Hello'} contains one item.

Lists can be nested to any depth, but lists are always one-dimensional. Nested lists are "flattened".

  • The list {1, 2, {3, 4}} is the same as the list {1, 2, 3, 4}.

  • The list {{1, {2, {3}}}} is the same as the list {1, 2, 3}.


Types

SimplerScript understands four simple types of data (strings, numbers, dates, booleans), and one complex type (lists).

  • The list {'A string', 'A ''string'' with nested quotes'} contains strings.

  • The list {1, 2.5, 3.14159, -42} contains numbers. SimplerScript numbers are equivalent to the Microsoft .Net decimal data type.

  • The list {#12/31/2009#} contains a date. SimplerScript dates are equivalent to the Microsoft .Net DateTime data type.

  • The list {true, false} contains booleans.

SimplerScript also has a special null value that is equivalent to an empty list ({}), and empty string (''), zero, and false.


Type Conversion and List Reduction

SimplerScript values are automatically converted to the required type, so if a number is provided where a string is expected, the number will be converted to a string. If a specific type conversion is required, the as clause explicitly converts a list from one type to another.

  • The list {42} as String is equal to the list {'42'}.

  • The list {'42'} as Number is equal to the list {42}.

When a list that contains more than one item is converted to a simple type, the list is "reduced". If the list is converted to a string, each item in the list is converted to a string and then the strings are concatenated together. If the list is converted to a number, each item in the list is converted to a number and then the numbers are added together. If the list is converted to a boolean, each item in the list is converted to a boolean and then the booleans are added together.

  • The list {1, 2, 3} as String is equal to the list {'123'}.

  • The list {'1', '2', '3'} as Number is equal to the list {6}.

  • The list {0, 1} as Boolean is equal to the list {false}.

It is also sometimes useful to do a list reduction that doesn't include a type conversion.

  • The list {'1', '2', '3'} as String is equal to the list {'123'}.


Identifiers

Identifiers can be used in place of literals to make scripts return different results depending on the context in which the script is evaluated. For example, when a template is executing, the values of identifiers are assigned by the query string or by <Script> elements. When a Select template is evaluating the value of a column, the values of identifiers are assigned based on the columns in the row that is being processed.

Basic identifiers start with a letter or underscore, and are followed by any number of letters, digits, or periods, or underscores.

Extended identifiers can contain any character, but must be delimited by double quotes.

Reserved identifiers are basic identifiers that contain a period. The values of reserved identifiers are assigned by the system.

  • The list {BasicIdentifier, _BasicIdentifier2} contains basic identifiers.

  • The list {"Extended identifier", """Extended"" identifier 2"} contains extended identifiers.

  • The list {Url.Path, Settings.DefaultPage} contains reserved identifiers.


Expressions

Arithmetic, boolean, and comparison expressions can be used in place of literals to perform computations.

  • The expression {3 * 4} is equal to 12.
  • The expression {12 / 3} is equal to 4.
  • The expression {1 + 2} is equal to 3.
  • The expression {1 - 2} is equal to -1.
  • The expression {1..4} is equal to the list {1, 2, 3, 4}.
  • The expression {0 = 1} is equal to false.
  • The expression {0 != 1} is equal to true.
  • The expression {0 < 1} is equal to true.
  • The expression {0 <= 1} is equal to true.
  • The expression {0 > 1} is equal to false.
  • The expression {0 >= 1} is equal to false.
  • The expression {true and false} is equal to false.
  • The expression {true or false} is equal to true.
  • The expression {not false} is equal to true.


Conditionals

Any item in a list can be followed by a when clause, or be preceded by the else keyword. If the expression following the when keyword evaluates to false, the item that precedes the when keyword is not included in the list. If a list is not empty when an item is encountered that is preceded by the else keyword, then the item that follows is not included in the list.

  • The expression {'A' when 0 = 1, 'B', 'C'} is equal to the list {'B, 'C'}.
  • The expression {'A' when 0 != 1, 'B', 'C'} is equal to the list {'A', 'B', 'C'}.
  • The expression {'A' when 0 = 1, 'B' when 0 != 1, 'C'} is equal to the list {'B', 'C'}.
  • The expression {'A' when 0 != 1, 'B' when 0 != 1, else 'C'} is equal to the list {'A', 'B'}.
  • The expression {'A' when 0 = 1, 'B' when 0 = 1, else 'C'} is equal to the list {'C'}.


Script Functions

Scripts can call built-in framework functions. A function is invoked by specifying the function name followed by parentheses. Any parameters for the function are listed inside the parenthesis and are separated by commas.

Function Usage

Function names have the same form as reserved identifiers. For example, String.Length is the function that returns the length of a string. The first part of the function name is the namespace. If the function is in the List namespace, then the namespace can be omitted. The following functions all take a single argument:

  • The result of String.Length('Hello') is 5.

  • The result of List.Count({1, 2, 3}) is 3.

  • The result of Count({1, 2, 3}) is 3.

Depending on the function, one to many arguments may be required to evaluate the result, while others require no arguments, or optional arguments:

  • The result of Date.Today() is

  • The result of Date.Now() is

  • The result of String.Random() is

Lastly, here are some functions that require more than one argument:

  • The result of String.Replace('Goodbye','Good','') is 'bye'.
  • The result of List.Contains({1,2,3}, 1) is true.
  • The result of Date.AddDays(Date.Today(),7) is

For a detailed listing of all built-in SimplerScript functions, see the Script Function Reference in the link below:

URL Evaluation 

Urls can be called as functions. Generally, the return value of a url will be a string containing html, but urls also can return non-html text. If the url is a template and the url extension is '.xml', then the return value may be a list if the template supports function calls.

Urls are invoked by delimiting a string with square braces: [ ]. If there are multiple values within the square braces, the values will be concatenated.

For example, let's say we have the following Tutorial template, /helloworld.xml, sitting in the root directory.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AllUsers" Description="Hello World Tutorial" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite ......\Template.xsd">
    <Tutorial>
        <Print>Hello World!</Print>
    </Tutorial>
</Template>

The result of ['/helloworld.txt'] is 'Hello World!'.

The square braces invoke the URL and return the results of this external URL to the page we have invoked it from. In this case, the <Print> statement is executed and 'Hello World!' is evaluated as the result.

Now let's say we have the same Tutorial template, /helloworld.xml, but we modified the <Print> element to accept a Name identifier through the URL query string.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AllUsers" Description="Hello World Tutorial" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite ......\Template.xsd">
    <Tutorial>
        <Print>{'Hello ', Name, '!'}</Print>
    </Tutorial>
</Template>

The result of ['/helloworld.txt', 'Name=Calvin'] is 'Hello Calvin!'.

Notice how we separated each component of the square-braces script notation: first, we provide the base url '/helloworld.txt'; second, we then add the argument(s) we pass as the query string, 'Name=Calvin'.

Script Functions

 

Framework Functions

Within any script, we can call built-in framework functions. A function is invoked by specifying the function name followed by parentheses. Any parameters for the function are listed inside the parenthesis and are separated by commas.

Function Usage

Function names have the same form as reserved identifiers. For example, String.Length is the function that returns the length of a string. The first part of the function name is the namespace. If the function is in the List namespace, then the namespace can be omitted. The following functions all take a single argument:

  • The result of String.Length('Hello') is 5.

  • The result of List.Count({1, 2, 3}) is 3.

  • The result of Count({1, 2, 3}) is 3.

Depending on the function, one to many arguments may be required to evaluate the result, while others require no arguments, or optional arguments:

  • The result of Date.Today() is

  • The result of Date.Now() is

  • The result of String.Random() is

Lastly, here are some functions that require more than one argument:

  • The result of String.Replace('Goodbye','Good','') is 'bye'.
  • The result of List.Contains({1,2,3}, 1) is true.
  • The result of Date.AddDays(Date.Today(),7) is

For a detailed listing of all built-in SimplerScript functions, see the Script Function Reference in the link below:

URL Evaluation 

URLs can be called as functions. Generally, the return value of a URL will be a string containing html, but URLs also can return non-html text. If the URL is a template and the URL extension is '.xml', then the return value may be a list if the template supports function calls.

URLs are invoked by delimiting a string with square braces: [ ]. If there are multiple values within the square braces, the values will be concatenated.

For example, let's say we have the following Tutorial template, /helloworld.xml, sitting in the root directory.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AllUsers" Description="Hello World Tutorial" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite ......\Template.xsd">
    <Tutorial>
        <Print>Hello World!</Print>
    </Tutorial>
</Template>

The result of ['/helloworld.txt'] is 'Hello World!'.

The square braces invoke the URL and return the results of this external URL to the page. In this case, the <Print> statement is executed and 'Hello World!' is evaluated as the result.

Now let's say we have the same Tutorial template, /helloworld.xml, but we modified the <Print> element to accept a Name identifier through the URL query string.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AllUsers" Description="Hello World Tutorial" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite ......\Template.xsd">
    <Tutorial>
        <Print>{'Hello ', Name, '!'}</Print>
    </Tutorial>
</Template>

The result of ['/helloworld.txt', 'Name=Calvin'] is 'Hello Calvin!'.

Notice how we separated each component of the square-braces script notation: first, we provide the base url '/helloworld.txt'; second, we then add the argument(s) we pass as the query string, 'Name=Calvin'.

Script Elements

Overview

The <Script> element can be placed as a child element of nearly any element in the framework. Besides making scripting more readable, the <Script> element also serves a purpose of declaring global identifiers, to be used to evaluate the script throughout a template. Since they can be assigned nearly anywhere, they can be as global or as local to a given element or group of elements as needed.

Format

Script elements can define one or more named scripts, and have a unique format in SimplerScript. The scripts being defined are listed as inner text, and are evaluated in the order they are listed.

The advantage of evaluating scripts in order, is primarily that scripts can be built in whole or in part from the scripts declared prior to it.  Take the example below:

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AllUsers" Description="Hello World Tutorial" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite ......\Template.xsd">
    <Tutorial>
        <Script>
          Greeting {'Hello ' when Direction = 'Coming', 'Goodbye ' when Direction = 'Going'}
          FullGreeting {Greeting, Name, '!'}
          GetDirection {Name, ', are you coming or going?'}
        </Script>
        <Print>{FullGreeting when Direction !=null and Name!=null, GetDirection when Direction=null and Name!=null, else 'No one to greet'}</Print>
    </Tutorial>
</Template>

Here we see three scripts declared in the <Script> element: Greeting, FullGreeting, and GetDirection. 

Usage

Readability

The <Script> element can be used for clearer readability of code. Rather than redundantly repeating the same snippet of code throughout a document, we need only write the code once, making the remainder of the XML document more concise and readable.

Reusability

In addition to readability, the succinct variables defined in the <Script> element make code snippets reusable as well. Not only does this make the document more readable, it also makes development quicker and more efficient.

Global vs Local Identifiers

Depending where the <Script> element is placed in the XML document, the variable identifiers can be used as globally or as locally as desired. If the <Script> is declared at the top of the XML document, as a sibling or parent element of those that follow, it can be globally evaluated throughout the document. However, it is is declared as a child element of a specific element, it is only evaluated within that tag.

Script.Url

Script.Select

When there's a need to look up multiple values from a dataset, and have them available as script values, we can use the Script.Select element. This will take an entire row from an external select template, rather than having to do one value at a time. 

 

Select Layer

Prerequisites

We will assume you have:

  • Watched the Navigate video, or are already familiar with the Simpler user interface.
  • Setup the Simpler environment, either on your computer or a development environment for your organization.

Overview

The Select layer provides services for selecting raw data stored in a variety of formats, including csv, sql, excel, text, and xml. The Select layer also provides services for synchronizing data, so that data stored in low performance formats (such as text files on the web) can be transferred into higher performance data stores (relational databases, for example).

Generating the Select Template

The Select template is the mechanism for the Select Layer to do its work. It can call various forms of raw data by calling the child elements within it. 

Start Page

The Start page is our starting point as developers. Among other essential administrative needs, It is also where template builders can be accessed, which will be used to create our first datapp select template.

Select Template Builder

Generating a select template is quite simple. From the Start page, under the header Select Template Builders, choose the type of data source your data is stored in (CSV, SQL table, XLS) and click on the link.

selecttemplatebuilder.PNG

In this example, we will create a Select template from a SQL object (a view or table).

1. Click SQL Table link.

 

selecttemplatebuilder_sqltable.PNG

2. Enter the Data Source, Schema, and object Name.

  • Data Source - Alias for the SQL connection string, defined in configuration.xml.
  • Schema - SQL schema for your SQL object (dbo is the typical default)
  • Name - SQL object name (could be table or view)
  Note: The Data Source "simpler_rpt" in this case is an alias for an underlying connection string. Rather than having to specify the connection string every time, we just call this alias to get data from this SQL data source.

Note: The Data Source "simpler_rpt" in this case is an alias for an underlying connection string. Rather than having to specify the connection string every time, we just call this alias to get data from this SQL data source.

 

3. After filling out the three above fields, click Build. A new browser tab should open with the generated XML code as the output:

Note: The original data for the trees dataset in this tutorial was taken from Data.SFGov.Org

4. Save the contents of this output as an xml file somewhere in the root application folder, naming it select.xml.

Note: For organizational purposes, it's strongly recommended that this file be saved in the /datapp folder, and then in a sub-directory named after the dataset being queried. Since this dataset is related to "Trees" data, we will put the select template in /datapp/trees.

The Select XML File

We should already be familiar with the general XML declarations outlined in the Hello World! section, so we will elaborate on the elements and attributes of the Select template in particular. 

Select 

The <Select> template is the parent for selecting and projecting raw data. It has the potential to select various data formats, represented by the child elements of the <Query> element. The <Query> child element must always follow the <Select> template declaration.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AuthenticatedUsers" Description="Select" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite Template.xsd">
  <Select>
      <Query>
      <!--Declare Query type here-->
      </Query>
  </Select>
</Template>

Query

The <Query> element will always accompany the <Select> element when creating a Select template. The <Query> element is an abstract query that must be followed by a <[DataFormat]> element. Sibling queries will be appended together, or unioned, while child queries will iterate over the parent query results, similar to a for loop.

Select.Query.[DataFormat]

There are numerous child elements of Select.Query that indicate the different data formats to be queried. However, for this tutorial, we will focus on the <SqlTable>.

Choosing <SqlTable> as the Select.Query child element will indicate a SQL object is the dataset format. Continuing with our dbo.Trees template we generated above, let's explore the elements and attributes of a typical datapp Select template.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AuthenticatedUsers" Description="" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite Template.xsd">
  <Select>
    <Query>
        <SqlTable DataSource="simpler_rpt" Schema="dbo" Name="trees" AutoFilter="Y" AutoSelect="Y" AutoSort="Y" SampleOnly="{SampleOnly}" Group="{Group}">
            <!--Declare Column elements here-->
          <SqlTable>
        </Query>
    </Select>
</Template>
Select.Query.SqlTable Attributes:

  • DataSource – Indicates alias of data source connection string to be selected from.
  • Schema – specifies the schema of the data source to be selected from.
  • Name – The name of the table or view to be selected from.
  • AutoFilter – Indicates whether column filters can be specified by the query string. If AutoFilter is “Y”, the value of the column name's query string parameter is used as the filter.
  • AutoSelect – Indicates whether column selection can be specified by the query string. If AutoSelect is “Y”, the value of the ‘Select’ query string parameter is used to determine which columns are sorted.
  • AutoSort – Indicates whether sorting can be specified by the query string. If AutoSort is “Y”, the value of the 'Sort' query string parameter is used to determine which columns are sorted.
  • SampleOnly – Indicates whether to process only a sample of the results.
  • Group – Indicates whether the results will be grouped. When enabled, data is grouped by all non-aggregated fields.

Sibling Queries

We may call as many <Query> elements as children of <Select> as are necessary. If they are siblings, meaning they share the same parent, these queries will be appended together, or unioned.

The only requirement to append queries together is that they must have the same underlying column names selected and in the same order, but they may otherwise come from disparate data sources, such as a different SQL instance, or a different data format all together (i.e., CSV and a SQL Object).

In the snippet below, notice how there is a <Query> element on line 4 and on line 9, but their <SqlTable> DataSource attributes are pointing to two different aliases on line 5 and 10. Assuming these two SQL objects have the same underlying column selections, they will be appended together in the datapp.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AuthenticatedUsers" Description="" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite Template.xsd">
  <Select>
    <Query>
        <SqlTable DataSource="simpler_rpt" Schema="dbo" Name="trees" AutoFilter="Y" AutoSelect="Y" AutoSort="Y" SampleOnly="{SampleOnly}" Group="{Group}">
            <!--Declare Column elements here-->
        <SqlTable>
    </Query>
    <Query>
        <SqlTable DataSource="test_db" Schema="dbo" Name="trees" AutoFilter="Y" AutoSelect="Y" AutoSort="Y" SampleOnly="{SampleOnly}" Group="{Group}">
            <!--Declare Column elements here-->
        <SqlTable>
    </Query>
   </Select>
</Template>

Child Queries

When there is a child <Query> element to a parent <Query> (Select.Query.Query), the results of the parent query will iterate over the child query for each result.

For example, you may iterate over a lookup table, using one or more of the columns to pass onto the child query for the final results of the Select template.

In the below snippet, notice how the parent <Query> on lines 4 and 5 is pointing to a <SqlTable> Name of dbo.tree_types in the same database, the results of which will iterate over its child <Query>, querying dbo.trees, on lines 8 and 9. The results of dbo.trees will be altered by the results of dbo.tree_types, before the user ever has any interaction with the datapp.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AuthenticatedUsers" Description="" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite Template.xsd">
  <Select>
    <Query>
        <SqlTable DataSource="simpler_rpt" Schema="dbo" Name="tree_types" AutoFilter="Y" AutoSelect="Y" AutoSort="Y" SampleOnly="{SampleOnly}" Group="{Group}">
            <!--Declare Column elements here-->
        <SqlTable>
        <Query>
            <SqlTable DataSource="simpler_rpt" Schema="dbo" Name="trees" AutoFilter="Y" AutoSelect="Y" AutoSort="Y" SampleOnly="{SampleOnly}" Group="{Group}">
                <!--Declare Column elements here-->
            <SqlTable>
        </Query>
    </Query>
   </Select>
</Template>

Column

The <Column> element defines a column in the dataset. It is not a required child element in any Select.Query.[DataFormat], but excluding a specific column selection will default to selecting all underlying columns in the dataset.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AuthenticatedUsers" Description="" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite Template.xsd">
  <Select>
    <Query>
        <SqlTable DataSource="simpler_rpt" Schema="dbo" Name="trees" AutoFilter="Y" AutoSelect="Y" AutoSort="Y" SampleOnly="{SampleOnly}" Group="{Group}">
            <Column Name="TreeId" />
            <Column Name="Genus" />
            <Column Name="Species" />
            <Column Name="Cultivar" />
            <Column Name="OtherPartOfName" />
            <Column Name="CommonName" />
            <Column Name="Diameter" />
            <Column Name="Height" />
            <Column Name="CrownWidth" />
            <Column Name="DatePlanted" />
            <Column Name="Condition" />
            <Column Name="PlantingSiteId" />
            <Column Name="StreetAddress" />
            <Column Name="StreetName" />
            <Column Name="HasTaxRoll" />
            <Column Name="HasMeter" />
          </SqlTable>
        </Query>
    </Select>
</Template>
Some Select.Query.[DataFormat].Column Attributes:

  • Name – The identifier of the column in the result set.
  • Type – Specifies the data type of the column in the result set. If compatible, source data will be converted to the specified type. (ex. Type= “Number”).
  • Value - A script that computes the value of th column.

Calculated Columns

Besides those columns that exist in the data source, we can also create calculated columns from Select.Query.[DataFormat].Column element, and using the Value attribute. This allows us to build additional columns on the fly, through some combination of existing columns in the Select template. The new Column element can be placed anywhere alongside its sibling Column elements, however for clarity, they often are placed following the column or columns that the new column is comprised of.

In the example below, we create a new column called "Radius" in line 13, which calculates the tree radius by dividing the Diameter by 2. Note that calculated columns must always be defined using script notation "{}", so that concatenation, math, and conditional values can be created.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AuthenticatedUsers" Description="" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite Template.xsd">
  <Select>
    <Query>
        <SqlTable DataSource="simpler_rpt" Schema="dbo" Name="trees" AutoFilter="Y" AutoSelect="Y" AutoSort="Y" SampleOnly="{SampleOnly}" Group="{Group}">
            <Column Name="TreeId" />
            <Column Name="Genus" />
            <Column Name="Species" />
            <Column Name="Cultivar" />
            <Column Name="OtherPartOfName" />
            <Column Name="CommonName" />
            <Column Name="Diameter" />
            <Column Name="Radius" Value="{Diameter / 2}" />
            <Column Name="Height" />
            <Column Name="CrownWidth" />
            <Column Name="DatePlanted" />
            <Column Name="Condition" />
            <Column Name="PlantingSiteId" />
            <Column Name="StreetAddress" />
            <Column Name="StreetName" />
            <Column Name="HasTaxRoll" />
            <Column Name="HasMeter" />
          </SqlTable>
        </Query>
    </Select>
</Template>
calculatedcolumnselect.PNG

Notice, the calculated "Radius" column is a whole number rounding to the nearest integer, rather than showing decimal places. Formatting such as this are addressed in the Schema section of the Select layer.

Schema

Note that so far we have only specified our datapp column selection in Select.Query.[DataFormat], and have not mentioned the topic of formatting. Formatting in the Compose and Search layers, as well as other functionality, are controlled from the metadata assigned in the Schema element (Select.Schema) of the Select template.

While Schema is not a required element of the Select template, it is almost always used, as this metadata drives the core look-and-feel of the datapp. On line 25 in the example below, notice the <Schema> element only has the Title attribute assigned, which drives the title on the compose and search layers. If we do not assign the Schema Title attribute, the datapp will default to taking the file name or object name of the data source, which is not very user-friendly.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AuthenticatedUsers" Description="" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite Template.xsd">
  <Select>
    <Query>
        <SqlTable DataSource="simpler_rpt" Schema="dbo" Name="trees" AutoFilter="Y" AutoSelect="Y" AutoSort="Y" SampleOnly="{SampleOnly}" Group="{Group}">
            <Column Name="TreeId" />
            <Column Name="Genus" />
            <Column Name="Species" />
            <Column Name="Cultivar" />
            <Column Name="OtherPartOfName" />
            <Column Name="CommonName" />
            <Column Name="Diameter" />
            <Column Name="Radius" Value="{Diameter / 2}" />
            <Column Name="Height" />
            <Column Name="CrownWidth" />
            <Column Name="DatePlanted" />
            <Column Name="Condition" />
            <Column Name="PlantingSiteId" />
            <Column Name="StreetAddress" />
            <Column Name="StreetName" />
            <Column Name="HasTaxRoll" />
            <Column Name="HasMeter" />
          </SqlTable>
        </Query>
     <Schema Title="Trees"/>
    </Select>
</Template>
selectschematitle.PNG

Schema.Column

Typically, we will add much more metadata to the Schema section. Namely, we will have a Select.Schema.Column element for every Select.Query.[DataFormat].Column element declared above. In the next snippet below, on lines 26-42, we see that we have done just that, with various metadata attributes to modify the format and functionality of the column.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AuthenticatedUsers" Description="" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite Template.xsd">
  <Select>
    <Query>
        <SqlTable DataSource="simpler_rpt" Schema="dbo" Name="trees" AutoFilter="Y" AutoSelect="Y" AutoSort="Y" SampleOnly="{SampleOnly}" Group="{Group}">
            <Column Name="TreeId" />
            <Column Name="Genus" />
            <Column Name="Species" />
            <Column Name="Cultivar" />
            <Column Name="OtherPartOfName" />
            <Column Name="CommonName" />
            <Column Name="Diameter" />
            <Column Name="Radius" Value="{Diameter / 2}" />
            <Column Name="Height" />
            <Column Name="CrownWidth" />
            <Column Name="DatePlanted" />
            <Column Name="Condition" />
            <Column Name="PlantingSiteId" />
            <Column Name="StreetAddress" />
            <Column Name="StreetName" />
            <Column Name="HasTaxRoll" />
            <Column Name="HasMeter" />
        </SqlTable>
     </Query>
     <Schema Title="Trees">
           <Column Name="TreeId" Title="Tree|ID" />
           <Column Name="Genus" Title="Genus" Width="8" />
           <Column Name="Species" Title="Species" Width="8" />
           <Column Name="Cultivar" Title="Cultivar" Width="8" />
           <Column Name="OtherPartOfName" Title="Other|Part|Of|Name" />
           <Column Name="CommonName" Title="Common|Name" />
           <Column Name="Diameter" Title="Diameter" DecimalPlaces="1" />
           <Column Name="Radius" Title="Radius" DecimalPlaces="1" />
           <Column Name="Height" Title="Height" DecimalPlaces="1" />
           <Column Name="CrownWidth" Title="Crown|Width" DecimalPlaces="2" />
           <Column Name="DatePlanted" Title="Date|Planted" />
           <Column Name="Condition" Title="Condition" />
           <Column Name="PlantingSiteId" Title="Planting|Site|ID" />
           <Column Name="StreetAddress" Title="Street|Address" Assist="Y" />
           <Column Name="StreetName" Title="Street|Name" Assist="Y" />
           <Column Name="HasTaxRoll" Title="Has|Tax|Roll" />
           <Column Name="HasMeter" Title="Has|Meter" />
     </Schema>
    </Select>
</Template>
These <Column> elements must have the same Name identifier as those defined in Select.Query.[DataFormat].Column, in order for the metadata assigned to represent a selected column.

Notice the various attributes declared: Title, Width, DecimalPlaces, and Assist. These are just a subset of the attributes available in Select.Schema.Column, all of which represent optional metadata to be applied to a column.

Notice the complementary Column for "Radius", which now has the decimal places to display the exact value of this calculated column.

selectschemacalculatedcolumndecimal.PNG

The <Link> is another important child element of the Schema section (Select.Schema.Link). The <Link> declares a hyperlink to be added to the result set, loaded at the end of the column list. This can be a relative link to another datapp, or an external link to a third party website. They can be literal URLs, or use the value of one or more columns in the result set to script the parameters of a dynamic URL.

<Link Name="TestLink" Url="{'/datapp/trees/compose.html?TreeId=', TreeId}" Text="Test Link"/>
In the above example, we have created a mock URL that will pass the "Tree ID" to a relative URL within the same datapp website. We specified a unique Name attribute, as well as the Url and the Text to be displayed in the results. Here is how this <Link> appears in a datapp, after the last column specified in Select.Query.[DataFormat]:

selectschemalink.PNG

Schema Build Types

A key metadata attribute of Select.Schema is the BuildType attribute. This attribute dynamically assigns the Select template to the desired build of the Compose and Search layers.

Metadata as Dynamic Template

The Schema metadata will be interpreted by the framework build templates, to dynamically generate the compose ands search layers of a datapp. This metadata will be added to the schema structure and format of compose and search UIs, without needing to generate compose and search template files with the Start page Template Builders.

Any metadata added in select.xml will be maintained if you do in fact decide to create compose.xml and search.xml files at a later time (using the Start Page Template Builders). Once these templates are created, however, all modifications thereafter must be made in compose.xml or search.xml, since these files override Select.Schema once they exist.

The datapp build type is discussed in more detail in the Compose section, next in this tutorial.

Compose Layer

Overview

The Compose layer provides services for turning raw data into output that people can easily comprehend. The compose layer retrieves, merges, summarizes, and formats data from the Select layer. The Compose layer is designed to handle large datasets efficiently.

Build Templates

In our Simpler framework environment, the /bin/build.zip contains the default build templates that create the layers of a datapp: select, compose, and search. Below is a look into compose build types. 

Build Types

We have the option to build templates as Basic or Advanced. Think of the build type as a default starting point of a datapp, derived from the dataset schema in the Select template (already created).

Basic vs Advanced

Within the default build templates in /bin/build.zip, the differences between the basic table vs. advanced table are quite simple:

  • Compose Basic Table

    • Allow strictly filter and sort functionality; filtering on column values, and sorting on column headers

    • Appropriate for lookup-oriented datasets 

  • Compose Advanced Table

    • Same as basic, but also allows grouping and aggregating by string data type columns, and totaling of numeric columns

    • Used for more analytical, summarization and drill-down datasets

    • Advanced compose are the best starting point to build highly customized compose tables of a datapp (examples of this under “Use Cases for Advanced Build” section below)

Assigning Build Type

Method 1: From the Select Template: BuildType Attribute 

The build type can be specified using the Select.Schema.BuildType attribute. The possible values are "Basic" or "Advanced". By specifying this attribute in select.xml, we will assign the select template to either the basic or advanced build template, which will dynamically generate the appropriate build of compose.xml and search.xml. If the BuildType attribute is not assigned, the datapp will default to a Basic build.

<Schema Title="Trees" BuildType="Advanced">

This attribute dynamically generates an advanced (or basic) datapp on-the-fly in the user's browser, based on the metadata assigned in Select.Schema, rather than physically creating a compose XML file in the datapp directory.

Method 2: Compose Template Builders 

Alternatively, from the Start page we can generate a compose template using the Template Builders. Selecting "Basic Table" is the equivalent of assigning the BuildType attribute to "Basic", and selecting "Advanced Table" is the equivalent of assigning it to "Advanced".

composebuilder.PNG

After clicking "Advanced Table" we come to the form below. Here, we provide the relative URL to the select template we are creating a advanced table template for. Click Build.

buildadvancedcompose.PNG

This process will generate a compose template XML file: 

composetemplate.PNG

Right click in your browser and select "Save As...", saving the compose.xml template to the datapp folder directory alongside its appropriate select.xml. 

composedirectory.PNG

Once created, we are not restricted by that starting point, whether we chose basic or advanced table, and may make the template as custom as necessary. 

There are two primary reasons to opt to generate a compose.xml file:

  1. The compose template dynamically-generated from the BuildType method has nearly everything needed, but we want to make a few custom changes that are outside the limits of Select.Schema.
  2. You need to make a wholly custom datapp, with features that go beyond the default layout of a basic or advanced build. 

Tip: Once these templates are created, however, all modifications thereafter must be made in compose.xml, since these files override Select.Schema once they exist. For this reason, we should be sure to have as many metadata and formatting attributes assigned in select.xml before we create a compose.xml file.

Use Cases for Advanced Build

While there are many reasons to curate a datapp with advanced compose and search templates, the following are common use cases we may want to apply.

Multiple Subqueries

Sometimes, an advanced compose template may need to pool data together from multiple queries and sources. With this need, in comes the <Script.Url> element, as seen in the example below:

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AuthenticatedUsers" Description="" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite Template.xsd">
  <Compose>
    <Table>
        <Script.Url Identifier="SelectUrl" BaseUrl="{Url.Path}" Name="select.xml">
            <Parameter Name="TreeId" />
            <Parameter Name="Genus" />
            <Parameter Name="Species" />
            <Parameter Name="Cultivar" />
            <Parameter Name="OtherPartOfName" />
            <Parameter Name="CommonName" />
            <Parameter Name="Diameter" />
            <Parameter Name="Radius" />
            <Parameter Name="Height" />
            <Parameter Name="CrownWidth" />
            <Parameter Name="DatePlanted" />
            <Parameter Name="Condition" />
            <Parameter Name="PlantingSiteId" />
            <Parameter Name="StreetAddress" />
            <Parameter Name="StreetName" />
            <Parameter Name="HasTaxRoll" />
            <Parameter Name="HasMeter" />
            <Parameter Name="Sort" />
            <Parameter Name="SortDescending" />
            <Parameter Name="SampleOnly" />
            <Parameter Name="SampleSize" />
      </Script.Url>
    </Table>
  </Compose>
</Template>

The <Script.Url> allows us to call select templates from anywhere within the application root directory, using the template’s relative path. By default, the primary select template is the one in the shared directory path of the compose template at hand (signified by BaseUrl="{Url.Path}" notation above, which calls the path of the template’s URL). However, we can add an arbitrary number of additional <Script.Url> elements to a compose template, calling data sources for specific needs, such as:

  • Title lookups to assign column headers, or descriptions lookups for code values

  • Generate dynamic URLs to other datapps or websites using ID or key fields

  • UNION together datasets with the same column schema

  • Calculated Columns, derived in all or in part from this outside dataset

For example, using the Trees dataset above, let's say we wanted to create a dynamic link to Google Maps using the StreetAddress field above. We will design the link so that when you click on the link of the StreetAddress cell, it takes you to a map of the tree's location. 

In the snippet below is our <Script.Url> to create this Google Maps link. Like the <Script> element, it can be defined as globally or locally as needed in the XML template. Notice that this is a script with a hard-coded literal at the end. Since all addresses are in the city of San Francisco, we add this to the end of the address for the Google Maps search.

<Script.Url Identifier="MapUrl" BaseUrl="https://www.google.com/maps/" > 
    <Parameter Name="place" Value="{StreetAddress, ' San Francisco, CA'}" /> 
</Script.Url>

Further down the XML document, in the Compose.Table.DataSet.Column element, you will see the array of columns that the Compose Template Builder generated. We will place this as the Link attribute for the StreetAddress column.

<Column Name="StreetAddress" Link={MapUrl}>
    <Title Text="Street|Address" PredefinedLink="Sort" />
</Column>

Notice that the Link is a scripted value (signified by curly brace "{}" script notation), and that it is assigned the Script.Url identifier of MapUrl.

Now, when a user clicks on any given Street Address, it will link to the address in Google Maps, rather than the default functionality of filtering the dataset on the cell's value.

linktest.PNG
googlemap.PNG

Calculated Columns

Calculated columns are those derived conditionally, and which do not exist in the primary source dataset as it is selected from SQL, a CSV, or elsewhere. They can be derived in many ways, such as concatenating string values or mathematically combining numeric values, conditionally or as literals. However, one of the most extensible ways to calculate columns is using the multiple subqueries functionality, through the <Script.Url>.

Using a parameter or set of parameters from the primary select template, we can call an external select template by passing a parameter with the same identifier. If the identifier names are the same and there is external data found, data will be returned from the external select template.

To execute the external dataset and return its results, we wrap the bracket (“[]”) script notation around the Script.Url Identifier, and place it as the Compose.Table.Dataset.Column Value attribute.

For example, let's say we had another datapp in the same root directory related to assessed values. Using the StreetAddress field again, we can pull in the assessed values for all the StreetAddresses where there is an asssessed value in the external datapp. Then, we can select the value and bring it into our dataset. We will first create another <Script.Url> to call the external template, and then return the results as a column in the compose template we are working in.

<Script.Url Identifier="ValueUrl" BaseUrl="/datapp/values/" Name="select.xml" > 
    <Parameter Name="StreetAddress" />
    <Parameter Name="Select" Value="AssessedValue" />
</Script.Url>

Notice our two parameters above. We want to pass the StreetAddress, and the Select parameter. Select is a keyword when used as a parameter, which only selects the field or fields that are specified in a comma-separated list. In this case, we are passing "AssessedValue" as the Select parameter value.

Now, returning to the Compose.Table.Dataset.Column section of the compose template, we will create an arbitrarily-named new field to pull in the external assessed value (if it exists).

<Column Name="AssessedValue" Value="{[ValueUrl] when HasTaxRoll='Y'}" >>
    <Title Text="Assessed Value"/>
</Column>

Notice the square brackets around the ValueUrl identifier, which represents our call to the external Assessed Values datapp. The square brackets will execute the URL if HasTaxRoll=Y, iterating through each row and passing the two parameters along.

When this url is executed, it will pass through all non-null parameters to build the url as follows:

/datapp/values/select.xml?StreetAddress=1314+47TH+AVE&amp;Select=AssessedValue

Thus, if an AssessedValue exists, externally, we will see it in our compose table.

calculatedcolumncompose.PNG

Value Attribute in Compose vs Select

Value vs AggregateValue

 

Group Element

Compose in Aggregate vs non-Aggregate

Group only

Group is a header and a footer, and detail is the unaggregated dataset.

Aggregate Only

 

Group and Aggregate

Total

The Total element is used to total a column's values, which will show in the footer of the grouping.  

Aggregate=Y will set Grand Total as sum of all rows above (default is "Y"). If Aggregate=N, then it will calculate based on other values in the total.

Custom Links vs Predefined Links

Iterative Elements ("Datasets", "Columns", "Groups")

Column Format Attributes

Percentage Columns with Number Format

Color

Format

Width

Fixed

Compose List Template

 

 

 

 

Menu System

 

Prerequisites

We will begin with a few assumptions:

  • Watched the Navigate video, or are already familiar with the Simpler user interface.
  • Setup the Simpler environment, either on your computer or a development environment for your organization.
  • Created a Basic datapp, or datapps have already been created on your site.

Overview

The menu can be easily customized. A site has two options for the menu:

  • Either all menu items can be displayed on a single Home page, or
  • You can create multiple menu pages with tabs along the top of the page. This tabular menu are ideal if we need to break menus out by department or by software application, and can also include drop-down submenus.
  Notice the tabular menu along the header banner, as well as the the content of the current "Trees" tab.

Notice the tabular menu along the header banner, as well as the the content of the current "Trees" tab.

Each tab has a heading, subheading, and menu groups that are organized using columns. Each menu group contains one or more links, or URLs, that are jumping off points into the data. 


Tabular Menu Configuration

To create a tabular menu, we need to verify the setting in the configuration.xml file is set.

configurationfile.PNG
  • If the TabularMenu setting exists but is set to "N", we must switch it to "Y" to activate the tabular menu system.
  • If the <Setting> is not defined, we need to define it and set it to "Y".

<!--Custom Frame Settings-->
<Setting Name="FrameStyle" Value="Custom" />
<Setting Name="FrameColor" Value="#fff" />
<Setting Name="HeadingColor" Value="#000" />
<Setting Name="LogoUrl" Value="/images/ss_icon_medium.png" />
<Setting Name="LogoWidth" Value="50" />
<Setting Name="LogoHeight" Value="50" />
<Setting Name="TabularMenu" Value="Y" />

Your datapp site is now activated to allow for the tabs across the header banner.


Folder Structure

Home Menu

The Home menu is derived from the home.xml file in the root of the Simpler folder. Whether we are using a single menu or tabular menu, home.xml should always be placed in the root. 

Tabular Menu

There is also a menu folder located in the root directory where the menu for each tab will be saved, if we choose to create a tabular menu. The menu file name(s) must be named as we’d like the tabs to appear to the end user.

  Notice the Home menu (home.xml) is in the root directory, while any menu tabs would be place in the menu folder. (above)

Notice the Home menu (home.xml) is in the root directory, while any menu tabs would be place in the menu folder. (above)

For example, if we want two tabs named "Properties" and "Trees", create a properties.xml and a trees.xml menu and save them in the menu folder. The framework will automatically parse the file name and proper-case it, for the end interface. 

tressproperties.PNG
tabmenusexample.PNG

If you have a multi-word tab, use an underscore ("_") where a space would be. The system will convert that underscore to a space automatically. See the "Tree Inventory" tab above.

treeinventory.PNG
treeinventorylive.PNG

Sub-menus

To add a sub-menu to a tab, which renders as a drop-down list when the mouse hovers over the tab, do the following:

  1. create a sub-folder in the /menu directory with the same name as the parent menu file.
  2. Then, create a new menu file in this folder, naming the file as we’d like the sub-menu to appear to the end user.
treesubmenudirectory.PNG

For example, to create a sub-menu called “California Trees” for Trees tab, create a new folder called "trees" in /menu directory ("/menu/trees"), and create a new menu called california_trees.xml in this folder.

californiatreessub.PNG
californiatreessublive.PNG

The Menu XML File

We should already be familiar with the general XML declarations outlined in the Hello World! section, so we will elaborate on the elements and attributes of the Menu templates in particular. 

Present

The <Present> template is the parent for the <Menu> element, since the menu is in the Present layer of the framework. All of the elements that define the menu frame, groups, and links must reside inside of the <Present> template.


<?xml version="1.0" encoding="utf-8"?>
<Template Access="AuthenticatedUsers" Description="Home" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite Template.xsd">
  <Present>
      <!--Declare Menu here-->
  </Present>
</Template>

Frame

The <Frame> element defines various page items such as the title, as well as some of the icons along the sidebar, like the Search icon.

framelive.PNG

The Title attribute of the <Frame> controls the title on the browser tab, as well as the frame banner title. In the example below, the Title is being created from the MenuTitle script, which selects the file name of the current URL and proper-cases it. So in this case our trees.xml menu, is taking the file name, "Trees", as the Title.

<Script>
    MenuTitle {String.ProperCase(String.FormatIdentifier(String.Replace(Url.GetName(Url.This),Url.GetExtension(Url.This),'')))}
</Script>
<!--The Frame should take dynamic MenuTitle for Menu templates-->
<Frame Title="{MenuTitle}"/>
Note: for full understanding of how theMenuTitlescript is calculated, see the Script Function reference page.

Menu

The <Menu> element defines a Menu template. It will set the number of columns organized on the menu, the menu's title, and an auxiliary description text under the title.

menulive.PNG

By default, the Title attribute uses the same MenuTitle script calculated for the Frame's title, as seen below:

<Menu Title="{MenuTitle}" Columns="1" Description="This menu contains data used to catalog trees in the city of San Francisco." >

Menu Groups

The content of a menu is organized into columnar groups, which display links to datapps under a related category, or subject area.

menugrouplive.PNG

Each menu group on the page has its own <Group> element, which then contains at least one <Link> element for that group.

<Group Column="1" Description="Group One" Access="Administrators">
    <Link Description="Link One" Url="/datapp/folder/search.html"/>
</Group>

  • The Column attribute indicates which column on the page to place the group in. If there is more than one group in that column, the groups are displayed in the order they are listed in the file.
  • The Description will appear as the heading for that group.
  • The Access attribute is not typically used, but can be included in order to restrict access to specific roles or individuals.
    • Access may be controlled at the Menu, Group, or Link level, by specific user name or by user role. For more on access, see our Access page.

See example below incorporating multiple groups in a column, and multiple columns: 

menugrouplive2.PNG
<Menu Title="{MenuTitle}" Columns="2" Description="This menu contains data used to catalog trees in the city of San Francisco.">
  <Group Description="Group One" Column="1">
      <Link Description="Link One" Url="/datapp/folder1/search.html"/>
  </Group>
  <Group Description="Group Two" Column="1">
      <Link Description="Link One" Url="/datapp/folder2/search.html"/>
      <Link Description="Link Two" Url="/datapp/folder3/search.html"/>
  </Group>
  <Group Description="Group Three" Column="2">
      <Link Description="Link One" Url="/datapp/folder4/search.html"/>
      <Link Description="Link Two" Url="/datapp/folder5/search.html"/>
  </Group>
</Menu>

Dynamic Links

Unlike the more common <Link>, <DynamicLinks> will generate links depending on some condition, or external list of links from elsewhere.

As an example, let's look at Shortcuts, which reside on the Home menu.

First we must declare our <Script.Url> elements, to grab user-specific Shortcuts and Shared Shortcuts. More on the <Script.Url> here.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AuthenticatedUsers" Description="Home" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite Template.xsd">
    <Present>
        <Script>
      MenuTitle {String.ProperCase(String.FormatIdentifier(String.Replace(Url.GetName(Url.This),Url.GetExtension(Url.This),'')))}
        </Script>
    <Script.Url Identifier="SelectUserShortcutsUrl" BaseUrl="/administer/shortcuts/select.xml">
        <Parameter Name="Select" Value="{'ShortcutName,Category,Url'}"/>
        <Parameter Name="Sort" Value="{'Category,ShortcutName'}"/>
        <Parameter Name="Category"/>
    </Script.Url>
    <Script.Url Identifier="SelectSharedUserShortcutsUrl" BaseUrl="/administer/shortcuts/shared/select.xml">
        <Parameter Name="Select" Value="{'ShortcutName,Category,Url'}"/>
        <Parameter Name="SharedWith" Value="{User.Id}"/>
        <Parameter Name="Sort" Value="{'Category,ShortcutName'}"/>
    </Script.Url>

Next we declare our DynamicLinksUrl for our "Shortcuts" and "Shared Shortcuts" menu groups, which will then query the aforementioned <Script.Url> elements by their Identifier, as highlighted in lines 20 and 23 below.

Then, using <DynamicLinks> element, we iterate through this external URL and assign the link Description and Url based off the query results.

<?xml version="1.0" encoding="utf-8"?>
<Template Access="AuthenticatedUsers" Description="Home" xmlns="http://simplersystems.com/suite" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://simplersystems.com/suite Template.xsd">
  <Present>
      <Script>
      MenuTitle {String.ProperCase(String.FormatIdentifier(String.Replace(Url.GetName(Url.This),Url.GetExtension(Url.This),'')))}
       </Script>
    <Script.Url Identifier="SelectUserShortcutsUrl" BaseUrl="/administer/shortcuts/select.xml">
        <Parameter Name="Select" Value="{'ShortcutName,Category,Url'}"/>
        <Parameter Name="Sort" Value="{'Category,ShortcutName'}"/>
        <Parameter Name="Category"/>
    </Script.Url>
    <Script.Url Identifier="SelectSharedUserShortcutsUrl" BaseUrl="/administer/shortcuts/shared/select.xml">
        <Parameter Name="Select" Value="{'ShortcutName,Category,Url'}"/>
        <Parameter Name="SharedWith" Value="{User.Id}"/>
        <Parameter Name="Sort" Value="{'Category,ShortcutName'}"/>
    </Script.Url>
    <!--Lines 1-16 merged in from previous snippet for full context-->
    <Frame Title="{MenuTitle}" />  
    <Menu Title="Home" Columns="3" >
        <Group Description="Shortcuts" DynamicLinksUrl="{SelectUserShortcutsUrl}" ManageUrl="/administer/shortcuts/manage.html" Column="2">
            <DynamicLinks Description="{ShortcutName}" Url="{Url}" />
        </Group>
        <Group Description="Shared Shortcuts" DynamicLinksUrl="{SelectSharedUserShortcutsUrl}" ManageUrl="/administer/shortcuts/shared/manage.html" Column="3">
            <DynamicLinks Description="{ShortcutName}" Url="{Url}" />
        </Group>
       </Menu>
    </Present>
</Template>
shortcutslive.PNG

In the above screenshot, we have 3 shortcuts and 1 shared shortcut populated from our "Trees" demo datapp, none of which were explicitly coded into the menu. Rather, all the links were dynamically populated from querying our Shortcut datasets.

For more on Shortcuts, see our Shortcuts page.

Syncs

Overview

A sync template is one part of the entire sync process that is used to take data from the source database or data file and place it into the Simpler database on a schedule, typically every night. In this exercise, we examine the template that takes a data file and copies the data into the database. 

Components

Synchronize templates are made up of two major components: 

  • Source Data 

  • Destination Table 

The source data can be any query that you would normally use in a select template. For this example we'll be using a query based on csv files since it's easy to run locally and manipulate with a text editor. 

The destination is defined by its SQL table name, the table columns, and the action that should be taken. 

Actions 

Here is the most basic sync template. It uses a query to a CSV file, a database table that has the same schema as the CSV file, and has the action "truncateappend". The template will truncate the table and append it with the contents of the CSV file. This type of template is useful for small tables where reloading the entire table is not very time consuming (less than 10,000 rows). The destination will always match the csv exactly since all the data is replaced. Keep in mind that if a row is deleted from the csv file that it will also be removed from the destination table. Templates that use the "truncateappend" or "append" actions do not require key attributes on the columns since they don't read anything from the destination table before inserting. 

An equivalent action for this example would use the "insertupdatedelete" action. Using this approach requires adding key attributes to the appropriate columns so that the framework can detect changes between the source and destination rows. This example will read the entire table and only update when necessary, so its performance is more appropriate for medium sized datasets (less than 100,000 rows). 

Insert/Update/Delete

Any combination of the words "insert" "update" and "delete" can also be used to modify the behavior of the sync. The most common actions are: 

  • "insert": only new rows are inserted, existing rows in the destination are not modified 

  • "insertupdate": rows are inserted and updated, but not deleted 

Advanced Options

Updatable = N 

Setting the "Updatable" attribute of a column to "N" will tell the framework not to update that column even if the source and destination data are different. An example where this feature is useful is when tracking insertion timestamps. The current timestamp can be included in the source data and will be inserted for new records, but will not be updated for existing records. This feature can also be useful for inserting default values that might be changed by the user within the application. 

Filters 

The filter attribute can be used to restrict the amount of data that is being compared. This is especially useful if the source data is partitioned or if dataset too large to be efficiently queried with a single query (greater than 100,000 rows). It functions like the normal sync, but just on a subset of the destination table. The filters used on the destination should always match the filters on the source data. If the destination is filtered, but the source isn't, it will cause the framework to insert rows that might already be there. If the source is filtered, but the destination isn't then the framework may delete rows unnecessarily (if delete is included in the action). 

 

Tips and Tricks 

Delete a Row 

Want to delete a single row? Use an empty source query, the "delete" action, and a filter that specifies the single row. The destination will return a single row and since the source is empty, it will remove it. 

All New Data 

Is your source guaranteed to only contain new rows? If there's no possibility of duplicates with the destination then use the "append" option instead of "insert". It's significantly faster since it does not perform any comparisons.

Remote Sync

Remote Sync Client 

Remote synchronization is used when the Simpler Systems application is hosted on the Simpler servers.  

The remote sync client can be installed on any server or workstation that can reach the target data source and also has internet access. The sync client is a lightweight standalone .net executable. The sync process consists of the following steps: 

  1. The Task Scheduler on the server or workstation runs a task to start the program [filepath]\bin\ss.exe “/remotesync.xml” (action) at the specified time (trigger). 

  2. The program gets a list of queries from the Simpler server from the file located at [project_name]/remotesync/remotequeries.xml.  

  3. The program runs each query and saves the data as a CSV files to the specified temporary data path. 

  4. The files are then securely transferred to the Simpler server using HTTPS. 

  5. Once all queries have completed and transferred, the client triggers the [project_name]/synchronize.xml task which performs all the necessary tasks to update the database using the newly uploaded data. Depending on the data, this could include truncating and replacing the existing table or only inserting new rows of data. 

  6. The new data is now available to the datapp(s). 

Configuration File 

The configuration.xml contains information about the data source and settings for data paths, authentication, etc. The DataSource tag contains the application login information which controls the security on what data is available for this process. 

Tasks

Overview 

Task templates are used to execute one or more templates in sequence. They can be used to automate complex tasks or to perform multiple actions from a single user action. 

Task Template

The simplest task is made of a Task element with one or more Step elements within it. Both the Task and Step elements require a “Name” attribute. The names are for informational purposes only and appear in the task log. In the simple example, a Url attribute is also required for each step. Running this simple task will execute each Url in order and then return a blank page. 

 

Redirects

If the Task is being called by a button on a present template then usually redirection is required to show the results or return the user to a landing page. This can be accomplished by either passing a “RedirectUrl” parameter when the task is called, or by specifying a “RedirectUrl” attribute on the task element. 

Saving Responses

Sometimes tasks need to save the results of a task to a file. This can be accomplished by specifying the “ResponsePath” and “ResponseFileName” attributes on the step. An example where this would be useful is a task that emails a report to a user. Frist the result must be saved to a file and then attached to the email. 

Inline Root Elements 

For tasks with just a few steps or tasks with steps that are never called individually, it can be useful to put the root templates inside the step element itself. If the template is included, the step does not need a Urlattribute. This approach is equivalent to having each step in a separate file and specifying the Url, but can make organization and maintenance easier since everything is in a single file. 

Async Tasks 

If the order of step execution does not matter, then asynchronous tasks can be used. This allows the task to run multiple steps simultaneously. It can be enabled by setting the “Async” attribute of the task to “Y” and setting the “AsyncThreads” attribute to the number of tasks that can be running at the same time. This will allow some tasks to complete much faster than usual, but the order of each step is unknown. 

Logging 

In the The logging can be turned on or off using the “Log” attribute of the Task. Each step can also have its logging turned off with the same attribute.