XML-Service

Einleitung

Dieser Abschnitt befasst sich kurz mit den XML-Dateien, die in den Chroniken von BVN verwendet werden. Es ist möglich, dass die Informationen für all diejenigen, die über kein XML-Grundwissen verfügen, nicht einfach zu verstehen sind.
Zunächst werden wir uns damit befassen, wie die einzelnen XML-Dateien angeordnet sind, um die Hierarchie und Themen zu kennzeichnen, die im Verzeichnisbaum stehen. Dann können wir uns dem Namensschema zuwenden, das für die Dateien verwendet wird. Diese zwei Aspekte sollten uns dann das nötige Grundwissen geben, damit wir auf Wunsch den Namen und den Ort einer Datei herausfinden können, um im dritten Teil zu erlernen wie die Daten auf der eingenen Webseite darstellbar sind.

Wir werden also die Verzeichnisstruktur durchgehen und den Inhalt jedes XML-Dateityps auflisten. Folgende Themen werden angesprochen:
-   Verband (Vereins- und Mannschaftslisten)
-   Spielplan
-   Rangliste
-   RSS Feed (Live Bookmark)

Schliesslich werden auch noch zwei Beispielcodes geliefert, die die abgerufenen Daten mittels HMTL und PHP darstellt.
Die Praxis hat gezeigt, dass das erste Beispiel bei gewissen Servern nicht funktioniert, da das direkte Lesen von Dateien von anderen Servern nicht erlaubt wird. Das zweite Beispiel besteht daher aus zwei Dateien. Die HTTPRequest Bibliothek und dem leicht angepassten Script aus Beispiel 1.


1. Verzeichnisbaum

Alle XML-Dateien sind unter derselben URL erreichbar:
http://www.bvn.ch/xml/
Eine Datei, die unter „http://www.bvn.ch/xml/ranking/H2L.xml zu finden ist, wird in der folgenden Erklärung nur mit: "ranking/H2L.xml" angesprochen.
Bei allen Verzeichnissen und Dateien ist auf die Gross- und Kleinschreibung zu achten!

XML - Filetypen
Von diesem URL ausgehend gibt es momentan folgende vier Verzeichnisse:

association   - Alle Vereine und der Mannschaften des Verbandes
schedules   - Alle Spielpläne der verschiedenen Vereine
ranking   - Alle Ranglisten der verschiedenen Ligen
rssFeed   - Die Files der RSS Feeds des BVN

2. Schema der Dateinamen

Das Schema der Dateinamen ermöglicht es uns, die genaue Bezeichnung der Dateien zu standardisieren (gemäss unserer allgemeinen Terminologie der regulären Ausdrücke).

Schrägschrift
Ein Begriff in Italic steht für einen Wert, der hier eingefügt wird. Zum Beispiel: idClub wird durch den tatsächlichen Kürzel eines Vereins ersetzt und idLeague wird durch den tatsächlichen Namen der Liga ersetzt. Mit folgendem Beispiel können wir auch schon die Namen der Files in den Verzeichnissen konkret definieren:

xml/ranking/idLeague.xml
xml/schedule/idClub.xml

Nun ist schon alles bekannt, was es über XML-Dateien zu den Chroniken vom BVN Service zu wissen gibt. Wir können uns nun also dem Inhalt zuwenden und die Informationen auflisten, die aus jeder Datei gewonnen werden können.

3. Die Bedeutung von XML

Die Bedeutung von XML hier einmal mehr zu erklären, wäre reine Zeitverschwendung, da es schon viele grossartige Erklärungen im Web gibt. Hier sei die Einleitung von Wikipedia zitiert:

Die Extensible Markup Language (engl. für „erweiterbare Auszeichnungs-Sprache“), abgekürzt XML, ist ein Standard zur Erstellung maschinen- und menschenlesbarer Dokumente in Form einer Baumstruktur, der vom World Wide Web Consortium (W3C) definiert wird. XML definiert dabei die Regeln für den Aufbau solcher Dokumente. Für einen konkreten Anwendungsfall ("XML-Anwendung") müssen die Details der jeweiligen Dokumente spezifiziert werden. Dies betrifft insbesondere die Festlegung der Strukturelemente und ihre Anordnung innerhalb des Dokumentenbaums. XML ist damit ein Standard zur Definition von beliebigen, in ihrer Grundstruktur jedoch stark verwandten Auszeichnungssprachen. Eine Sprache zur Definition anderer Sprachen nennt man Metasprache. XML ist eine vereinfachte Teilmenge von SGML.

http://de.wikipedia.org/wiki/Xml

