Von Tcl zu XML

Dieser Abschnitt beschreibt, wie Applikationen über die XML-Schnittstelle des Content Management Servers auf die Daten zugreifen können, die dieser verwaltet. In den Beispielen dieses Abschnitts werden Payloads und Requests nur fragmentarisch wiedergegeben. Wie vollständige Payloads und Requests aufgebaut sind, können Sie dem Abschnitt CRUL-Payloads entnehmen.

Die Funktionen, die über die XML-Schnittstelle verfügbar sind, decken sich im Wesentlichen mit denen der Tcl-Schnittstelle. Sie können also sowohl über die XML-Schnittstelle als auch über Tcl beispielsweise Dateien anlegen oder die Werte von Versionsfeldern abfragen. Dies ist möglich, weil die Tcl-Schnittstelle und der in den Content Management Server eingebaute XML-Parser die gleichen Programmfunktionen aufrufen, um Operationen auszulösen.

Klassen und Instanzen

Um Tcl-Befehle in XML-Fragmente übersetzen zu können, muss man wissen, dass sich jede Befehlsgruppe auf eine Klasse bezieht und dass Klassen Instanzen haben. So bezieht sich die Befehlsgruppe attribute auf die Klasse der Felder, die Befehlsgruppe obj auf Dateien usw. Instanzen dieser Klassen sind die einzelnen Felder bzw. die Dateien. Mit den Befehlen einer Befehlsgruppe kann man sowohl auf eine Klasse insgesamt zugreifen, also beispielsweise auf alle Dateien, als auch auf einzelne Instanzen. So wird mit dem folgenden Befehl die Liste der Felder ausgegeben:

attribute list

Befehle wie list, mit denen auf eine Klasse insgesamt zugegriffen wird, werden Klassenmethoden genannt. create ist ebenfalls eine Klassenmethode der meisten Klassen. Mit create wird zu einer Klasse eine Instanz hinzugefügt:

attribute create name obst type multienum

An diesem Beispiel ist zu erkennen, dass Klassenmethoden Argumente haben können. Fügt man beispielsweise zu einer Klasse eine Instanz hinzu, so muss man die Instanz eindeutig referenzieren können. Dies geschieht bei Feldern über den Namen. Der Name ist eine Eigenschaft (auch "Parameter") eines Feldes, ebenso wie beispielsweise der Typ. Im obigen Beispiel werden der Methode create als Argumente paarweise der Name eines Parameters und dessen Wert übergeben (name = obst sowie type = multienum). Bei vielen Tcl-Befehlen werden Argumente auf diese Weise übergeben.

Instanzen

Bei Tcl-Befehlen, die sich auf eine einzelne Instanz (etwa eine Datei oder einen Benutzer) beziehen, muss der Wert des Parameters angegeben werden, der die Instanz eindeutig identifiziert. Das folgende Tcl-Kommando ermittelt das Passwort des Benutzers mit dem Login mustermann:

user withLogin mustermann get password

In diesem Befehl ist user die Klasse. Die Instanz dieser Klasse, auf die sich der Befehl bezieht, wird durch mustermann eindeutig referenziert. Ein Kommando, mit dem eine Instanz einer Klasse angesprochen wird, hat immer auch ein Subkommando. Das Subkommando spezifiziert, welche Aktion die Instanz durchführen soll. Im obigen Beispiel wurde das Subkommando get verwendet. Mit get kann der Wert einer Instanzvariablen, hier password, ermittelt werden. Im folgenden Beispiel wird mit dem Subkommando set der Ordner festgelegt, in dem sich eine Datei befindet:

obj withId 4912 set parent aPublicationObjectId

Die Datei mit der ID 4912 ist hier die Instanz der Klasse obj, auf die sich das Subkommando set auswirkt. Subkommandos werden Instanzmethoden genannt.

Methoden in XML

Klassenmethoden und Instanzmethoden werden in CRUL-Requests als Elemente kodiert. Das Tag des entsprechenden Elements wird aus dem Klassennamen und dem Methodennamen zusammengesetzt, wobei ein Bindestrich die beiden Komponenten miteinander verbindet:

<attribute-create>
 ... 
</attribute-create>

Mit diesem Element wird ein Feld erzeugt, und die erforderlichen Namen und Werte der zu erzeugenden Instanz werden als Unterelemente angegeben:

<cm-request...>
  <attribute-create>
    <name>Adresse</name>
    <type>string</type>
  </attribute-create>
</cm-request>

