5 The transformer Object

The transformer object allows for traversing an XML Document or an IDM hierarchy, whereby during the traversing semantic actions can be carried out on particular nodes. Through this it is easy to implement a transformation of data. For example, XML data can be transferred into IDM objects or vice versa, XML Documents can be generated from the data contained in IDM objects. Because semantic actions are described through user-defined code, the transformations can have many different forms.

Definition

{ export | reexport } { model } transformer { <Identifier> }
{
  [ <atribute definition> ]
  [ <method definition> ]
}

The following means are available to the IDM programmer regarding the definition of transformations.

Events

None

Children

document

mapping

record

transformer

Parents

application

canvas

checkbox

dialog

doccursor

document

edittext

groupbox

image

import

layoutbox

listbox

mapping

menubox

menuitem

menusep

messagebox

module

notebook

notepage

poptext

pushbutton

radiobutton

record

rectangle

scrollbar

spinbox

splitbox

statictext

statusbar

tablefield

timer

toolbar

transformer

treeview

window

Menu

None

Methods

:action()

:apply()

:select_next()

5.1 Attributes

.document[integer]

.external

.external[integer]

.firstrecord

.label

.lastrecord

.mapping[integer]

.model

.module

.parent

.record[integer]

.recordcount

.root

.scope

.userdata

5.2 Object-specific Attributes

.mapping[integer]

The mapping children can be accessed through the .mapping attribute. The attribute is indexed with the object index (similar to child). The sequence of the mappings within this vector determines the sequence in which nodes are compared to particular mappings during a transformation. The inherited mappings are not taken into this vector. During a transformation, the comparison to these mappings is done at the very end, i.e. the direct instances have priority. This is different in comparison to other inherited child objects within IDM, which are inserted at the beginning of the parent instance’s child vector.

.root

After calling the :apply() method the starting point of the transformation will be stored in this attribute. This makes it possible to decide during a transformation, if the starting point has been reached again, and if the transformation can be stopped.

The following cases should be distinguished:

  • When the Src parameter of the apply method is a document or a doccursor, a string is saved in .root, which describes the corresponding position in the XML tree. The syntax of the string follows the convention, which is used for the .path attribute of the doccursor object (see doccursor object description). Because of this, comparisons to the .path attributes of doccursors are very easy.
  • If the Src parameter of the apply method is an IDM object, this object will be stored in .root. Consequently, in this case, the data type of the attribute is object.

On the basis of the value in the .root attribute, the action and :select_next() methods of the transformer decide what they have to do (see description of these methods).

At the end of the apply method .root is set to void again.

The default value for the attribute is void.

5.3 Object-specific Methods

:apply()

The transformation is initiated with this method. The default implementation of the algorithm is as follows:

  • If the Src parameter is a document or a doccursor object, it is assumed that data from the XML tree should be transferred to the IDM. In the case of a document object, a temporary doccursor object will be created which is used for the navigation within the XML tree. In the pseudo-code below, for the purpose of simplicity it is assumed that a doccursor is passed in Src.

    :apply(anyvalue Src, anyvalue Dest)
    {
      variable object NextObj;
      
      this.root ::= Src.path;
      NextObj := Src;
      while NextObj <> null do
        this:action(Src, Dest);
        NextObj := this:select_next(NextObj);
      endwhile
      this.root ::= null;
      return true;
    }
  • If the Src parameter is an IDM object (except for document and doccursor objects), it is assumed that data from IDM should be transferred to XML or somewhere else. The underlying code is identical to the code above, except that Src is stored in .root instead of Src.path. For example:

    this.root ::= Src;

The apply method can be overwritten (similar to :init()).

:action()

This method is used by the apply method of the transformer (see above) to determine if the current node matches one of the mapping children. If it does, the action method of the mapping object is called.

The action method can be overwritten (similar to :init()).

:select_next()

This method is used by the apply method of the transformer for traversing all nodes of an XML tree or an IDM object hierarchy (see above). The default implementation of this is, that a pre-order sequence is processed by the repeated calls of the method.

The :select_next() method can be can be overwritten (similar to :init()).

5.4 Example

This example can be found in the examples/xml directory.

As XML Document the following file with the name CD-Katalog.xml is used:

<?xml version="1.0" ?>
<CATALOG>
  <CD>
    <TITLE>Empire Burlesque</TITLE>
    <ARTIST>Bob Dylan</ARTIST>
    <COUNTRY>USA</COUNTRY>
    <COMPANY>Columbia</COMPANY>
    <PRICE>10.90</PRICE>
    <YEAR>1985</YEAR>
  </CD>
  <CD>
    <TITLE>Hide your heart</TITLE>
    <ARTIST>Bonnie Tyler</ARTIST>
    <COUNTRY>UK</COUNTRY>
    <COMPANY>CBS Records</COMPANY>
    <PRICE>9.90</PRICE>
    <YEAR>1988</YEAR>
  </CD>
  <CD>
    <TITLE>Maggie May</TITLE>
    <ARTIST>Rod Stewart</ARTIST>
    <COUNTRY>UK</COUNTRY>
    <COMPANY>Pickwick</COMPANY>
    <PRICE>8.50</PRICE>
    <YEAR>1990</YEAR>
  </CD>
</CATALOG>

The data from this file can, for example, be read out as follows:

dialog D {}

window Wi
{
  .title "XML-CD-CATALOG";

  on close { exit(); }

  child treeview Tv
  {
    .xauto 0;
    .yauto 0;
    .style[style_lines]   true;
    .style[style_buttons] true;
    .style[style_root]    true;
    integer CdIdx := 0;

    rule NewCatalog() {
      if this.itemcount = 0 then
        this.itemcount ::= this.itemcount + 1;
      endif
      this.content[this.itemcount] := "CD-Catalog";
      this.open[this.itemcount] := true;
    }

    rule AddCD() {
      this:insert(this.itemcount+1, 4);
      this.CdIdx := this.CdIdx + 1;
      this.content[this.itemcount-3] := ""+this.CdIdx+". CD";
      this.level[this.itemcount-3] := 2;
    }

    rule AddTitle(string S input) {
      this.content[this.itemcount-2] := "Title: " + S;
      this.level[this.itemcount-2] := 3;
    }

    rule AddArtist(string S input) {
      this.content[this.itemcount-1] := "Artist: " + S;
      this.level[this.itemcount-1] := 3;
    }

    rule AddPrice(string S input) {
      this.content[this.itemcount] := "Price: " + S;
      this.level[this.itemcount] := 3;
    }
  }
}

transformer Tr
{

  !! transformer is for taking over data from an XML Document
  !! therefore a doccursor can be expected in Src

  child mapping MCatalog {
    .name "..CATALOG";

    :action() {
      Dest:NewCatalog();
      return true;
    }
  }

  child mapping MCD {
    .name "..CD";

    :action() {
      Dest:AddCD();
      return true;
    }
  }

  child mapping MTitle {
    .name "..CD.TITLE";

    :action() {
      Dest:AddTitle(Src.text);
      return true;
    }
  }

  child mapping MArtist {
    .name "..CD.ARTIST";

    :action() {
      Dest:AddArtist(Src.text);
      return true;
    }
  }

  child mapping MPrice {
    .name "..CD.PRICE";

    :action() {
      Dest:AddPrice(Src.text);
      return true;
    }
  }
}

document Doc {}

on dialog start
{
  Doc:load("CD-Katalog.xml");

  Tv.visible := false;
  Tr:apply(Doc, Tv);
  Tv.visible := true;
}