Start
Unternehmen
Buch-Katalog
Seminare
Leserservice
Comelio-Blog
Datenbanken
SQL
MS SQL Server
Oracle
PHP
UML
C#.NET
XML Schema

Elemente/Attribute

Namensgebung

Hierarchien

Attribut-Orientiertierung

Dokumentmodellierung

Element-Benennung

Bedeutung der Namensgebung

XForms

XSLT

Übersicht

Comelio GmbH
Rellinghauser Straße 10
D-45128 Essen
Deutschland
Fon: 0201-437517-0
Fax: 0201-437517-10
info@comelio.com

Comelio GmbH
Goethestraße 34
D-13086 Berlin
Deutschland
Fon: 030-921019-85
Fax: 030-921019-89
info@comelio.com

Comelio GmbH (Ecos)
Glockengießerwall 17
D-20095 Hamburg
Deutschland
Fon: 040-4689908-91
Fax: 040-4689908-95
info@comelio.com

Comelio GmbH (Ecos)
Mainzer Landstraße 27-31
D-60329 Frankfurt
Deutschland
Fon: 069-2475030-35
Fax: 069-2475030-39
info@comelio.com

Comelio GmbH (Ecos)
Stiglmaierplatz/Dachauer Str. 37
D-80335 München
Deutschland
Fon: 089-2000154-90
Fax: 089-2000154-94
info@comelio.com

Comelio GmbH (Ecos)
Liebknechtstr. 33
D-70565 Stuttgart
Deutschland
Fon: 0711-252534-20
Fax: 0711-252534-24
info@comelio.com

Comelio-Blog > XML Schema > Hierarchien

Eltern-Kind-Strukturen in XML Schema

Eine sehr einfache Technik, XML-Dokumente durch geschickte Modellierung mit Hilfe von XML Schema für die Verarbeitung mit XSLT zu optimieren, liegt in der ausdrücklichen Betonung der Eltern-Kind-Strukturen. Dieser Artikel zeigt, welche Vorteile sich durch die Modellierung solcher Strukturen für die Verarbeitung ergeben und zeigt an einem kurzen Beispiel, wie man bei der Modellierung vorgehen kann.

Kontakt

Anrede* Herr Frau
Vorname*
Nachname*
Firma
E-Mail*
Tel-Nr.
Bereich*
Freitext

XML Schema und XSLT: Eltern-Kind-Strukturen in XML

Bereits im letzten Beispiel hatte man eine wesentliche Strukturierung des Dokuments durch die Verwendung von umschließenden Eltern erreicht. Dies betrifft die Elemente Monat und Tarif, wobei Letztere in einer andere Struktur nun in folgendem Beispiel erscheinen. Wir verraten vermutlich nichts Neues, wenn wir sagen, dass in XML einige Elemente Kinder enthalten und damit Elternelemente sind und dass daher andere Elemente Kinder solcher Elternelemente sind. Es ist ebenfalls einfach erkennbar, dass sich durch solche Strukturen Geschwister-Strukturen ergeben.

Grundlagen

Wie allerdings schon bei der Diskussion der Nutzung von Benennungen, so ist es für uns auch im Fall der Strukturierung immer wieder möglich, dass wir auch in größeren Projekten, die deutlich längere Lebenszyklen als ein oder zwei Jahr haben und deren Datenmodellierung sogar in verkaufbaren Produkten einfließen, auf Modellierungen treffen, in denen innerhalb des Wurzelknotens beliebige Elemente in völlig ungeordneter Weise aufeinander folgen.

Dies führt dazu, dass ähnliche Elemente nur schwer erkannt werden oder jedes Mal über ihren Namen aufgerufen werden müssen, um eine passende Vorlage auszuwählen. Ebenfalls sind Erweiterungen von Dokumenten nur überaus umständlich für die Transformation zu berücksichtigen, weil bei ungeschickter Verschachtelung (Eltern-Kind-Strukturierung) neue Elementnamen überall in den XPath-Ausdrücken der Transformationsdokumente einzufügen sind. Bei unseren kurzen Beispielen ist möglicherweise der Nutzen der hier vorgestellten Technik nicht unmittelbar ersichtlich. Vergleichen Sie allerdings die Anzahl der Elemente in Ihren geplanten Dokumenten mit der Elementanzahl in unserem Beispiel und versuchen Sie abzuschätzen, was fünf- oder zehnmal mehr Elemente für Arbeitsaufwand oder auch -erleichterung bieten können, wenn sie geschickt strukturiert sind.