Wie der entsprechende Tcl-Befehl (attribute create name Adresse type string) erzeugt diese Anfrage eine Antwort, die den Namen des angelegten Feldes enthält:

<cm-response ...>
  <cm-code numeric="0" phrase="ok">
    <attribute>
      <name>Adresse</name>
    </attribute>
  </cm-code>
</cm-response>

In der Tcl-Schnittstelle wird bei attribute create der Name des angelegten Feldes ohne Zusätze zurückgegeben. Im Antwortdokument der XML-Schnittstelle dagegen ist der Rückgabewert im Klassennamen-Element (hier attribute) als Parameter-Element (hier name) enthalten. Grundsätzlich liefern die XML-Schnittstelle und die Tcl-Schnittstelle bei Instanziierungen den Wert des Primärschlüssels der erzeugten Instanz, bei Dateien beispielsweise die ID, bei Benutzern das Login und bei Workflows den Namen.

Instanzmethoden werden auf Instanzen einer Klasse angewendet. In der Tcl-Schnittstelle kann eine Dateiinstanz mit obj withId oder obj withPath, eine Feldinstanz mit attribute withName, eine Workflowinstanz mit workflow withName usw. referenziert werden. Der folgende Tcl-Code setzt bei der Datei mit der ID 4812 den Wert des Feldes title auf Bericht. Dies wird mit der Instanzmethode set erledigt:

obj withId 4812 set title Bericht

Alternativ kann man die Klassenmethode where verwenden, um auf mehrere Instanzen zuzugreifen. where ermittelt eine Liste von Instanzen, bei denen die angegebende Zeichenkette im Wert eines Parameters vorkommt oder mit ihm übereinstimmt. Der folgende Code setzt bei allen Dateien mit der Dateivorlage Notiz den Wert des Feldes journal auf Nein:

foreach id [obj where objClass Notiz] \  {obj withId $id set journal Nein}

In der XML-Schnittstelle wird dieser Tcl-Befehl durch den folgenden Request abgebildet:

<cm-request ...>
  <obj-where>
    <objClass>Notiz</objClass>
  </obj-where>
  <obj-set>
    <journal>Nein</journal>
  </obj-set>
</cm-request>

Natürlich können im obj-set-Element die Werte mehrerer Felder gleichzeitig gesetzt werden. Das obj-where-Element kann ebenfalls mehrere Unterelemente haben, um die zu modifizierenden Instanzen nach Belieben zu selektieren. Dadurch ist es möglich, das obige Beispiel dahingehend zu verfeinern, dass der Wert von journal nur bei Dateien gesetzt wird, die eine Arbeitsversion haben:

<cm-request ...>
  <obj-where>
    <objClass>Notiz</objClass>
    <state>edited</state>
  </obj-where>
  <obj-set>
    <journal>Nein</journal>
  </obj-set>
</cm-request>

Wichtig ist, dass auf die Klassenmethode obj-where eine Instanzmethode (hier obj-set) unmittelbar folgt. Dadurch wird eine Schleife gebildet, in der die Instanzmethode auf jede Instanz angewendet wird, die mit dem where-Element ermittelt wurde. Bei allen Klassen außer obj ist das where-Element das einzige, mit dem Instanzen ermittelt werden können. Es bildet sowohl die with-Logik (withName, withId, withPath) als auch die list-Klassenmethoden des Tcl-Interfaces ab. Bei obj gibt es neben where die Klassenmethode search, mit der man über die Search Cartridge nach CMS-Dateien suchen kann.

Durchsucht man im Tcl-Interface mit der where-Methode die Namen von Instanzen, so erhält man diejenigen, deren Name die angegebene Zeichenkette enthält. Im Unterschied dazu liefert das folgende XML-Fragment nur die Feldinstanz, deren Name exakt mit dem angegebenen String übereinstimmt:

<cm-request ...>
  <attribute-where>
    <name>attr</name>
  </attribute-where>
  <attribute-set>
    <editField parameter="type">textField</editField>
  </attribute-set>
</cm-request>

Dieses Verhalten ist darin begründet, dass es im XML-Interface die Selektoren withName, withId und withPath nicht gibt. Ihre Funktion wird dadurch abgebildet, dass der Parameter name in where- und search-Elementen eine exakte Suche auslöst. Um dennoch Instanzen selektieren zu können, deren Name eine Zeichenkette nur enthält (anstatt mit ihr übereinzustimmen), steht der Parameter nameLike zur Verfügung. So löscht das folgende XML-Fragment alle Workflows, deren Name spezial enthält:

