Lesson 7 -- Pattern Based Interpreters, Working With XML Data

Lesson 7
Working With XML Data
Pattern-Based Generator-Interpreter

7.1 XML data formats in GME
7.2 The pattern-based generator-interpreter

7.1 XML data formats in GME

GME uses XML data format for two purposes:

- to represent paradigms (by default, these files have the extension ".xmp"), and
- to provide an export format for modeling projects.

Although the directly useable, native formats for both the paradigms and the modeling projects are different, XML files are essential for GME as a common language for paradigms (for example, the output of the metamodel interpreter) and as a paradigm-independent data storage format.

Since the XML files are handled by automated procedures (such as "File/Update through XML..."), ordinary users will never need to look at the contents of these files. But for advanced GME users, a glimpse of the XML data is usually very instructive; it reveals a lot of information about the internal logic of GME. Please note, however, that the formats of these files are not published and may change without notice at any time.

XML may also be used to perform changes on a modeling project that would be too tedious to implement through the user interface. For example, if a model contains the words "Mr." and "Mrs." in the "Title" attribute for a large number of people, translating this model into German requires changing the words to "Herr" and "Frau" respectively. The pedantic approach for such a task is to write an interpreter. This is truly the most efficient option if there are a large number of projects to be converted. But if there is only one modeling project, the easiest way would probably be to use the Search/Replace function of an ordinary text editor.

Changes in the metamodel may also render an existing XML file invalid. Suppose a certain model used to be able to contain an atom, which is not allowed in the recent version of the paradigm. Due to indentations, containment relationships are readily apparent in the XML file; it is fairly easy to locate the offending atom and to delete it or move it to anther location.

The following example has been written to explain a little of the format and logic of the GME XML files. Let us consider a simple metamodel (Fig 7.1).

Fig 7.1 A simple metamodel

When a metamodel is interpreted, an XML paradigm file (which by default is named "tmeta.xmp" for this metamodel) is created. As a paradigm defines metaobjects, the XML file defines metaentities: a Folder, (the root folder), two attributes, a model and an atom. The child entities (like "Prisoner") are usually defined outside the container model ("Prison"); therefore, the paradigm representation is a flat hierarchy. To express containment, models have <role> elements which refer to the contained objects ("Prisoner", in this case). The role and the referred kind are often given identical names. <model>s also have <aspect> elements, which list all the visible roles as <part> elements.

Note that paradigm files refer to the file "edf.dtd" for definitions of the document type (DTD).

`<?xml version="1.0"?>
<!DOCTYPE paradigm SYSTEM "edf.dtd">
<paradigm name ="tmeta">
<comment> Generated by the Meta2000 interpreter </comment>
<folder name = "RootFolder" metaref = "1000" rootobjects = "Prison " >
<attrdef name="Age" metaref = "1007" valuetype = "integer" defvalue = "">
<dispname></dispname>
</attrdef>
<attrdef name="Weight" metaref = "1001" valuetype = "double" defvalue = "">
<dispname></dispname>
</attrdef>
<atom name = "Prisoner" metaref = "1002" attributes = "Age Weight">
<regnode name = "namePosition" value ="4"></regnode>
</atom>
<model name = "Prison" metaref = "1003" >
<regnode name = "namePosition" value ="4"></regnode>
<role name = "Prisoner" metaref = "1008" kind = "Prisoner"></role>
<aspect name = "Roomies" metaref = "1009" >
<part metaref = "1010" role = "Prisoner" primary = "yes" linked = "no"></part>
</aspect>
</model>
</folder>
</paradigm>`

The following file is the data file. It is a concrete prison named "SingSing", with three inmates. Hierarchy is strictly followed here: the Prison is contained by the root folder, and inmates are contained by the Prison. FCOs (atoms, models, etc.) have "kind" and "role" attributes as well as child elements: their <name> property and a number of <attribute>s. There are also a relatively high number of <regnode> elements; these are mechanisms used internally by GME to store positions and other visualization information. Even for a model with 5 objects, the XML export file is about 50 lines (or 50 XML elements) long. Since the two XML file formats obviously differ, the document type definition is also different ("mga.dtd" for this format).

