XML / XML-Datenstrukturen

XML-Datenstrukturen

XML-Datenstrukturen

➪ Das Datenformat XML ist außerordentlich gestaltungsflexibel. Das hat Konsequenzen für die Art der automatischen Verarbeitung.

Auf dieser Seite:

Grundsätzlich lassen sich XML-Dokumente unterteilen in

Jede dieser Strukturierungsalternativen erfordert andere Vorgehensweisen bei der systematischen Verarbeitung. Dieses Buch legt seinen Schwerpunkt auf starke, datenzentrierte Strukturierung der XML-Dokumente. Daher möchte ich hier nur kurz auf schwach strukturierte Dokumente oder auf Dokumente mit mixed content eingehen.

XML: Schwach strukturierte Dokumente


<?xml version="1.0" encoding="iso-8859-1"?>
<root>Die enorme Gestaltungsflexibilität 
zwingt zu systematischer Strukturierung, 
damit die XML-Dokumente systematisch 
ausgewertet werden können.</root>

Abgesehen vom XML-Prolog und dem "<root>"-Element, ist das vorstehende XML-Dokument zwar wohlgeformt, aber im Übrigen unstrukturiert. Das wird auch nicht besser, wenn einige Tausend Sätze hinzukommen, die ebenfalls keine strukturierenden Elemente beinhalten. Es bleibt unserer Fantasie oder unserer Bereitschaft zur Spekulation überlassen, hier eine klare Struktur erraten zu wollen, die sich systematisch auswerten ließe. Gerade der völlige Mangel an systematischer Strukturierung zeigt, wie eingeschränkt die anschließende Auswertbarkeit ist.

Eine schwache Strukturierung kann beispielsweise entstehen, wenn einzelne Textteile hervorgehoben werden, etwa durch "... damit die <hervorheben>XML</hervorheben>-Dokumente systematisch ...". Dann haben Sie es mit einer gemischten Abfolge aus Textinhalt und Formatierungsanweisungen zu tun, deren Abfolge kaum vorhersehbar ist und die eine hohe Flexibilität bei der Programmierung erfordert.

Das wiederum lässt vermuten, dass Sie in diesem Umfeld mit der Anwendung von xsl:for-each Mühe haben könnten. Sinnvoller scheint die Arbeit mit xsl:template match bzw. xsl:apply-templates, die eine Aufsplittung der Programmierlogik in mehrere Templates mit sich bringt.

Solange der Überblick über die ggf. sehr zahlreichen (Hunderte, Tausende) Templates gewährleistet ist (optimal durch eine effiziente Koordination der Teamarbeit), sind keine Probleme für die flexible Anpassung der Programmlogik zu erwarten. Eine weniger qualitätsbewusste Teamarbeit birgt jedoch Gefahren der Unübersichtlichkeit und hoher Wartungskosten.

XML-Struktur: mixed content

Das folgende Beispiel zeigt einen Mix aus klarer Basisstruktur, die mit XPath gezielt adressiert werden kann (Abschnitt/para) und einer gemischten Abfolge aus Textinhalt und Formatierungsanweisungen (innerhalb para: text(), kursiv, fett, link), für deren systematische Auswertbarkeit eine hohe Flexibilität erforderlich ist.

Während es sich anbietet, die Abschnitt/para-Struktur durch zu verarbeiten, bleibt für die Formatierungsanweisungen innerhalb para vorrangig die Arbeit mit "xsl:template match" bzw. . So vielfältig wie die Input-Struktur dürfte auch die Programmierlogik bei deren Auswertung gestaltet werden. Auch hier empfiehlt sich eine effiziente, qualitätsbewusste Koordination der Teamarbeit, um die langfristigen Wartungskosten unter Kontrolle zu behalten.


<?xml version="1.0" encoding="iso-8859-1"?>
<Abschnitt>
  <title>Namespaces</title>
  <para>Die enorme Gestaltungsflexibilität der 