<cm-request ...>
  <workflow-where>
    <nameLike>spezial</nameLike>
  </workflow-where>
  <workflow-delete/></cm-request>

Mit where ist es ebenfalls möglich, alle Instanzen einer Klasse zu ermitteln. Diese Aufgabe hat im Tcl-Interface die Klassenmethode list, die es im XML-Interface nicht gibt. Stattdessen verwendet man ein leeres where-Element wie im folgenden XML-Fragment, mit dem man alle Dateien freigeben kann (sofern es keine Gründe gibt, die dies verhindern):

<cm-request ...>
  <obj-where/>
  <obj-release/>
</cm-request>

In der Tcl-Schnittstelle kann dies mit dem folgenden Code erledigt werden:

foreach id [obj list] {obj withId $id release}

Instanzvariablen auslesen

Mit der Instanzmethode get können die Parameter der Instanzen ausgelesen werden, die mit dem vorausgegangenen where-Element ermittelt wurden. Im folgenden Beispiel wird bei allen Dateien mit der Vorlage Notiz der Wert des Feldes journal abgefragt:

<cm-request ...>
  <obj-where>
    <objClass>Notiz</objClass>
  </obj-where>
  <obj-get>
    <journal/>
  </obj-get>
</cm-request>

Alle unmittelbaren und mittelbaren Unterelemente eines get-Elements müssen leer sein, weil der Content Management Server die Elementhierarchie im get-Element wie eine Schablone verarbeitet. Für jede mit dem where-Element ermittelte Instanz wird die Schablone mit den entsprechenden Werten ausgefüllt und in den Antwort-Request eingefügt. Dies wird im Abschnitt Requests als Schablonen und die Darstellung der Ergebnis-Daten erläutert.

Instanzmethoden-Argumente

Instanzmethoden können Argumente haben. So gibt es im Tcl-Interface beispielsweise die Methode isOwnerOf. Mit ihr kann man feststellen, ob ein Benutzer der Verwalter eines Benutzers oder einer Benutzergruppe ist:

user withLogin mustermann isOwnerOf admins

Die Instanzmethoden isOwnerOf hat als Argument das Login eines Benutzers oder einen Gruppennamen (hier den Gruppennamen admins). Argumente werden als Attribute des entsprechenden XML-Elements kodiert. Der obige Tcl-Befehl hat also die folgende Übersetzung:

<cm-request ...>
  <user-where>
    <login>mustermann</login>
  </user-where>
  <user-get>
    <isOwnerOf group="admins"/>
  </user-get></cm-request>

Das obige Beispiel veranschaulicht einen wichtigen Unterschied zwischen Tcl-Interface und XML-Schnittstelle: man kann nur mit der get-Methode lesend auf Instanzen zugreifen. Folglich müssen alle lesenden Instanzmethoden innerhalb eines get-Elements (hier user-get) verwendet werden. Solche Instanzmethoden sehen dadurch wie Instanzvariablen (wie name bei Feldern oder realName bei Benutzern) aus, können sich jedoch von solchen durch Argumente unterscheiden. So hat isOwnerOf genau ein (variables) Argument, nämlich group oder user. Argumente von Instanzmethoden werden (wie im obigen Beispiel gezeigt) als Tag-Attribute (nicht etwa als Unterelemente) spezifiziert.

Dieses Verfahren der Kodierung von Instanzmethoden als Instanzvariablen ist bei allen Klassen identisch. Das folgende Beispiel zeigt, wie die Instanzmethode permissionGrantedTo der Klasse obj verwendet wird:

<cm-request...>
  <obj-where>
    <objClass>publication</objClass>
  </obj-where>
  <obj-get>
    <permissionGrantedTo permission="permissionWrite" user="elton"/>
  </obj-get></cm-request>

Untereigenschaften referenzieren

Die Klasse der Felder ist die einzige im Content Management Server, deren Instanzen Untereigenschaften haben: bei jedem Feld kann man das Eingabefeld definieren, mit dem der Benutzer den Wert des Feldes eingeben soll. Die Definition eines Eingabefeldes besteht aus fünf Parametern, unter anderem dem Typ des Eingabefeldes, das im Tcl-Interface folgendermaßen gesetzt wird:

attribute withName attr editField set type popup

Im XML-Interface werden die Parameter mit dem Tag-Attribut parameter im editfield-Tag referenziert. Das folgende Beispiel zeigt die Entsprechung des obigen Befehls im XML-Interface:

