DATEX II: Spannende Daten kompliziert verpackt

Spätestens seit dem 2. BMVI Data Run sind ein paar mehr Menschen in Berührung mit dem DATEX II Standard gekommen. Glücklicherweise gab es die meisten Datensätze übersetzt in GeoJSON, denn DATEX II ist schon ein ziemliches Monster. Gleichermaßen sind viele spannende Verkehrsdaten in DATEX II, so dass sich ein tiefergehender Blick lohnt.

Was ist DATEX II?

Zunächst einmal ist DATEX II ein XML-basierter Standard für Mobilitätsdaten aus dem Jahre 2009. Von Baustellen über öffentlichen Parkraum bis Verkehrsmonitoring findet man fast alles im DATEX II Standard, was die öffentliche Hand an Daten generiert – zumindest auf höheren Ebenen, auf kommunaler Ebene ist DATEX II u.a. aufgrund seiner Komplexität nicht so weit verbreitet.

Der Standard wird EU-weit eingesetzt und fasst eine Reihe verschiedener Verkehrsinfosysteme zusammen. Dabei werden eine Vielzahl lokaler und zum Teil historischer Repräsentationen von Daten unterstützt – auf eine dieser historischen Repräsentationen, der LCL, werde ich weiter unten auch noch eingehen. Der Standard kann erweitert werden, was DATEX II kaum übersichtlicher macht. Andererseits ist genau das eine halbe Revolution: egal, wie umfassend der Standard auch sein mag und wie viele Datenrepräsentations-Arten er haben mag: man spricht EU-weit einigermaßen dieselbe Sprache, und allein das ist viel wert.

Es ist ein DIN-Standard, die Dokumentation kann dort kostenpflichtig bestellt werden (was ich aber nicht empfehlen kann, die Dokumentation entspricht nicht dem, was man unter einer sauberen Standard-Dokumentation erwartet). Die Dokumentation ist generell eher mäßig gut, und vieles ist nicht wirklich intuitiv – aber genau deswegen schreibe ich diesen Artikel. Am Ende gibt es auch noch eine Linksammlung, u.a. auch mit Dokumentationen.

Ein DATEX II Datensatz

Baustellen auf Bundesautobahnen sind ein typischer DATEX II Datensatz, weswegen dies mein erstes Beispiel ist:

<d2LogicalModel xmlns="http://datex2.eu/schema/2/2_0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" modelBaseVersion="2" extensionName="MDM-BIS" extensionVersion="02-00-00" xsi:schemaLocation="http://datex2.eu/schema/2/2_0 http://bast.s3.amazonaws.com/schema/1358258738363/MDM_Profile_BIS.xsd">
  <exchange>
    <supplierIdentification>
      <country>de</country>
      <nationalIdentifier>
        DE-MDM-Baustelleninformationssystem des Bundes und der Länder
      </nationalIdentifier>
    </supplierIdentification>
  </exchange>
  <payloadPublication xsi:type="SituationPublication" lang="de">
    <publicationTime>2016-12-23T01:00:02.692+01:00</publicationTime>
    <publicationCreator>
      <country>de</country>
      <nationalIdentifier>
        DE-MDM-Baustelleninformationssystem des Bundes und der Länder
      </nationalIdentifier>
    </publicationCreator>
    <situation id="42831f2c-6d47-4918-8cae-5d414c94cc13_123111" version="1482415202822">
      <headerInformation>
        <confidentiality>noRestriction</confidentiality>
        <informationStatus>real</informationStatus>
      </headerInformation>
      <situationRecord xsi:type="ConstructionWorks" id="42831f2c-6d47-4918-8cae-5d414c94cc13_123111" version="1482415202822">
        <situationRecordCreationTime>2016-12-22T15:00:02.822+01:00</situationRecordCreationTime>
        <situationRecordVersionTime>2016-12-22T15:00:02.822+01:00</situationRecordVersionTime>
        <probabilityOfOccurrence>certain</probabilityOfOccurrence>
        <validity>
          <validityStatus>definedByValidityTimeSpec</validityStatus>
          <validityTimeSpecification>
            <overallStartTime>2017-01-03T00:00:00.000+01:00</overallStartTime>
            <overallEndTime>2017-01-26T23:59:00.000+01:00</overallEndTime>
          </validityTimeSpecification>
        </validity>
        <generalPublicComment>
          <comment>
            <values>
              <value lang="de">Brückenneubau</value>
            </values>
          </comment>
        </generalPublicComment>
        <groupOfLocations xsi:type="Linear">
          <supplementaryPositionalDescription>
            <affectedCarriagewayAndLanes>
              <carriageway>mainCarriageway</carriageway>
              <lengthAffected>760.0</lengthAffected>
            </affectedCarriagewayAndLanes>
          </supplementaryPositionalDescription>
          <alertCLinear xsi:type="AlertCMethod2Linear">
            <alertCLocationCountryCode>de</alertCLocationCountryCode>
            <alertCLocationTableNumber>15</alertCLocationTableNumber>
            <alertCLocationTableVersion>15.1.D-160122</alertCLocationTableVersion>
            <alertCDirection>
              <alertCDirectionCoded>negative</alertCDirectionCoded>
            </alertCDirection>
            <alertCMethod2PrimaryPointLocation>
              <alertCLocation>
                <alertCLocationName>
                  <values>
                    <value lang="de">Kreuz Mönchengladbach-Wanlo</value>
                  </values>
                </alertCLocationName>
                <specificLocation>12017</specificLocation>
              </alertCLocation>
            </alertCMethod2PrimaryPointLocation>
            <alertCMethod2SecondaryPointLocation>
              <alertCLocation>
                <alertCLocationName>
                  <values>
                    <value lang="de">Mönchengladbach-Güdderath</value>
                  </values>
                </alertCLocationName>
                <specificLocation>12018</specificLocation>
              </alertCLocation>
            </alertCMethod2SecondaryPointLocation>
          </alertCLinear>
          <linearWithinLinearElement>
            <linearElement>
              <roadNumber>A61</roadNumber>
            </linearElement>
            <fromPoint xsi:type="DistanceFromLinearElementReferent">
              <distanceAlong>34000.0</distanceAlong>
              <fromReferent>
                <referentIdentifier>Linear Element Origin</referentIdentifier>
                <referentType>referenceMarker</referentType>
              </fromReferent>
              <towardsReferent>
                <referentIdentifier>Linear Element Destination</referentIdentifier>
                <referentType>referenceMarker</referentType>
              </towardsReferent>
            </fromPoint>
            <toPoint xsi:type="DistanceFromLinearElementReferent">
              <distanceAlong>34760.0</distanceAlong>
              <fromReferent>
                <referentIdentifier>Linear Element Origin</referentIdentifier>
                <referentType>referenceMarker</referentType>
              </fromReferent>
              <towardsReferent>
                <referentIdentifier>Linear Element Destination</referentIdentifier>
                <referentType>referenceMarker</referentType>
              </towardsReferent>
            </toPoint>
          </linearWithinLinearElement>
        </groupOfLocations>
        <operatorActionExtension>
          <operatorActionExtended>
            <temporarySpeedLimit>80.0</temporarySpeedLimit>
          </operatorActionExtended>
        </operatorActionExtension>
        <subjects>
          <subjectTypeOfWorks>bridge</subjectTypeOfWorks>
        </subjects>
        <roadworksExtension>
          <roadworksExtended>
            <internalRoadworksIdentifier>RP23</internalRoadworksIdentifier>
          </roadworksExtended>
        </roadworksExtension>
        <constructionWorkType>constructionWork</constructionWorkType>
      </situationRecord>
      [...]
    </situation>
  </payloadPublication>
</d2LogicalModel>