<kursiv>XML-Dokumente</kursiv> zwingt zu 
<fett>systematischer Strukturierung</fett>, 
damit die <kursiv>XML-Dokumente</kursiv> 
systematisch ausgewertet werden können.</para>
<para>Aber auch eine klare systematische 
Strukturierung von <kursiv><fett>Element- und 
Attributnamen</fett></kursiv> sowie deren 
<fett><kursiv>Datentypen</kursiv></fett> 
(etwa durch <link 
l="http://www.w3.org/2001/XMLSchema">XML-Schema</link>) 
reicht nicht immer aus, begriffliche 
Kollisionen zu vermeiden. </para>
</Abschnitt>

XML: Stark strukturierte Dokumente

Stark strukturierte XML-Dokumente (das Kernthema dieses Buches) haben häufig einen klaren, hierarchischen Aufbau, der sich entsprechend systematisch auswerten lässt.

Das ist aber keine Selbstverständlichkeit. Es kann schnell passieren, dass die Datenstruktur des XML-Input-Dokuments auf verschiedene Ebenen verteilt ist und gegenseitige Abhängigkeiten aufweist, die in der Programmierlogik mittels XPath mehr oder weniger aufwendig nachvollzogen werden müssen. Das wird spätestens dann ein Problem, wenn die internen Abhängigkeiten nicht im XML-Schema (und auch sonst nirgendwo) dokumentiert sind, sodass die automatisierte Kontrolle erschwert ist.

Ebenso kann es vorkommen, dass der strukturelle Aufbau des XML-Dokuments sich nur aus der sequenziellen Abfolge der einzelnen Elemente ergibt, ohne dass eine hierarchische Strukturierung vorliegt. Abhängig von diesen unterschiedlichen Datenstrukturen müssen auch unterschiedliche Verarbeitungskonzepte bereitstehen.

XML: Hierarchischer Aufbau

Der einfachste Ansatz ist das folgende XML-Dokument: Ein Root-Element Orte hat mehrere Child-Elemente Ort (jeweils mit id und name); jeder Ort hat mehrere Child-Elemente Mensch (mit id, name, vorname, Gehalt und idOrt), und jeder Mensch kann darüber hinaus noch mehrere Child-Elemente Kauf haben (mit den Child-Elementen idMensch, anzahl, bez, preis und Gesamt, die jeweils nur einmal auftreten können).


<?xml version="1.0" standalone="yes"?>
<Orte>
  <Ort>
    <id>1</id>
    <name>Neustadt</name>
    <Mensch>
      <id>1</id>
      <name>Holzflos</name>
      <vorname>Hugo</vorname>
      <Gehalt>234.56</Gehalt>
      <idOrt>1</idOrt>
      <Kauf>
        <idMensch>1</idMensch>
        <anzahl>3</anzahl>
        <bez>Hemd</bez>
        <preis>12.99</preis>
        <Gesamt>38.97</Gesamt>
      </Kauf>
    </Mensch>
  </Ort>
</Orte>

Diese komfortable hierarchische Struktur lässt sich gut mit XPath auswerten. Sie verdeutlicht das Zusammenspiel von XPath mit XSLT und deren jeweiligen Funktionen sehr gut. In diesem Beispiel lassen sich XPath-Statements wie


/Orte/Ort[name='Neustadt']/Mensch/Kauf[bez='Hemd']/Gesamt

auf einfache Weise nachvollziehen. Sie erbringt eine Elementliste sämtlicher Gesamt-Felder von Menschen, die in Neustadt wohnen und sich ein oder mehrere Hemden gekauft haben.

Das XML-Dokument entspricht einem XML-Schema, das Constraints (Beziehungen von Primär- und Fremdschlüsseln) sichtbar macht.

pic/Datenbank_ADONET_Schema.png