`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE project SYSTEM "mga.dtd">
<project guid="{00000000-0000-0000-0000-000000000000}" cdate="Fri Sep 21 12:16:55 2001" mdate="Fri Sep 21 12:19:36 2001" metaguid="{F079E422-DEAD-BEEF-FEED-DAD000000000}" metaname="tmeta">
<name>SingSing</name>
<comment></comment>
<author></author>
<folder id="id-006a-00000001" kind="RootFolder">
<name>SingSing</name>
<model id="id-0065-00000001" kind="Prison">
<name>Prison</name>
<atom id="id-0066-00000001" kind="Prisoner" role="Prisoner">
<name>#96514</name>
<regnode name="PartRegs" isopaque="yes">
<value></value>
<regnode name="Roomies" isopaque="yes">
<value></value>
<regnode name="Position" isopaque="yes">
<value>164,39</value>
</regnode>
</regnode>
</regnode>
<attribute kind="Age">
<value>30</value>
</attribute>
<attribute kind="Weight">
<value>190</value>
</attribute>
</atom>
<atom id="id-0066-00000003" kind="Prisoner" role="Prisoner">
<name>#14325</name>
<regnode name="PartRegs" isopaque="yes">
<value></value>
<regnode name="Roomies" isopaque="yes">
<value></value>
<regnode name="Position" isopaque="yes">
<value>38,39</value>
</regnode>
</regnode>
</regnode>
<attribute kind="Age">
<value>55</value>
</attribute>
<attribute kind="Weight">
<value>171</value>
</attribute>
</atom>
<atom id="id-0066-00000002" kind="Prisoner" role="Prisoner">
<name>#99325</name>
<regnode name="PartRegs" isopaque="yes">
<value></value>
<regnode name="Aspect" isopaque="yes">
<value></value>
<regnode name="Position" isopaque="yes">
<value>290,39</value>
</regnode>
</regnode>
</regnode>
<attribute kind="Age">
<value>15</value>
</attribute>
<attribute kind="Weight">
<value>155.5</value>
</attribute>
</atom>
</model>
</folder>
</project>`

7.2 The pattern-based generator-interpreter

The pattern based generator-interpreter is probably the most convenient way to provide simple interpretation (e.g. data export to different file formats) of GME2000 models. The pattern based generator is paradigm-independent, so it can be used with any kind of models, only a pattern file needs to be created.

The generator-interpreter reads a pattern file, and based on its contents generates output to one or several files. The pattern file may contain plain text, which is copied to the output verbatim, and special pattern instructions (macros like $Name and funtions like $!EVAL_FORALL), that are evaluated, and their result is inserted into the output. Pattern instructions have arguments. A significant type of arguments are text arguments, which can again contain any mixture of plain text or pattern instructions.

The pattern is always evaluated in the context of an FCO, which is used when evaluating pattern instructions. Some pattern instructions ($!EVAL_WITH, and $!EVAL_FORALL) change the context when evaluating their text arguments.

7.2.1 The macro language

$<varname>
Evaluates variable or attribute <varname> and returns its value to the output.

- First, the set of variables is searched for <varname> (variables are defined by $!DEFINE, see below).
- Next if <varname> is "Name", then returns the name of the current object.
- If <varname> is "Kind", then returns the kind of the current object.
- Otherwise reads and returns the current object's attribute identified by <varname>
- If none is defined, report error.

$!EVAL_FORALL( <fieldspec>, <textarg> )
Gets any number (including 0) of objects identified by <fieldspec>, iterates through them, and evaluates <textarg> in their context. <fieldspec> may contain one of the following specifications:

R: |  | the children of this role,
Parent | the parent of this object if any,
Type | the basetype of this object if any,
Ref | the target of a reference object if any,
Dst:<rolename> | the destination peer(s) of all connections to the current object,
Src:<rolename> | the source peer(s) of all connections to the current object.

$!EVAL_WITH( <fieldspec>, <textarg> )
Gets the single object identified by <fieldspec> and evaluates <textarg> in its context, then returns the result. See above the specification of <fieldspec>.

$!IFEMPTY( <textarg1>, <textarg2> )
If <textarg1> evaluates to an empty string, evaluates <textarg2> and returns the result.

$!IFDEFAULT( <textarg1>, <textarg2> )
If <textarg1> does not have a default value, evaluates <textarg2> and returns the result.

$!TOFILE( <textarg> )
Closes current output file, and starts writing to the file specified by <textarg>

$!DEFINE( <varname>, <textarg> )
Creates or redefines the variable identified by varname to contain the current value of textarg.

$!POSTINCR( <varname> )
Increments variable varname by 1, and returns its original value (its value must be legible as a number).

$!SEQ( <textarg1>, <textarg2>, ... )
Evaluates textargs one by one and appends their result .

7.2.2 Separating verbatim text and pattern instructions

The text of the pattern file is copied verbatim to the output, unless a pattern instruction (beginning with $) is detected. A pattern instruction must fit into a single line, but physical lines can be merged into a single logical one by specifying \ as the last character of the first line. ‘$’ and ‘\’ characters are produced using ‘\$’ and ‘\\’ respectively.

Text arguments within functions are evaluated in a similar fashion, but