Weiterführende Informationen zu XML können entweder unter obigem Link oder unter http://www.professionelle-softwareentwicklung-mit-php5.de/erste_auflage/ gefunden werden.
Hier sei einfach noch erwähnt, dass wir bewusst, Attribute so selten wie nötig verwendet haben, um bei der Darstellung ein möglichst einfaches Abarbeiten mit dem in PHP5 enthaltenen SimpleXML zu ermöglichen. SimpleXML wird daher im Kapitel 8 auch noch kurz vorgestellt.

4. Übersetzung

Liste der Vereine und deren Teams -- token.xml

<association date='2005-12-26 16:45:59'>
    <club>
        <idClub>laufen</idClub>
        <clubName>BBC Laufen</clubName>
        <region>BVN</region>
        <homepage>www.bbc-laufen.ch</homepage>       
        <team>
            <idTeam>16</idTeam>
            <idLeague>D3L</idLeague>
            <category>Senior</category>
            <teamName>BBC Laufen</teamName>
            <leagueName>Damen 3. Liga</leagueName>
        </team>
        <team>
            <idTeam>74</idTeam>
            <idLeague>H4L</idLeague>
            <category>Senior</category>
            <teamName>BBC Laufen</teamName>
            <leagueName>Herren 4. Liga</leagueName>
        </team>
    </club>
</association>

In der Datei "token.xml" setzt sich der Wurzelknoten "asscociation" aus mehreren "club"-Verzweigungspunkten zusammen, welche einerseits die Clubinformationen und anderseits wiederum mehrere "team" -Verzweigungspunkte beinhalten, die ihrerseits die wichtigsten Informationen bezüglich der Teams anzeigen.
Die Datei dient als Nachschlagewerk, so dass wenn wir später das SimpleXML Script konfigurieren wollen, hier einfach die Vereins-, Mannschafts- oder Liga-Referenz herauslesen können.

5. Spielplan

Spielplanliste der Mannschaften des Vereines idClub -- idClub.xml

<club date='2005-12-26 17:15:23'>
    <team idTeam="16">
        <match>
            <matchNr>2501</matchNr>
            <date>20.09.05</date>
            <time>19:30</time>
            <homeName>BBC Laufen</homeName>
            <awayName>BC Boncourt</awayName>
            <gymName>Gym Laufen</gymName>
            <homeScore>35</homeScore>
            <awayScore>68</awayScore>
        </match>
        <match>
            <matchNr>2556</matchNr>
            <date>27.09.05</date>
            <time>20:15</time>
            <homeName>TV Muttenz 2</homeName>
            <awayName>BBC Laufen</awayName>
            <gymName>Donnerbaum</gymName>
            <homeScore>30</homeScore>
            <awayScore>48</awayScore>
        </match>
    </team>
</club>

In der Datei "idClub.xml" setzt sich der Wurzelknoten "club" aus mehreren "team"-Verzweigungspunkten zusammen, welche einerseits das Attribut "idTeam" und anderseits wiederum mehrere "match" -Verzweigungspunkte beinhalten, die ihrerseits dann die Informationen über ein Spiel anzeigen.

Die "idTeam"-Attribute der"team"-Verzweigungspunkte geben die Referenz (oder ID) gemäß der "token.xml" Übersetzung-XMLs an.

6. Rangliste

Rangliste der Mannschaften der Liga idLeague -- idLeague.xml

<league>
    <team>
        <rank>1</rank>
        <name>BC Boncourt</name>
        <games>3</games>
        <win>3</win>
        <lost>0</lost>
        <forfait>0</forfait>
        <scored>316</scored>
        <received>64</received>
        <difference>252</difference>
        <points>6</points>
        <directEncounter>1</directEncounter>
        <directEncounterPoints>2</directEncounterPoints>
        <directEncounterDifference>33</directEncounterDifference>
    </team>
    <team>
        <rank>2</rank>
        <name>BC Münchenstein 2</name>
        <games>3</games>
        <win>3</win>
        <lost>0</lost>
        <forfait>0</forfait>
        <scored>186</scored>
        <received>89</received>
        <difference>97</difference>
        <points>6</points>
        <directEncounter>0</directEncounter>
        <directEncounterPoints>0</directEncounterPoints>
        <directEncounterDifference>0</directEncounterDifference>
    </team>
</league>

In der Datei "idLeague.xml" setzt sich der Wurzelknoten "league" aus mehreren "team"-Verzweigungspunkten zusammen, welche ihrerseits wiederum mehrere Informationen über die Rangliste der Liga preisgeben.

7. Voraussetzung

Die hier vorgestellte Variante setzt einen Webserver mit PHP 5 und minimale PHP Kenntnisse voraus.

8. SimpleXML

Für die einfache Verarbeitung von XML-Dokumenten bietet PHP die SimpleXML-Programmierschnittstelle an. Diese baut auf der Idee des Perl-Paketes XML::Simple auf und bietet einen intuitiven Zugriff auf XML-Daten.