<?xml version="1.0" standalone="yes"?>
<xs:schema id="Orte" xmlns="" 
 xmlns:xs="http://www.w3.org/2001/XMLSchema" 
 xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
 <xs:element name="Orte" 
   msdata:IsDataSet="true" msdata:Locale="de-DE">
  <xs:complexType>
   <xs:choice maxOccurs="unbounded">
    <xs:element name="Ort">
     <xs:complexType>
      <xs:sequence>
       <xs:element name="id" type="xs:int" minOccurs="0"/>
       <xs:element name="name" type="xs:string" minOccurs="0"/>
       <xs:element name="Mensch" minOccurs="0" maxOccurs="unbounded">
        <xs:complexType>
         <xs:sequence>
          <xs:element name="id" type="xs:int" minOccurs="0"/>
          <xs:element name="name" type="xs:string" minOccurs="0"/>
          <xs:element name="vorname" type="xs:string" minOccurs="0"/>
          <xs:element name="Gehalt" type="xs:string" minOccurs="0"/>
          <xs:element name="idOrt" type="xs:int" minOccurs="0"/>
          <xs:element name="Kauf" minOccurs="0" maxOccurs="unbounded">
           <xs:complexType>
            <xs:sequence>
             <xs:element name="idMensch" type="xs:int" minOccurs="0"/>
             <xs:element name="anzahl" type="xs:int" minOccurs="0"/>
             <xs:element name="bez" type="xs:string" minOccurs="0"/>
             <xs:element name="preis" type="xs:double" minOccurs="0"/>
             <xs:element name="Gesamt" type="xs:double" minOccurs="0"/>
            </xs:sequence>
           </xs:complexType>
          </xs:element>
         </xs:sequence>
        </xs:complexType>
       </xs:element>
      </xs:sequence>
     </xs:complexType>
    </xs:element>
   </xs:choice>
  </xs:complexType>
  <xs:unique name="Mensch_Constraint1" 
   msdata:ConstraintName="Constraint1">
   <xs:selector xpath=".//Mensch" />
   <xs:field xpath="id" />
  </xs:unique>
  <xs:unique name="Constraint1">
   <xs:selector xpath=".//Ort" />
   <xs:field xpath="id" />
  </xs:unique>
  <xs:keyref name="relationOrtMensch" 
   refer="Constraint1" msdata:IsNested="true">
   <xs:selector xpath=".//Mensch" />
   <xs:field xpath="idOrt" />
  </xs:keyref>
  <xs:keyref name="relationMenschKauf" 
   refer="Mensch_Constraint1" msdata:IsNested="true">
   <xs:selector xpath=".//Kauf" />
   <xs:field xpath="idMensch" />
  </xs:keyref>
 </xs:element>
</xs:schema>

XML: Aufbau entspricht der SQL-Datenbankstruktur

Obwohl die Inhalte des folgenden XML-Dokuments sachlich identisch sind mit dem vorher dargestellten Beispiel, ist doch ihr struktureller Aufbau ein völlig anderer, was auch eine aufwendigere Programmierlogik der XPath-Statements erfordert, die die XML-Input-Dokumente auswertbar machen sollen.

Im folgenden Beispiel bringt das vorhin erwähnte XPath-Statement


/ROOT/Ort[name='Neustadt']/Mensch/Kauf[bez='Hemd']/Gesamt"

kein Ergebnis. Ganz abgesehen davon, dass die Felder Kauf/bez und Kauf/Gesamt hier nicht existieren, muss die Verknüpfung zum Ort "Neustadt" ziemlich aufwendig durch zusätzliche temporäre Variablen hergestellt werden. Dazu später mehr.


<ROOT>
  <Ort>
    <id>1</id>
    <name>Neustadt</name>
  </Ort>
  <Mensch>
    <id>1</id>
    <name>Holzflos</name>
    <vorname>Hugo</vorname>
    <Gehalt>234.56</Gehalt>
    <idOrt>1</idOrt>
  </Mensch>
  <Ware>
    <id>1</id>
    <bez>Hemd</bez>
    <preis>12.99</preis>
  </Ware>
  <Kauf>
    <id>1</id>
    <anzahl>3</anzahl>
    <idMensch>1</idMensch>
    <idWare>1</idWare>
  </Kauf>
