QML

Query Markup Language


QML is designed to simplify creation of web pages which access databases. It is based heavily on hyperSQL, and steals freely from the ideas of hyperSQL's creators. A qml file, though, looks more like an html file than a computer program, the idea being to make it simpler for web page designers to use. In fact, a qml file is html with some additional tags; anything which is not part of a qml tag is simply sent to the browser as html (except that macros and variables in the text are interpolated into variable references (any word with a $ in front of it). The inclusion of html text obviates the need for hyperSQL statements such as banner, header, footer, etc.

The current release of QML is version 2.0.

Variables

QML variables are set either by being passed to the script as CGI parameters (typically having been set by a qml_input in a previous screen), or set in a qml_output construct to the current values of the database fields.

QML tags

Most QML tags accept parameters in the form of attribute=value pairs. There are a few attributes which don't take values. In all tags, the value must be double-quoted if it contains white space or the character ">". In some tags, the value is a comma-separated list of parameters - white space may be left around the commas, but if it is, the list must be quoted.

The following tags are supported; features shown in red are new in QML 2.0:

<qml_usedatabase [name=foo] [default] database=ocid login=foo server=bar password=hello>
This sets parameters for subsequent database access. If the "default" attribute is specified, or if the name attribute is not specified, the database will be the default database. Any number of databases may be specified, but there may be at most one default database.

<qml_screen name=foo [file="foo/bar"] [default]> and </qml_screen>
These tags delineate a QML screen. Text inside the screen will be triggered only if the name of the screen matches the target specified by the previous submit, or if the screen has the "default" attribute and no target has been specified. Text or tags which lie outside any screen will be printed, in the order encountered, regardless of what target is specified (but note that not all QML tags may be used outside of screens). The "file" attribute allows screens to reside in individual files; if it is used, no /qml_screen tag is used with it. Use of the file option will speed loading of large interfaces, since only the necessary screens need be parsed. Screens may not be nested.

<qml_condition name=foo [op=or] sql="...">
Sets a condition which is tied to a variable (which will usually be set in a previous screen, typically via a qml_input). Conditions are used to construct sql "where" clauses for inputs which allow multiple values. For example, consider the following qml code:

<qml_condition name=genus sql="genus like '$genus'">
<qml_input name=genus sql="select genus where $genus">

If a previous qml_input sets genus to the values Felis or Escherichia, the condition will be expanded to "(genus like 'Felis' or genus like 'Escherichia')", and the sql for the qml_input will be expanded to "select genus where (genus like 'Felis' or genus like 'Escherichia')". The default for op is "or", but "and" may also be used. If you aren't using multiple inputs or refineable queries, you probably don't need conditions. If you place conditions outside of any qml screen, you can use them in multiple screens (eg, to generate sql both for a refinable input and an output).

<qml_table name=foo [database=foo] sql="...">
Performs a database access and stores the result for later use in a qml_input, qml_output, or qml_download statement. Some advantages over supplying the sql directly in the input or output statement are:

