When using a database oriented DTD, a powerful query language is essential to leverage all the power of this. Especially the following features are required.
 
Multiple instances and trees must be queried. This is used for merge and lookup processes
 
Information must be available from anywhere in the trees.
 
Queries must be concatenated so that each object in the result is the base point for new queries.
 
Any arbitrary condition must be applicable at any point
 
There must be a way to keep results of subqueries for later reuse
 
The result of a query can be anything from a single value up to an entire tree structure.
 
It must be possible to establish auxiliary data structures for query optimization (e.g. indexes like in database systems)
 
The results of subqueries are lists or sets which must be handled using set operations (union, intersection).
The following examples use the query language of MetaMorphosis (http://www.ovidius.com) to illustrate how these features are used. The first example () shows concatenated queries with nested conditions (the related instance is shown in . The result of the query is a list of short-name of all parameters with implausible values.
Finding invalid parameters
descendant // consider all descendants [ // for which is true: @f-id-class=="PRM" // Attribute f-id-class is "PRM" AND child // has a child [ // for which is true: ?prm-char // GID is "PRM-CHAR" and child[?min].data // child with GID "MIN" // is greater than one of // the children with GID "TYP" or "MAX" child[?typ | ?max].data ] ] . // for each of those child[?short-name] // use children with GID "SHORT-NAME" . data // for each of those return PCDATA
The next example () shows how multiple instances are queried while data is retrieved from multiple places in each instance. The query is based on the MSRSW.DTD (see ) The result of the query is all contents of all data dictionaries, in other words the united data dictionary.
Merging Data
source("sim.sgm", "impl.sgm") // two sources "sim.sgm" as well as "impl.sgm" .( // for each of those root, // use root // as well as path to ... path("sw-function-spec/sw-function/sw-function-variants/sw-function-variant")). // for each of those // path down to sw-data-dictionary path("sw-data-dictionary-spec/sw-datadictionaries/sw-data-dictionary").contents // for each of those return the contents
The last example (instance shown in , result displayed as , query explained in ) shows how to retrieve all information about a parameter set and to return an entire tree. The result is in fact a tree representing a table structure similar to a CALS table. It also shows how intermediate results can be saved in variables.
MSR-Instance for parameter set
<PRMS> <PRM> <LONG-NAME>Long-name</LONG-NAME> <SHORT-NAME>sn</SHORT-NAME> <DESC>Das ist die Beschreibung des Parameters sn</DESC> <PRM-CHAR> <COND> <P>Bedingung1</P> </COND> <MIN>min-1</MIN> <TYP>typ-1</TYP> <MAX>max-1</MAX> <REMARK> <P>Das ist der Hinweis zur Bedingung 1</P> </REMARK> </PRM-CHAR> <PRM-CHAR> <COND> <P>Bedingung 2</P> </COND> <MIN>min 2</MIN> <TYP>typ-2</TYP> <MAX>max-2</MAX> <UNIT>unit</UNIT> </PRM-CHAR> </PRM> <PRM> <LONG-NAME>Abs-tol-Parameter</LONG-NAME> <SHORT-NAME>atsn</SHORT-NAME> <DESC>Das ist ein abs-tol-parameter</DESC> <PRM-CHAR> <ABS>abs</ABS> <TOL>tol</TOL> <UNIT>unit</UNIT> <REMARK> <P>Das ist die Anmerkung zu abstol</P> </REMARK> </PRM-CHAR> </PRM> <PRM> <LONG-NAME>Textparameter</LONG-NAME> <SHORT-NAME>txt</SHORT-NAME> <PRM-CHAR> <TEXT>Das ist der text des Parameters</TEXT> </PRM-CHAR> </PRM> </PRMS>
The desired result is as follows:

Result of query on parameter set
 

Bezeichnung
Kürzel
Min
Typ
Max
Abs
Tol
Einh.
Hinw.
Long-name
               

 
- Bedingung 1
sn
min-1
typ-1
max-1
   
unit
1.
Long-name
                 
 
- Bedingung 2
sn
min-2
typ-2
max-2
   
unit
 
Abs-tol-Parameter
atsn
     
abs
tol
     
Textparameter
txt
Das ist der text des Parameters
             

The query to achieve this is given in . The interesting point is the fact that the presentation table is specified declaratively, its cells are populated by sub queries retrieving the desired data from the source document.
Query to retrieve a parameter set as a table
|st.table|(*hook:=this) // create the table // keep hook in variable { |st.title|node{*hook._GID | *hook.GID}, // make Title |st.cols|node // define columns { |st.col, @width:="4cm"|node, |st.col, @width:="2cm"|node, |st.col, @width:="1.5cm"|node, |st.col, @width:="1.5cm"|node, |st.col, @width:="1.5cm"|node, |st.col, @width:="1.5cm"|node, |st.col, @width:="1.5cm"|node, |st.col, @width:="2cm"|node, |st.col, @width:="1.5cm"|node }, |st.thead|node // Table head { |st.row|node {|st.entry|node{"Bezeichnung"}, |st.entry|node{"Kürzel"}, |st.entry|node{"Min."}, |st.entry|node{"Typ."}, |st.entry|node{"Max."}, |st.entry|node{"Abs."}, |st.entry|node{"Tol."}, |st.entry|node{"Einheit"}, |st.entry|node{"Hinw."} } }, |st.tbody|*hook // Table body, hooked to parameter-table { |st.row|child .child[?prm-char] // a table row for each prm-char {(*curent:=this).null // save actual prm-char in variable |st.entry, // an entry for title @hjust:="l"|node{(*current.parent.child[?long-name].contents //use cousin long-name | // or *current.parent.gid), // or GID of table element |q.pb|that.child[?cond] .contents // add cond {" - ",contents}}, |st.entry|node{*current.left[?short-name].contents}, // an entry for short-name (|st.entry, // spanned entry for text @w:="9cm",@hjust:="l", @hspan:=6|child[?text]{contents} | // or individual entries for (|st.entry|node{that.child[?min].contents}, // min |st.entry|node{that.child[?typ].contents}, // typ |st.entry|node{that.child[?max].contents}, // max |st.entry|node{that.child[?abs].contents}, // abs |st.entry|node{that.child[?tol].contents}, // tol |st.entry|node{that.child[?unit].contents} // unit ) ), |st.entry|node // entry for remark { that.child[?remark] .(count(parent.parent // number counter for remark .left.child[?prm-char] // count grand cousins .child[?remark] // ,parent .left[?prm-char] // and cousins .child[?remark] )+1||"." ) |null // leave cell blank if // there is no remark } } } }