- they may be surrounded by double quotes ( " " ) to indicate the borders of the string. Otherwise, a string is terminated by the first unquoted ‘,’ or ‘)’.
- ‘\t’ and ‘\n’ is converted to tab and newline characters in the generated output.

7.2.3 Examples

The following example generates an XML output from the networking example.

`$!DEFINE("_FILENAMEBASE", "$!IFDEFAULT("FileNameBase","$(Name)")")
$!TO_FILE("$!IFDEFAULT("OutputPath","")$(_FILENAMEBASE).xml")
<?xml version="1.0" encoding="UTF-8"?>
<$Name>
$!EVAL_FORALL("R:Folder","<Folder>\n<Name>$Name</Name>\n<FolderContainment>\n\
$!EVAL_FORALL("Src:FolderContainment","<$Kind>$Name</$Kind>\n")\
</FolderContainment>\n</Folder>\n")
$!EVAL_FORALL("R:Model","<Model>\n<Name>$Name</Name>\n<Containment>\n\
$!EVAL_FORALL("Src:Containment","<$Kind>$Name</$Kind>\n")\
</Containment>\n</Model>\n")
$!EVAL_FORALL("R:Set","<Set>\n<Name>$Name</Name>\n<SetMembership>\n\
$!EVAL_FORALL("Src:SetMembership","<$Kind>$Name</$Kind>\n")\
</SetMembership>\n</Set>\n")
$!EVAL_FORALL("R:Reference","<Reference>\n<Name>$Name</Name>\n<ReferTo>\n\
$!EVAL_FORALL("Dst:ReferTo","<$Kind>$Name</$Kind>\n")\
</ReferTo>\n</Reference>\n")
$!EVAL_FORALL("R:FCO","<FCO>\n<Name>$Name</Name>\n<Inheritance>\n\
$!EVAL_FORALL("Dst:BaseInheritance","\
$!EVAL_FORALL("Dst:DerivedInheritance","<$Kind>$Name</$Kind>\n")")\
</Inheritance>\n</FCO>\n")
$!EVAL_FORALL("R:Atom","<Atom>\n<Name>$Name</Name>\n<Inheritance>\n\
$!EVAL_FORALL("Dst:BaseInheritance","\
$!EVAL_FORALL("Dst:DerivedInheritance","<$Kind>$Name</$Kind>\n")")\
</Inheritance>\n</Atom>\n")
$!EVAL_FORALL("R:Connector","<Connector>\n<SourceToConnector>\n\
$!EVAL_WITH("Src:SourceToConnector","<$Kind>$Name</$Kind>\n")\
</SourceToConnector>\n<ConnectorToDestination>\
$!EVAL_WITH("Dst:ConnectorToDestination","<$Kind>$Name</$Kind>\n")\
</ConnectorToDestination>\n<AssociationClass>\n\
$!EVAL_WITH("Dst:AssociationClass","<$Kind>$Name</$Kind>\n")\
</AssociationClass>\n</Connector>\n")
</$Name>
`

And the next one generates an HTML file from the SF demo.

`$!DEFINE("_FILENAMEBASE", "$!IFDEFAULT("FileNameBase","$(Name)")")
$!TO_FILE("$!IFDEFAULT("OutputPath","")$(_FILENAMEBASE).html") <html>
<head>
<title>GME SF2000Demo - Generated by PatPlugin</title>
</head>
<body>
<h1>PrimitiveParts</h1>
<table align="center" width="600" cellspacing="0" cellpadding="0" border="1">
<tr><td>Item No.</td><td>Name</td><td>Firing</td><td>Script</td><td>Priority</td></tr>
$!DEFINE("INDEX","1")
$!EVAL_FORALL("R:PrimitiveParts","<tr>\n<td>$!POSTINCR("INDEX")</td>\
<td>$Name</td><td>$Firing</td><td>$Script</td><td>$Priority</td>\n</tr>\n")
</table>
<br><br>
<h1>CompoundParts</h1>
$!DEFINE("INDEX","1")
$!EVAL_FORALL("R:CompoundParts",\
"<table align=\"center\" width=\"600\" cellspacing=\"0\" cellpadding=\"0\" border=\"1\">\n\
<tr>\n<th colspan=\"5\" align=\"left\"><b>$Name</b></th>\n</tr>\n\
<tr>\n<td>Item No.</td><td>Name</td><td>Firing</td><td>Script</td><td>Priority</td>\n</tr>\n\
$!EVAL_FORALL("R:PrimitiveParts","<tr>\n<td>$!POSTINCR("INDEX")</td>\
<td>$Name</td><td>$Firing</td><td>$Script</td><td>$Priority</td>\n</tr>\n")\</table>")
<br><br>
</body>
</html>`

<< Previous Lesson |  | Complete List |  | Next Lesson >>