Folgende allgemeine Modellierungshinweise können wir geben. Sammeln Sie innerhalb von Elternelementen

  • gleiche Elemente, die den gleichen Namen und den gleichen Aufbau besitzen. Dies ist der einfachste Fall und ist normalerweise völlig problemlos zu realisieren bzw. ist fast ein Modellierungsfehler, wenn er nicht erkannt wurde.
  • ähnliche Elemente, die den gleichen Datentyp besitzen oder gleich verarbeitet werden sollen. Dies ist schon diskussionswürdig, weil die Verarbeitung eigentlich erst nach der Modellierung betrachtet wird oder die bereits genutzten oder angedachten Elementnamen gänzlich unterschiedlich sind.
  • erweiterbare Elemente, die zunächst nur als einzelner Wert ohne Geschwister auftreten und möglicherweise in Zukunft Geschwister in Form von ähnlichen Elementen erhalten. Dies ist besonders schwer durchsetzbar, weil Befürchtungen bestehen, zu tief zu verschachteln oder unnütze Elternelemente zu erstellen. Die letztere Sorge ist durchaus berechtigt, allerdings ist die Wahrscheinlichkeit, dass Datenstrukturen im Laufe der Zeit eher zu- als abnehmen, durchaus hoch.

Durch eine solche Aufbereitung kann man sehr einfach eine einzige allgemeine Vorlage für alle Kinder entwickeln, deren Namen nicht notwendigerweise bekannt sein muss. Stattdessen erstellt man eine Vorlage für das Elternelement (enthält Umsatzzahlen, Mitarbeiter, Grundstücke oder gleich typisierte Messdaten), dessen Kinder nach dem gleichen Schema verarbeitet werden. Wie viele Kinder genau verfügbar sind, ist unerheblich, da sie innerhalb eines Elternelements platziert sind. Auch wenn neue Kinder mit gleichem oder anderem Namen hinzukommen, ist dies nicht von Bedeutung, solange sie gleich verarbeitet werden.

In Erweiterung dieses Ansatzes lässt sich noch ein Benennungsschema oder mit Hilfe von Attributen ein Typisierungsschema verwenden, das in RDF (Resource Description Framework) zum Einsatz kommt. Da die Elternelemente eigentlich keine andere Aufgabe haben, als Elemente für eine einfache XPath-Adressierung zu umschließen, kann man sie im Namen oder mit Attributwerten auch mit zusätzlichen Informationen ausstatten. Diese könnten für die Verarbeitung nützliche Angaben enthalten. Ein typ-Attribut könnte die Werte sammlung oder reihenfolge speichern oder der Elementname könnte diese Bezeichnungen enthalten. Es ließe sich hier auch anregen, sofort die Bezeichner aus dem RDF zu verwenden, da sie dort definiert sind und man auf einen anderen Standard des W3C zurückgreift.

Dies kann die Reihenfolgebeziehung der enthaltenen Kinder betreffen:

  • Reihenfolge: Die Anordnung der Kinder in Dokumentrichtung entspricht einer notwendigen Reihenfolge bzw. ist für die Verarbeitung von Bedeutung. Einfaches Beispiel: Hier könnte die Verarbeitung z.B. zu einer nummerierten Liste führen.
  • Sammlung: Die Anordnung der Kinder in Dokumentrichtung entspricht keiner notwendigen Reihenfolge bzw. ist nicht für die Verarbeitung von Bedeutung. Einfaches Beispiel: Hier könnte die Verarbeitung z.B. zu einer nicht nummerierten Liste führen.

Beispiel zur Modellierung