Zu vertiefenden Informationen verweisen wir wieder auf Wikipedia sowie PHP.net, ausserdem empfehlen wir http://www.professionelle-softwareentwicklung-mit-php5.de/erste_auflage/programming-php.xml.simplexml.html.

Für unseren Zweck reicht es jedoch vollkommen zu wissen, dass die Funktion simplexml_load_file() ein Objekt der Klasse SimpleXMLElement für die Verarbeitung von XML-Daten erzeugt, die aus einer Datei gelesen werden.

Ein Objekt der Klasse SimpleXMLElement enthält für jedes XML-Kindelement eine Instanzvariable, die den entsprechenden Namen trägt. Kommt dieses nur einmal vor, so ist der Wert der Instanzvariablen der Wert des Kindelementes. Kommt das Kindelement mehrfach vor, so enthält die Instanzvariable ein Array von SimpleXMLElement-Objekten für die Kindelemente.

Vor- und Nachteile

  • + Einfacher Zugriff auf XML-Element.
  • + Geringer Speicherverbrauch, da PHP-Objekte nur bei Bedarf erzeugt werden und das Dokument zu Beginn nur einmal (im Speicher der libxml2-Bibliothek) vorliegt.
  • + Schnell.
  • - Zugriff auf Attribute eines XML-Elementes umständlich.
  • - Kein Standard.

9. Beispiel 1 (mit simplexml_load_file)

<?php
$XMLFilePath = "http://www.bvn.ch/xml/schedule/SC_UNI_BASEL.xml";

function printScheduleData($XMLFilePath, $idTeam) {
    if (!(file_exists($XMLFilePath))) {
        return FALSE;
    }

    $club = simplexml_load_file($XMLFilePath);

    foreach ($club as $team) {
        if ($team['idTeam'] == $idTeam) {
            foreach ($team as $match) {
                $arSplitDate = explode(".",$match->date);
                printf ("<tr>\n
                    <td>%s</td>\n
                    <td>%s</td>\n
                    <td>%s</td>\n
                    <td>%s</td>\n
                    <td>%s</td>\n
                    <td>%s</td>\n
                    <td>%s:%s</td>\n
                    </tr>\n",
                    $match->matchNr,
                    strftime("%a", mktime(0, 0, 0, $arSplitDate[1], $arSplitDate[0], "20".$arSplitDate[2])),
                    $match->date,                     $match->time,
                    utf8_decode($match->homeName),
                    utf8_decode($match->awayName),
                    utf8_decode($match->gymName),
                    $match->homeScore, $match->awayScore);
                }
            }
        }
    }
?>
<table width='676' border='0' cellpadding='0' cellspacing='0'>
    <tr>
        <td class='title'>#</td>
        <td class='title'>Tag</td>
        <td class='title'>Datum</td>
        <td class='title'>Zeit</td>
        <td class='title'>Heim</td>
        <td class='title'>Gast</td>
        <td class='title'>Halle</td>
        <td class='title'>Resultat</td>
    </tr>
<?php
  $idTeam = 440;
  printScheduleData($XMLFilePath, $idTeam); ?>
</table>

10. Beispiel 2 (mit simplexml_load_string)

<?php include_once("./lib.HTTPRequest.php"); ?>
<?php
// Dateiname z.b. schedule.php
$XMLFilePath = "http://www.bvn.ch/xml/schedule/SC_UNI_BASEL.xml";

function printScheduleData($XMLFilePath, $idTeam) {
    $myRequest = new HTTPRequest($XMLFilePath);
    $xml_contents = $myRequest->DownloadToString();

    $club = simplexml_load_string($xml_contents);

    foreach ($club as $team) {
        if ($team['idTeam'] == $idTeam) {
            foreach ($team as $match) {
                $arSplitDate = explode(".",$match->date);
                printf ("<tr>\n
                    <td>%s</td>\n
                    <td>%s</td>\n
                    <td>%s</td>\n
                    <td>%s</td>\n
                    <td>%s</td>\n
                    <td>%s</td>\n
                    <td>%s</td>\n
                    <td>%s:%s</td>\n
                    </tr>\n",
                    $match->matchNr,
                    strftime("%a", mktime(0, 0, 0, $arSplitDate[1], $arSplitDate[0], "20".$arSplitDate[2])),
                    $match->date, $match->time,
                    utf8_decode($match->homeName),
                    utf8_decode($match->awayName),
                    utf8_decode($match->gymName),
                    $match->homeScore, $match->awayScore);
                }
            }
        }
    }
?>
<table width='676' border='0' cellpadding='0' cellspacing='0'>
    <tr>
        <td class='title'>#</td>
        <td class='title'>Tag</td>
        <td class='title'>Datum</td>
        <td class='title'>Zeit</td>
        <td class='title'>Heim</td>
        <td class='title'>Gast</td>
        <td class='title'>Halle</td>
        <td class='title'>Resultat</td>
    </tr>