Auch wenn in der XML eine Menge Meta-Informationen ohne praktischen Wert für eine Weiterverarbeitung stehen, so lassen sich die interessanten Punkte doch schnell identifizieren. Es geht dabei um einen Brückenneubau, der 760 m lang ist, ein Geschwindigkeitslimit von 80 km/h bedeutet und vom 3. bis zum 26. Januar 2017 stattfinden wird.

Auffällig ist jedoch, dass keine „normalen“ Geokoordinaten vorliegen. Dafür nimmt der Block groupOfLocations einen ausgeprägten Anteil der XML ein. Als Unterknoten sind dort neben supplementaryPositionalDescription gleich zwei eher befremdlich wirkende Geolokalisationen zu finden. Dies ist typisch für DATEX II: es wird eine große Anzahl verschiedener Geolokalisationsmethoden unterstützt, und vielfach werden gleich mehrere davon in einem Datensatz angegeben. Die hier verwendete Geolokalisation AlertC / LCL wird weiter unten im Detail besprochen.

Nehmen wir noch ein anderes Beispiel: die Parkplatzdaten der Stadt Düsseldorf.

<d2LogicalModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://datex2.eu/schema/2/2_0" modelBaseVersion="2" extensionName="MDM" extensionVersion="00-01-03" xsi:schemaLocation="http://datex2.eu/schema/2/2_0 http://bast.s3.amazonaws.com/schema/1370440019172/MDM-Profile_ParkingFacilityTable.xsd">
  <exchange>
    <supplierIdentification>
      <country>de</country>
      <nationalIdentifier>DE-MDM- Landshauptstadt Duesseldorf</nationalIdentifier>
    </supplierIdentification>
  </exchange>
  <payloadPublication xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="GenericPublication" lang="de">
    <publicationTime>2016-12-23T00:16:07.394+01:00</publicationTime>
    <publicationCreator>
      <country>de</country>
      <nationalIdentifier>DE-MDM- Landshauptstadt Duesseldorf</nationalIdentifier>
    </publicationCreator>
    <genericPublicationName>ParkingFacilityTablePublication</genericPublicationName>
    <genericPublicationExtension>
      <parkingFacilityTablePublication>
        <headerInformation>
          <confidentiality>noRestriction</confidentiality>
          <informationStatus>real</informationStatus>
        </headerInformation>
        <parkingFacilityTable>
          <parkingFacilityTableVersionTime>2016-12-23T00:16:07.394+01:00</parkingFacilityTableVersionTime>
          <parkingFacility id="2[PH 02 - Kunstsammlung]" version="1.0">
            <parkingFacilityName>
              <values>
                <value>PH 02 - Kunstsammlung</value>
              </values>
            </parkingFacilityName>
            <parkingFacilityRecordVersionTime>2016-07-14T15:22:07.000+02:00</parkingFacilityRecordVersionTime>
            <openingTimes/>
            <facilityLocation xsi:type="Point">
              <externalReferencing>
                <externalLocationCode>ePOB2</externalLocationCode>
                <externalReferencingSystem>GIS</externalReferencingSystem>
              </externalReferencing>
              <pointByCoordinates>
                <pointCoordinates>
                  <latitude>51.2283</latitude>
                  <longitude>6.775858</longitude>
                </pointCoordinates>
              </pointByCoordinates>
            </facilityLocation>
          </parkingFacility>
          [...]
        </parkingFacilityTable>
      </parkingFacilityTablePublication>
    </genericPublicationExtension>
  </payloadPublication>
</d2LogicalModel>

Hier werden statt den historischen Geolokalisationsmethoden einfach die üblichen WSG84-Geokoordinaten verwendet. Gleichzeitig ist der Datensatz ein Anzeichen dafür, dass in DATEX II verschiedene Repräsentationen von Datetimes  zusammenkommen. Hier werden nur zwei verschiedene Zeitzonen verwendet, es gibt allerdings auch Datensätze mit Zeitstempeln ohne Zeitzone, bei denen zumeist GMT und nicht UTC gemeint ist.