Mit der bereits von den Daten her bekannten Umsatzaufstellung pro Monat und Tarif wollen wir die gegebenen Tipps illustrieren. Eine sehr sinnvolle und sicherlich schnell auf Gegenliebe stoßende Verbesserung ist die Gruppierung der Daten. Dies ließe sich für die Verarbeitung natürlich auch in XSLT erledigen, doch ist es durchaus arbeitserleichternd, wenn die Monate alle abgerufenen Tarife in der Tarifliste enthalten und nicht nur einen. (Um ehrlich zu sein, hatten wir das vorherige Dokument auch nur deswegen so schlecht aufgebaut, damit wir es jetzt korrigieren können.)

Eltern-Kind-Struktur: Erster Versuch

Dies ergibt dann ein Dokument wie folgendes:

<Monatsliste xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="212_02a.xsd">
  <Monat>
    <Datum>01.04</Datum>
    <Kunden>25649</Kunden>
    <Tarifliste>
      <Tarif>
        <Pro-Kopf-Umsatz>0.0251</Pro-Kopf-Umsatz>
        <Name>Mondschein1</Name>
        <Umsatz>644.69</Umsatz>
      </Tarif>
      <Tarif>
        <Pro-Kopf-Umsatz>0.0254</Pro-Kopf-Umsatz>
        <Name>Frühstück</Name>
        <Umsatz>650.57</Umsatz>
      </Tarif>
      ..
Leicht verbesserte Umsatzaufstellung

Nun schauen wir uns das Dokument noch einmal an und korrigieren es mit Hilfe der Benennungsempfehlungen und einer völlig veränderten Struktur im Bereich der Tarifliste. Weil unterschiedlich benannte, aber gleich verarbeitete Elemente im Element Tarif zu finden waren, gibt es nun ein Umsatz-Element, das das bereits vorhandene Elemente Pro-Kopf-Umsatz und das ehemalige Umsatz-Element im Namen Gesamt-Umsatz enthält. Da davon auszugehen ist, dass möglicherweise weitere Informationen zum Tarif benötigt werden wie z.B. Gültigkeit oder Tariftyp, befindet sich ein einzelnes Name-Element in einem Element Beschreibung. Dies ist in einer Projektsitzung schwierig zu vermitteln, weil ja eindeutig ein einzelnes Element mit einem scheinbar unnützen Elternelement versehen wird. Da allerdings tatsächlich im Datendokument private und geschäftliche Tarife enthalten sind und diese mit Sicherheit irgendwann getrennt voneinander ausgelesen werden sollen (Durchschnittsberechnungen, Gruppierung, Sortierung etc.), wäre dies ein Vorschlag, den man vorsorglich umsetzen sollte.

Eltern-Kind-Struktur: Zweiter Versuch

Wenn man sich schon die Mühe macht, ähnliche Elemente unter einem Elternelement zu vereinen, dann lohnt sich auch, eine Vereinfachung der Benennungen durchzuführen. Weil die Kinder eines Umsatz-Elements ohnehin Umsatzzahlen in verschiedenen Ausprägungen (pro Kopf, gesamt, im Vergleich zum Vormonat, Zuwachsrate etc.) enthalten, kann man die Namen auf Pro-Kopf und Gesamt verkürzen.

Eltern-Kind-Struktur: Zweiter Versuch

Sehr diskussionswürdig ist weiterhin die Modellierung von Datum und Kunden. Hier ist – so soll die Annahme sein – zunächst schwierig abzuschätzen, inwieweit hier Ober- oder Unterbegrifflichkeiten in den Datenstrukturen vorzufinden sind oder sein werden. Dass man mehr Zeitinformationen speichert, scheint eher unwahrscheinlich. Dass man detailliertere Kundeninformationen benötigt, ist insoweit fraglich, als dass sich diese erweiterten Zahlen auf andere Daten (pro Stadt, pro Tarif) beziehen müssten. Dies allerdings wäre dann eher im Tarif-Element unterzubringen und nicht als allein stehendes Konstrukt, weil möglicherweise Datenredundanzen auftreten können. Da dies nicht klar zu erkennen ist, bleibt es zunächst im Dokument so wie jetzt. Eine Verlagerung in den Umsatz-Bereich mit neuen Werten ist allerdings kein Problem, solange die Verarbeitung (in unserem Fall immer Ausgabe in HTML) die gleiche ist und der Datentyp zu den potenziellen Geschwistern im Umsatz-Element passt.