<qml_input name=genus sql="..." [type=radio|checkbox] [multiple] [size=n] [blank="..."] [default="..."] [label="..." ] [value="..."]>
or
<qml_input name=genus table=foo [type=radio|checkbox] [multiple] [size=n] [blank="..."] [default="..."] [label="..." ] [value="..."]>
Acts just like an input statement in hyperSQL, except that it is always a database access (since other input types can be done as straightforward html), and it allows radio buttons and checkboxes. The "multiple" and "size" attributes are passed through to the resulting html, and the browser will choose between a pulldown or scrolled list accordingly. If the "table" attribute is set, this construct uses the contents of the existing table; otherwise it queries the database (after substituting the current variable values into the sql) to produce its own table. The "label" attribute is a string which, after variable substitution, is used as the label for the selection list. The "value" attribute is used as the value in the list (i.e., is actually sent to the next form as a cgi param). The "blank" attribute just supplies a label to use when the database returns a blank (null or whitespace only) value. The "default" attribute selects which, if any, value is pre-selected. It may take on several different values: MIN, MAX, FIRST, LAST, NONE, or an arbitrary string. MIN and MAX, typically used with numeric values, select the smallest or largest value of the returned set. FIRST or LAST select the first or last value in the list as it is returned from the database (useful with SQL's "order by" clause). NONE specifies no default selection, and any other string is used as a label for a wildcard value. If the clause is omitted, the default is a wildcard with '** All values **' as the label. The qml_input tag may be used only inside a QML screen.

<qml_output sql="..." [[index=bar] start=0]> and </qml_output>
or
<qml_output table=foo [[index=bar] start=0]> and </qml_output>
If the "table" attribute is set, this construct uses the contents of the existing table; otherwise the "sql" attribute must be set, and QML will query the database (after substituting the current variable values into the sql) to produce its own table. In either case, it then loops through the rows of the table. On each pass through the loop, it sets variables to the fieldnames of the table, substitutes them into the enclosed text, and prints it. These are nestable and variables are lexically scoped. If the "index" attribute is set, it is the name of a variable which will contain the index of each iteration through the loop; the "start" attribute may be used to set the starting value of the variable (eg, 0, 1, a, etc). Note: though qml is case-sensitive, Oracle is case-sensitive upper. If using Oracle, variable names must be in all caps inside the qml_output construct.

<qml_if param=xxx,yyy> and </qml_if>
Replaces the SUPPRESS_IF_EMPTY construct of hyperSQL. Text between the tags is output only if all specified variables are set. Nestable. Note that, before 2.0, the keyword for the param attribute was "var" - this is still accepted, but "param" is preferred. The change has been made for the sake of consistency with other constructs. "param" and "var" are now synonyms in all QML tags where they occur.

<qml_unless param=xxx,yyy> and </qml_unless>
The negation of a qml_if. Text between the tags is output only if none of the specified variables are set. Nestable. You can use these along with a qml_quit to require that the user make a selection for particular inputs. I'd really like to replace this with a more flexible version of qml_if. See qml_if for discussion of the param attribute.

<qml_ifselected name=foo field=bar> and </qml_ifselected>
This tag allows the script developer to test the value of a list returned by a group of related inputs. In a typical case, a select list for use in an sql statement would be constructed using a series of html checkboxes:

<input type=checkbox name=foo value=genus>Genus
<input type=checkbox name=foo value=species>Species

This creates a variable "foo" which can be used in an sql statement:

sql="select $foo from table"

and will select only those items which the user has checked. If the script developer wishes to determine what the user has chosen - say, to create the column headings for an output table - he can use the qml_ifselect tag to look inside the selectlist:

<qml_ifselected name=foo field=genus><th>Genus</th></qml_ifselected>

<qml_link target=yyy param=abc,def>
Creates a link reference - highlighted text which will contact QML and produce the screen specified in the target parameter. Variables which must be set should be given in the param parameter (the values will be taken care of by QML). This tag produces only the text <a href=....>; the script developer must supply the linked text and the closing </a> tag.

<qml_submit target=foo [value="Retrieve Results"]>
Creates a submit button for the current query, formatting it using the query page specified in the "target" attribute. The "value" attribute, if it exists, is used as the label for the button. The qml_submit tag may be used only inside a QML screen.

<qml_refine [value="Refine Query"]>
Creates a button which resubmits the query with the same parameters, but updated with selections made from the current page. This is typically used for refining the query; i.e., eliminating choices which are unavailable due to constraints imposed by other selections. The qml_refine tag may be used only inside a QML screen.

<qml_new [value="New Query"]>
Creates a button which creates a new query form (i.e., which brings up the default screen with the same initial values as when first invoked). The qml_new tag may be used only inside a QML screen.

<qml_macro name=foo text="...">
Interpolates the given text anywhere where the variable $foo is used. Variables are substituted when the macro is expanded, not when it is read (note that this was incorrectly documented in earlier versions of QML). Macros are global - if set inside a qml_output construct, they exist after than construct is egressed.

<qml_set name=foo text="...">
Interpolates the given text anywhere where the variable $foo is used. Variables are substituted when the tag is read (which is the only difference between qml_set and qml_macro).

<qml_forward param=foo,bar,...>
Forwards the given variable to the next screen. This is really just shorthand for a list of html statements of the form:

<input type=hidden name=foo value="$foo">

which are often needed in linked chains of qml screens. The qml_forward tag may be used only inside a QML screen.

<qml_debug [sql=on] [method=get]>
The qml_debug tag sets various parameters to help in debugging. With the sql parameter set (either just "sql" or "sql=on"), html comments are produced showing the sql which is sent to the database server. This can be turned off with "sql=off". The cgi method used to invoke subsequent screens may be set to either "post" (the default, and more secure) or "get" (which shows the passed parameters in the browser window).

<qml_download [type=application/csv] table=foo>
or
<qml_download [type=application/csv] sql="...">
or
<qml_download [type=application/csv]> and </qml_download>
Creates an anchor for a link which will download the specified table as a file of comma-separated values (usable by many spreadsheets). The script developer must supply the text after the anchor link and the closing </a> tag. The last version allows arbitrary constructs enclosed by the tags to produce the file. The type param allows specification of an HTTP Content-Type: header (the default is application/csv).

<qml_quit>
Stop processing qml input.

Things hyperSQL does that qml doesn't do (yet)

Other functionality I'd like to add to qml

Acknowledgements

I am much indebted to Drs. Cherri Pancake and Mark Newsome, and to Joe Hanus and Sherry Pittam, without whom QML wouldn't exist. Mark, with much guidance from Cherri, and much input from Joe and Sherry, thought up all the foregoing database access ideas and implemented them in the original hyperSQL. He then patiently explained to me what they were doing as I subsequently stole his ideas for use in QML. Joe and Sherry listened to me muse a lot and helped me figure out what sort of constructs would be useful and desirable in QML. Thanks, all.