Richtig spannend werden die Daten allerdings erst mit einem zweiten Datensatz: der mit den Live-Daten:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<d2LogicalModel modelBaseVersion="2" extensionName="MDM" extensionVersion="00-01-03" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://datex2.eu/schema/2/2_0 http://bast.s3.amazonaws.com/schema/1370439856400/MDM-Profile_ParkingFacilityStatus.xsd" xmlns="http://datex2.eu/schema/2/2_0">
  <exchange>
    <supplierIdentification>
      <country>de</country>
      <nationalIdentifier>DE-MDM- Landshauptstadt Duesseldorf</nationalIdentifier>
    </supplierIdentification>
  </exchange>
  <payloadPublication xsi:type="GenericPublication" lang="de" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <publicationTime>2016-12-23T00:54:12.234+01:00</publicationTime>
    <publicationCreator>
      <country>de</country>
      <nationalIdentifier>DE-MDM- Landshauptstadt Duesseldorf</nationalIdentifier>
    </publicationCreator>
    <genericPublicationName>ParkingFacilityTableStatusPublication</genericPublicationName>
    <genericPublicationExtension>
      <parkingFacilityTableStatusPublication>
        <headerInformation>
          <confidentiality>noRestriction</confidentiality>
          <informationStatus>real</informationStatus>
        </headerInformation>
        <parkingFacilityStatus>
          <parkingFacilityOccupancy>0.25971732</parkingFacilityOccupancy>
          <parkingFacilityOccupancyTrend>decreasing</parkingFacilityOccupancyTrend>
          <parkingFacilityReference targetClass="ParkingFacility" id="2[PH 02 - Kunstsammlung]" version="1.0"/>
          <parkingFacilityStatus>open</parkingFacilityStatus>
          <parkingFacilityStatusTime>2016-12-23T00:48:05.504+01:00</parkingFacilityStatusTime>
          <totalNumberOfOccupiedParkingSpaces>147</totalNumberOfOccupiedParkingSpaces>
          <totalNumberOfVacantParkingSpaces>419</totalNumberOfVacantParkingSpaces>
          <totalParkingCapacityOverride>566</totalParkingCapacityOverride>
          <totalParkingCapacityShortTermOverride>566</totalParkingCapacityShortTermOverride>
        </parkingFacilityStatus>
        [...]
      </parkingFacilityTableStatusPublication>
    </genericPublicationExtension>
  </payloadPublication>
</d2LogicalModel>

Mit beiden Datensätzen zusammen ließe sich eine schöne Parkplatz-App basierend auf Live-Daten entwickeln. Ein wenig schade ist, dass im ersten Datensatz openingTimes keine Werte enthält, aus Sicht der Weiterverwendung wäre das ein wichtiges Feld. Jedoch ist auch das ein Charakteristikum von DATEX II: man merkt an verschiedenen Datensätzen, dass man eben all die Informationen bereitstellt, die da sind. Das kann bedeuten, dass Informationen weggelassen werden, das kann auch bedeuten, dass einzelne Daten fehlen.

Die Parkdaten sind übrigens auch ein schönes Beispiel für den grundsätzlichen Aufbau von DATEX II: der Standard kann um Extensions – in dem Fall die Parking Extension – erweitert werden. Die Dokumentationen dazu befinden sich meist ebenso auf der DATEX II Website. Die Feldbeschreibungen sind allerdings wie beim Basis-Datenmodell eher schmal gehalten, so dass man vielfach raten muss, was gemeint ist Beispiel: Was totalParkingCapacityShortTermOverride ist, geht aus der Dokumentation nicht hervor, und auch im Modell-Browser stehen keine relevanten Informationen über die Bedeutung des Feldes. Es ist übrigens ein kurzzeitiges Überschreiben des statischen Wertes für die Gesamtanzahl von Kurzzeit-Parkplätzen, wobei nicht ganz klar ist, warum man den Wert kurzzeitig überschreiben möchte.