<Monatsliste xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="212_03.xsd">
  <Monat>
    <Datum>01.04</Datum>
    <Kunden>25649</Kunden>
    <Tarifliste>
      <Tarif>
        <Umsatz>
          <Pro-Kopf>0.0251</Pro-Kopf>
          <Gesamt>644.69</Gesamt>
        </Umsatz>
        <Beschreibung>
          <Name>Mondschein1</Name>
        </Beschreibung>
      </Tarif>
      ...
Neufassung der Umsatzübersicht

Beispiel zur Verarbeitung

Als beispielhafte Verarbeitung dieses Dokuments soll es nicht darum gehen, völlig allgemein zu arbeiten, sodass ein Transformationsdokument für unterschiedliche XML-Dokumenttypen entsteht. Stattdessen richtet sich unser Augenmerk darauf, eine Transformation zu erstellen, die auch bei sich wandelnden Dokumentstrukturen entweder gar keine Änderung oder nur kleinere Anpassungen erfordert. Wenn sich natürlich Namen ändern oder ganze Hierarchieverschiebungen ergeben, die in der Transformation ebenfalls über Namensaufruf und damit nicht völlig allgemein abgebildet werden, dann kommt man nicht umhin, Änderungen an diesen Bezeichnern auch in der Transformation vorzunehmen.

Wir gehen allerdings in unserem Beispiel davon aus, dass grundlegende Strukturen erhalten bleiben und hierarchisch tiefer angesiedelte Strukturen möglichst allgemein verarbeitet werden. Die Startvorlage ruft zunächst eine passende Vorlage für das Element Monat auf.

<!-- Startvorlage -->
  <xsl:template match="/Monatsliste" priority="2.0">
    <html>
      ...
      <body>
        <xsl:apply-templates select="Monat"/>
      </body>
    </html>
  </xsl:template>
Startvorlage

Diese Vorlage für das Element Monat erstellt eine Tabelle und arbeitet danach ausschließlich mit Hilfe der Eltern-Kind-Beziehung. Die inhärente und nicht zu modellierende Bedeutung von Kindern für die Ausgabe ist dabei für Änderungen der XML-Strukturen natürlich sehr wichtig. In unserem Fall werden aus den Namen der Kinder von Monat Spaltenköpfe, sodass neue Elemente, die – aus welchen Gründen auch immer – sich nicht für die Ausgabe oder für die Erzeugung von Spaltenköpfen eignen, hier fehl am Platz wären oder einen namentlichen Aufruf der anderen Elemente erfordern würden.

Für die Ausgabe der Datenreihen rufen wir diese Kindknoten erneut auf und suchen passende Vorlagen für sie.

  <!-- Vorlage für Monat -->
  <xsl:template match="Monat" priority="2.0">
    <h2>
      <xsl:value-of select="(position(), local-name(.))" separator=".) "/>
    </h2>
    <table border="1">
      <tr>
        <xsl:for-each select="child::*">
          <th>
            <xsl:value-of select="local-name(.)"/>
          </th>
        </xsl:for-each>
      </tr>
      <xsl:apply-templates select="child::*"/>
    </table>
  </xsl:template>
Vorlage für Monat

Die gerade erwähnten passenden Vorlagen für die Kindknoten von Monat werden ausdrücklich nicht über ihren Namen weiterverarbeitet, sondern über eine Vorlage, die speziell für Kinder :-) geschrieben wurde. Sie enthält verschiedene Fälle, die sich explizit auf das vorhandene Dokument beziehen und die unterschiedlichen Situationen abfragen, in denen Kindknoten auftreten können. Wichtig ist allerdings, dass auch bei wachsender Dokumentstruktur auf mehreren Kind-Ebenen die Transformation nicht anzupassen ist. Ob man mit der vorhandenen Vorlage drei oder vier Kindelemente beliebigen Namens verarbeitet oder ob diese wiederum Kinder enthalten, ist zunächst egal, solange mit der strukturierten Ausgabe in Tabellenform eine sinnvolle Ausgabe erzielt wird. Damit soll dieses Beispiel verdeutlichen, wie man sich die Arbeit bei sich verändernder Dokumentstruktur erleichtern kann, wenn man allgemeine Vorlagen einsetzt.