<?php
  $idTeam = 440;
  printScheduleData($XMLFilePath, $idTeam); ?>
</table>

11. HTTP Request Library (notwendig für Bsp2)

<?php
// Dateiname lib.HTTPRequest.php für Aufruf aus Beispiel 2
class HTTPRequest {
  var $_fp; // HTTP socket
  var $_url; // full URL
  var $_host; // HTTP host
  var $_protocol; // protocol (HTTP/HTTPS)
  var $_uri; // request URI
  var $_port; // port

  // scan url
  function _scan_url() {
    $req = $this->_url;

    $pos = strpos($req, '://');
    $this->_protocol = strtolower(substr($req, 0, $pos));

    $req = substr($req, $pos+3);
    $pos = strpos($req, '/');
    if($pos === false) {
      $pos = strlen($req);
    }
    $host = substr($req, 0, $pos);

    if(strpos($host, ':') !== false) {
      list($this->_host, $this->_port) = explode(':', $host);
    } else {
      $this->_host = $host;
      $this->_port = ($this->_protocol == 'https') ? 443 : 80;
    }

    $this->_uri = substr($req, $pos);
    if($this->_uri == '') {
      $this->_uri = '/';
    }
  }

  // constructor
  function HTTPRequest($url) {
    $this->_url = $url;
    $this->_scan_url();
  }

  // download URL to string
  function DownloadToString() {
    $crlf = "\r\n";

    // generate request
    $req = 'GET ' . $this->_uri . ' HTTP/1.0' . $crlf
      . 'Host: ' . $this->_host . $crlf
      . $crlf;

    // fetch
    $this->_fp = fsockopen(($this->_protocol == 'https' ? 'ssl://' : '')
      . $this->_host, $this->_port);
    fwrite($this->_fp, $req);
    while(is_resource($this->_fp) && $this->_fp && !feof($this->_fp)) {
      $response .= fread($this->_fp, 1024);
    }
    fclose($this->_fp);

    // split header and body
    $pos = strpos($response, $crlf . $crlf);
    if($pos === false) {
      return($response);
    }
    $header = substr($response, 0, $pos);
    $body = substr($response, $pos + 2 * strlen($crlf));

    // parse headers
    $headers = array();
    $lines = explode($crlf, $header);
    foreach($lines as $line) {
      if(($pos = strpos($line, ':')) !== false) {
        $headers[strtolower(trim(substr($line, 0, $pos)))] = trim(substr($line, $pos+1));
      }
    }

    // redirection?
    if(isset($headers['location'])) {
      $http = new HTTPRequest($headers['location']);
      return($http->DownloadToString($http));
    } else {
      return($body);
    }
  }
}
?>

12. Beispiel 3 (für Rangliste)

<?php include_once("./lib.HTTPRequest.php"); ?>

<?php
$XMLFilePath = "http://www.bvn.ch/xml/ranking/H3L.xml";

function printRankingData($XMLFilePath) {

  $myRequest = new HTTPRequest($XMLFilePath);
  $xml_contents = $myRequest->DownloadToString();

  $league = simplexml_load_string($xml_contents);

  // evtl hier das Array League noch nach Rank sortieren

  foreach ($league as $team) {
    printf ("<tr>\n
      <td>%s</td>\n
      <td>%s</td>\n
      <td>%s</td>\n
      <td>%s</td>\n
      <td>%s</td>\n
      <td>%s</td>\n
      <td>%s</td>\n
      <td>%s</td>\n
      <td>%s</td>\n
      <td>%s</td>\n
      <td>%s</td>\n
      <td>%s</td>\n
      <td>%s</td>\n
      </tr>\n",
      $team->rank,
      utf8_decode($team->name),
      $team->games,
      $team->win,
      $team->lost,
      $team->forfait,
      $team->scored,
      $team->received,
      $team->difference,
      $team->points,
      $team->directEncounter,
      $team->directEncounterPoints,
      $team->directEncounterDifference
      );
    }
  }
?>
<table width='676' border='0' cellpadding='0' cellspacing='0'>
    <tr>
        <td class='title' width="30"> </td>
        <td class='title' width="400">Mannschaft</td>
        <td class='title' width="50">Spiele</td>
        <td class='title' width="40">S</td>
        <td class='title' width="40">N</td>
        <td class='title' width="40">FF</td>
        <td class='title' width="50">Erz</td>
        <td class='title' width="50">Erh</td>
        <td class='title' width="50">KV</td>
        <td class='title' width="50">Punkte</td>
        <td class='title' width="50">SpDB</td>
        <td class='title' width="60">Pt.DB</td>
        <td class='title' width="50">KVDB</td>
    </tr>
<?php printRankingData($XMLFilePath); ?>
</table>