ALERT-C und die Location Code List (LCL)

Die LCL und die dahinter stehende ALERT-C Lokalisation ist das für einen „normalsterblichen“ Entwickler mit Abstand absurdeste Konstrukt, was in DATEX II eingesetzt wird. Statt den gewohnten Geokoordinaten wird hier eine große Liste als Basis verwendet, in der 64.000 Wegkreuzungen in Deutschland fest definiert sind. Da es in Deutschland mehr Wegkreuzungen gibt, ist dies relativ ungenau. Um die Genauigkeit zu erhöhen, werden zum Teil Offsets von eben diesen definierten Punkten angegeben.

Hintergrund ist damals die sehr schmale Bandbreite von TMC gewesen, und eine einzelne Integer bis 65536 braucht nun mal nur 16 Bit, zwei Float-Werte für „normale“ WSG84-Geokoordinaten dagegen für Längen- und Breitengrad 2 x 32 = 64 Bit. Bei einer Übertragungsgeschwindigkeit von 60 Bit / Sekunde ist das ein durchaus relevanter Unterschied, weswegen man sich für die sparsamen 16 Bit entschieden hat.Dies hat so Entwicklern von heute, denen einzelne Bit in den meisten Fällen egal sein können, ein hässliches Ei ins Nest gesetzt.

Um zu verstehen, wie AlertC funktioniert, schauen wir uns den alertCLinear-Teil des Baustellen-DATEX II-Datensatzen mal genauer an:

<alertCLinear xsi:type="AlertCMethod2Linear">
  <alertCLocationCountryCode>de</alertCLocationCountryCode>
  <alertCLocationTableNumber>15</alertCLocationTableNumber>
  <alertCLocationTableVersion>15.1.D-160122</alertCLocationTableVersion>
  <alertCDirection>
    <alertCDirectionCoded>negative</alertCDirectionCoded>
  </alertCDirection>
  <alertCMethod2PrimaryPointLocation>
    <alertCLocation>
      <alertCLocationName>
        <values>
          <value lang="de">Kreuz Mönchengladbach-Wanlo</value>
        </values>
      </alertCLocationName>
      <specificLocation>12017</specificLocation>
    </alertCLocation>
  </alertCMethod2PrimaryPointLocation>
  <alertCMethod2SecondaryPointLocation>
    <alertCLocation>
      <alertCLocationName>
        <values>
          <value lang="de">Mönchengladbach-Güdderath</value>
        </values>
      </alertCLocationName>
      <specificLocation>12018</specificLocation>
    </alertCLocation>
  </alertCMethod2SecondaryPointLocation>
</alertCLinear>

Der erste wichtige Punkt ist alertCLocationTableNumber und alertCLocationTableVersion: dies beschreibt die Version der LCL-Tabelle. Von Zeit zu Zeit gibt es Updates der Tabelle, bei denen bestehende Wegekreuzungen korrigiert und Neue hinzugefügt werden. Die Tabellen sollten abwärtskompatibel sein, lies: man kann zum Dereferenzieren von LCL 14 Daten meist auch die LCL 15 nehmen, so ganz sichergestellt ist dies aber nicht.

Mit alertCMethod2PrimaryPointLocation und alertCMethod2SecondaryPointLocation werden dann zwei Punkte angegeben, zwischen denen sich die Baustelle befindet. Hierbei ist in Fahrtrichtung betrachtet der PrimaryPoint der Zielpunkt und der SecondaryPoint der Startpunkt – man fährt also von 2 zu 1 (worüber nicht nur ich gestolpert bin).

Unter specificLocation ist dann die Location ID zu finden, welche in der LCL-Tabelle nachzuschlagen ist. Aus der Tabelle kann man dann WSG84-Geokoordinaten und noch einiges mehr erhalten und so die Baustelle tatsächlich lokalisieren. Der alertCLocationName lässt sich auch in der LCL wiederfinden.