<cm-request...>
  <attribute-where>
    <name>attr</name>
  </attribute-where>
  <attribute-set>
    <editField parameter="type">popup</editField>
  </attribute-set></cm-request>

Analog dazu werden Eingabefeldparameter folgendermaßen ausgelesen:

<cm-request ...>
  <attribute-where>
    <name>attr</name>
  </attribute-where>
  <attribute-get>
    <editField parameter="type"/>
  </attribute-get>
</cm-request>

Suchanfragen formulieren

Wenn Sie die Search Cartridge installiert und auf der Redaktionsseite eingebunden haben, so können Sie sowohl im Tcl-Interface (mit dem Kommando obj search) als auch in der XML-Schnittstelle (mit obj-search) nach Dateien suchen. Wie Suchanfragen aufgebaut sein müssen, ist in der Tcl-Referenz sowie der Dokumentation zum Search Server und der XML-Referenz beschrieben.

Auf das obj-search-Element können die gleichen Elemente folgen wie auf obj-where, d. h. Sie können die von der Suchfunktion ermittelten Dateiinstanzen anschließend mit einer Instanzmethode wie obj-get oder obj-set weiterverarbeiten.

Dimensionen von Werten

Im Content Management Server stehen manche Werte von Eigenschaften in mehreren Sprachen zur Verfügung. So haben beispielsweise Versionen sowohl ein allgemeines Feld title als auch sprachspezifische Varianten dieses Feldes (title.english usw.). Diese "Fähigkeit" einer Instanz, mehrere "Auslegungen" oder Varianten einer Eigenschaft haben zu können, nennt man eine "Dimension". Das Feld title einer Version oder eines Feldes, einer Dateivorlage und eines Workflows hat die Dimension "Sprache". Auf die Varianten von Eigenschaften können Sie mit einem Tag-Attribut im entsprechenden XML-Tag zugreifen.

"Sprache" ist zurzeit die einzige Eigenschaften-Dimension im Content Manager. Sie steht bei den title-, helpText - und den description-Parametern der meisten Klassen zur Verfügung. Die Sprachdimension wird mit dem lang-Tag-Attribut spezifiziert:

<cm-request ...>
  <obj-where>
    <objClass>document</objClass>
  </obj-where>
  <obj-get>
    <title lang="en"/>
  </obj-get>
</cm-request>

Einfache und strukturierte Werte

Die Werte von Instanzen-Eigenschaften können einfache Werte oder strukturierte Werte sein. Ein einfacher Wert ist eine Zeichenkette, ein strukturierter Wert ist eine Liste oder ein Dictionary.

Während "Zeichenkette" ein gängiges Konzept ist, bedürfen "Liste" und "Dictionary" einer Erläuterung. Eine Liste ist eine geordnete Menge beliebig vieler Elemente. Jedes Element wird in der XML-Schnittstelle durch ein listitem-Element dargestellt:

<cm-request ...>
  <attribute-where>
    <name>channels</name>
  </attribute-where>
  <attribute-addEnumValues type="list">
    <listitem>books</listitem>
    <listitem>computing</listitem>
    <listitem>music</listitem>
  </attribute-addEnumValues>
</cm-request>

Im obigen Beispiel werden zum Feld channels (bei dem wir voraussetzen, dass es vom Typ enum oder multienum ist) die drei möglichen Werte books, computing und music hinzugefügt. Die Ordnung in einer solchen Liste ergibt sich aus der Reihenfolge der Listenelemente. Sie ist im Allgemeinen nicht relevant.

Ein Dictionary ist eine nicht geordnete Menge beliebig vieler Zuordnungen von Werten zu Namen. Jede Zuordnung wird durch ein dictitem-Unterelement repräsentiert, das wiederum aus einem Namen (key) und einem Wert (value) besteht:

<myDictionary>
  <dictitem>
    <key>name</key>
    <value>theName</value>
  </dictitem>
  <dictitem>
  ...
  </dictitem>
</myDictionary>

Dictionarys, die mit dictitem-Elementen strukturiert sind, kommen im XML-Interface recht selten (beispielsweise bei Zugriffen auf Benutzereinstellungen) vor. Die meisten Name-Wert-Paare werden in CRUL mit dem Namen als Elementname und dem Wert als Inhalt des Elements kodiert.

Der Wert eines Dictionary-Elements und eines Listenelements kann eine Zeichenkette oder wiederum eine Liste oder auch ein Dictionary sein.