Im Quelltext haben wir die verschiedenen Kommentare gefettet, die jeweils die Fälle oder die Ausgabearten bezüglich der angestrebten Tabelle ankündigen.

  <!-- Vorlage für Kinder -->
  <xsl:template match="child::*">
    <xsl:choose>
    <!-- Eltern = Monat -->
      <xsl:when test="local-name(parent::*)='Monat'">
        <xsl:choose>
        <!-- Keine Kinder, sondern Textknoten -->
          <xsl:when test="count(child::*) = 0 and exists(text())">
            <td>
              <xsl:value-of select="."/>
            </td>
          </xsl:when>
          <!-- Ein Kind -->
          <xsl:when test="count(child::*) = 1">
            <td>
              <xsl:value-of select="."/>
            </td>
          </xsl:when>
          <!-- Mehr als ein Kind -->
          <xsl:when test="count(child::*) > 1">
            <td>
              <xsl:apply-templates select="child::*"/>
            </td>
          </xsl:when>
        </xsl:choose>
      </xsl:when>
      <!-- Eltern != Monat -->
      <xsl:when test="not(local-name(parent::*)='Monat')">
        <table border="1">
          <tr>
          <!-- Kinder von Monat -> TH -->
            <xsl:for-each select="child::*">
              <th>
                <xsl:value-of select="local-name(.)"/>
              </th>
            </xsl:for-each>
          </tr>
          <tr>
            <xsl:for-each select="child::*">
              <td>
              <!-- Kinder von Kinder von Monat -> TD -->
                <xsl:for-each select="child::*">
                  <xsl:value-of select="('(', local-name(.),')',.)"/>
                  <br/>
                </xsl:for-each>
              </td>
            </xsl:for-each>
          </tr>
        </table>
      </xsl:when>
    </xsl:choose>
  </xsl:template>
Ausgabeanweisungen

In HTML enthält man eine Tabelle, die ihrerseits wiederum mehrere kleine Tabellen enthält. Jeder Spalte in der äußeren Tabelle stellt ein Kind von Monat dar. Sollten hier also in Zukunft mehr Kinder erscheinen, dann würden zwangsläufig mehr Spalten ausgegeben werden. Sind in den Kindern Textknoten enthalten, werden diese in der Zelle ausgegeben. Enthalten die Kinder dagegen ebenfalls wieder Kinder, so werden diese bis zur in der vorher abgedruckten Vorlage berücksichtigten Hierarchietiefe ebenfalls in Tabellenform ausgegeben. Sollten hier ebenfalls mehr Kinder erscheinen, werden die Kindeskinder von Monat in mehr Spalten dieser Tabellen ausgegeben. Dies betrifft zurzeit die Elemente Umsatz und Beschreibung. Sollten dann wiederum mehr Kinder der Kindeskinder auftreten, entstünden automatisch längere Tabellen, da diese Elemente in den Zellen zu finden sind, wobei als Beschriftung eingeklammerte Ausdrücke entstehen.

Eltern-Kind-Struktur: Ausgabe
    Comelio GmbH XML Schema: Hierarchien und Eltern-Kind-Beziehungen Comelio GmbH XML Schema: Hierarchien und Eltern-Kind-Beziehungen Comelio GmbH XML Schema: Hierarchien und Eltern-Kind-Beziehungen Comelio GmbH XML Schema: Hierarchien und Eltern-Kind-Beziehungen Comelio GmbH XML Schema: Hierarchien und Eltern-Kind-Beziehungen Comelio GmbH XML Schema: Hierarchien und Eltern-Kind-Beziehungen Comelio GmbH XML Schema: Hierarchien und Eltern-Kind-Beziehungen Comelio GmbH XML Schema: Hierarchien und Eltern-Kind-Beziehungen Comelio GmbH XML Schema: Hierarchien und Eltern-Kind-Beziehungen