Auffällig ist dabei, das die Distanz zwischen zwei Punkten nicht der angegebenen Länge der Baustelle entspricht. Hin und wieder werden Offsets von einem LCL-Punkt angegeben, um die Lage der Baustelle zu präzisieren, aber auch dort stimmen Distanz + Offsets weder mit Luftlinie noch mit der gerouteten Distanz zwischen den beiden Punkten überein.

Hintergrund ist hier die Datenquelle: die Verkehrsplanung „denkt“ tatsächlich in gefahrener Distanz von Anschlusspunkten. Die hochpräzisen Planungsdaten der Planungsbüros z.B. für den Brückenbau spielen hierbei keine Rolle. Dies erklärt auch die Beliebtheit der LCL: die Autobahnmeisterei denkt eben genau in diesen in der LCL definierten Anschlusspunkten. Das bedeutet aber auch, dass bei den Offsets kein Routing-Algorithmus angegeben werden kann, mit dem der Offset dann in eine Route verwandelt wird: der Offset ist das, was die Autobahnmeisterei in etwa seit dem Anschlusspunkt gefahren ist.

Interessantes Bonus-Feature der LCL ist übrigens ein Routing über die Anschlussstellen, welches sich auch im DATEX II-Datensatz widerspiegelt. Der XML-Node alertCDirectionCoded ist ein Hinweis auf die beiden Spalten NEGATIVE_OFFSET und POSITIVE_OFFSET der LCL. Mit diesen Spalten kann man sich so auf den neuen Punkt handeln. Durch mehrere unpräzise Formulierungen in dem Zusammenhang kann aber nicht sicher auf alertCDirectionCoded vertraut werden, in den meisten Fällen funktioniert das Routing korrekt, wenn man alertCMethod2SecondaryPointLocation als Startpunkt wählt. Das Routing ist allerdings eh hochgradig unpräzise, da eben nur Anschlussstellen als Punkte zur Verfügung stehen, so dass das Ergebnis kaum brauchbar ist und man eh auf eine echte Routing-Library zurückgreift.

Mehr Daten

Zur Zeit ist die Menge der öffentlichen DATEX II-Daten eher begrenzt, Datenquelle ist vor allem der Mobilitäts-Daten-Marktplatz des Bundes. Dort befinden sich vor allem Baustellen-, Sperranhänger- und Statistik-Daten von Autobahnen sowie eine Hand voll Parkplatz- sowie Baustellen-Daten von einzelnen Kommunen (was auch schon eine ganze Menge ist, gerade die Zählungen hier aus NRW sind ein hochspannender Datensatz).

Doch Änderung ist in Sicht: im Zuge der OpenData-Bemühungen des Bundes und der Länder werden zunehmend mehr Daten im DATEX II-Format zur Verfügung stehen, so dass es erst Recht Sinn macht, sich damit intensiver zu beschäftigen (Beispiel: erste DATEX II Datensätze auf OpenNRW). Denn auch wenn DATEX II im ersten Moment nicht vergnügungssteuerpflichtig erscheint, so ist es als Austauschformat doch im behördlichen  überregionalen Bereich weit verbreitet, und wenn man Mobilität mit Hilfe von Digitalisierung besser machen möchte, so muss man sich zwangsweise damit beschäftigen.

Und vielleicht gibt es ja über die Zeit auch professionelles Angebote, welches die DATEX II-Daten konvertieren – Unternehmen wie con terra, welche verschiedene Datensätze aus dem MDM für den BMVI Data Run in GeoJSON konvertiert haben, haben sich ja bereits auf den Weg gemacht, um solche Angebote zu schaffen. Disclaimer: ich arbeite mit con terra in diesem Punkt zusammen.

Wertvolle Ressourcen

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.