</ROOT>

Eine veränderte Situation liegt vor, wenn die Struktur des XML-Input-Dokuments dem Ergebnis der Datenbankabfragen entspricht, wenn also die komplexen XML-Elemente im Grunde genommen Datensätze darstellen. Solchermaßen veränderte Strukturen machen die Formulierung der XPath-Statements (und deren Pflege) nicht unbedingt einfacher.

pic/Datenbank_ADONET_Schema_2.png


<xs:schema id="ROOT" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
 <xs:element name="ROOT" 
  msdata:IsDataSet="true" 
  msdata:UseCurrentLocale="true">
  <xs:complexType>
   <xs:choice maxOccurs="unbounded">
    <xs:element name="Ort">
     <xs:complexType>
      <xs:sequence>
       <xs:element name="id" type="xs:int" />
       <xs:element name="name" type="xs:string" />
      </xs:sequence>
     </xs:complexType>
    </xs:element>
    <xs:element name="Mensch">
     <xs:complexType>
      <xs:sequence>
       <xs:element name="id" type="xs:int" />
       <xs:element name="name" type="xs:string" />
       <xs:element name="vorname" type="xs:string" />
       <xs:element name="Gehalt" type="xs:string" />
       <xs:element name="idOrt" type="xs:int" />
      </xs:sequence>
     </xs:complexType>
    </xs:element>
    <xs:element name="Ware">
     <xs:complexType>
      <xs:sequence>
       <xs:element name="id" type="xs:int" />
       <xs:element name="bez" type="xs:string" />
       <xs:element name="preis" type="xs:double" />
      </xs:sequence>
     </xs:complexType>
    </xs:element>
    <xs:element name="Kauf">
     <xs:complexType>
      <xs:sequence>
       <xs:element name="id" type="xs:int" />
       <xs:element name="anzahl" type="xs:int" />
       <xs:element name="idMensch" type="xs:int" />
       <xs:element name="idWare" type="xs:int" />
      </xs:sequence>
     </xs:complexType>
    </xs:element>
   </xs:choice>
  </xs:complexType>
 </xs:element>
</xs:schema>

XML: Sequenzielle Dokument-Struktur

Stellen Sie sich einmal vor, die hierarchische Struktur würde weitestgehend fehlen, und Sie hätten es mit einer rein sequenziellen XML-Struktur zu tun, deren inhaltliche Abhängigkeiten durch die Anschlussprogrammierung erst einmal abgebildet werden müssten, um sie auswerten zu können.


<ROOT>
  <id>1</id>
  <name>Neustadt</name>
  <id>1</id>
  <name>Holzflos</name>
  <vorname>Hugo</vorname>
  <Gehalt>234.56</Gehalt>
  <idOrt>1</idOrt>
  <idMensch>1</idMensch>
  <anzahl>3</anzahl>
  <bez>Hemd</bez>
  <preis>12.99</preis>
  <Gesamt>38.97</Gesamt>
</ROOT>

Inhaltlich ist das XML-Dokument identisch mit dem erstgenannten Beispiel, lediglich mit einem komplett veränderten strukturellen Aufbau. (Streng genommen hätte man hier ohne Informationsverlust sogar noch auf die "Fremdschlüssel" idOrt und idMensch sowie auf das Gesamt-Feld verzichten können, da sie sich aus dem Kontext der Sequenz ergeben.) Auch so etwas kommt in der Praxis vor, und es stellt sich die Frage, wie in diesem Fall vorgegangen werden kann.

wg / 12. April 2018



Fragen? Anmerkungen? Tips?

Bitte nehmen Sie Kontakt zu mir auf.






Vielen Dank für Ihr Interesse an meiner Arbeit.


V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn

☎ 0151. 750 360 61 * eMail: info10@wilfried-grupe.de

www.wilfried-grupe.de/XML_Strukturalternativen.html