Übung: Erstellung einer Document-Type-Definition für XML-Rechnungen

https://bildung.social/@oerinformatik/111980708596828078

https://oer-informatik.de/xml-dtd-uebung

XML, DTD, Document Type Definition, Inhaltsmodell, Mixed Content, Attributdeklaration, ID-Attribut, Validierung, Übungsaufgaben, Prüfungsvorbereitung

tl/dr; (ca. 33 min Lese- und Bearbeitungszeit): Für eine XML-Rechnung soll Schritt für Schritt eine Document-Type-Definition erstellt werden, die einen relativ großen Funktionsumfang der DTD enthält. Geeignet zur Vertiefung des XML-DTD-Wissens in Kombination mit dem DTD-Artikel [AI-Assisted]. (Zuletzt geändert am 28.10.2026)

Dieser Artikel ist Bestandteil einer Serie zu den XML-Grundlagen:

Sämtliche Aufgaben lassen sich mit einem Tool wie dem Online XML-Validator von truugo.com überprüfen. Lokal geht das auf der Kommandozeile mit xmllint (Teil von libxml2, unter Linux meist vorinstalliert): xmllint --noout --valid <datei>.xml. Lade in Online-Validatoren nur Testdaten hoch, nie echte Kunden- oder Firmendaten oder andere personenbezogene Daten – Du weißt nicht, was der Anbieter damit macht.

Hinweise zur Bearbeitung: Bis zur Teil-1-Prüfung der IT-Berufe solltest Du die Basiskompetenz beherrschen, also Aufgabe 1.1, Aufgabe 1.2, Aufgabe 1.3, Aufgabe 1.4 und Aufgabe 1.5. Als FIA musst Du zur Teil-2-Prüfung Aufgaben auf Kernkompetenz-Ebene lösen können, das sind Aufgabe 2.1, Aufgabe 2.2, Aufgabe 2.3, Aufgabe 2.4, Aufgabe 2.5 und Aufgabe 2.6. Die Aufgaben bauen aufeinander auf und stehen daher nicht nach Kompetenzstufe sortiert, sondern in der Reihenfolge, in der die DTD Schritt für Schritt entsteht. Erweitere Deine DTD von Aufgabe zu Aufgabe und prüfe jeden Zwischenstand mit einem Validator, bevor Du die Beispiellösung aufklappst.

Aufgabenstellung der Gesamtrechnung

Rechnungen sollen als XML-Datei exportiert werden. Hierzu liegt ein XML-Beispielauszug vor, für den in kleinen Schritten eine Document-Type-Definition (DTD) erstellt werden soll.

Die Gesamtdatei sieht folgendermaßen aus, wird aber gleich in kleineren Schritten realisiert:

<?xml version='1.0' encoding='UTF-8'?>

<rechnung nr="1234" datum="12.01.2024">
    <absender>
        <adresse>
            <firmenname>Baschira GmbH</firmenname>
            <postfach>Postfach 12344</postfach>
            <plz>10248</plz>
            <ort>Berlin</ort>
            <telefon>0124 / 6567891</telefon>
            <telefon>0234 / 7567894</telefon>
        </adresse>
    </absender>
    <empfaenger>
        <adresse kundennummer="1234">
            <vorname>Max</vorname>
            <nachname>Mustermann</nachname>
            <namenszusatz>3. OG links</namenszusatz>
            <strasse>Hauptstraße</strasse>
            <hausnr>23</hausnr>
            <plz>12345</plz>
            <ort>Berlin</ort>
        </adresse>
    </empfaenger>
    <positionen>
        <position nr="pos1">
            <anzahl>2</anzahl>
            <artikelNr>12345</artikelNr>
            <artikelName>Produkt1</artikelName>
            <einzelpreis>12.50</einzelpreis>
            <betragNetto>25.00</betragNetto>
        </position>

        <position nr="pos2">
            <anzahl>1</anzahl>
            <artikelNr>54321</artikelNr>
            <artikelName>Produkt2</artikelName>
            <einzelpreis>75.00</einzelpreis>
            <betragNetto>75.00</betragNetto>
        </position>
    </positionen>
    <summe>
        <netto>100.00</netto>
        <mwst>19.00</mwst>
        <brutto>119.00</brutto>
    </summe>
    <status>
        <statusmeldung datum="22.02.2024" statusart="unbekannt" />
        <statusmeldung datum="24.02.2024" statusart="vorbereitet" />
    </status>
    <hinweise>
        <notiz>Dies ist eine Korrektur der Rechnung 1234 über <netto>80.00</netto> Euro.</notiz>
        <text>Dies ist eine Korrektur der Rechnung 1234 über 80.00 Euro.</text>
        <weitereadresse>
            Versandadresse
            <adresse>
                <firmenname>Baschira GmbH Filiale Hamburg</firmenname>
                <postfach>Postfach 12344</postfach>
                <plz>20248</plz>
                <ort>Hamburg</ort>
            </adresse>
        </weitereadresse>
        <text>Noch ein Text</text>
    </hinweise>
</rechnung>

Falls Du das nicht in Einzelschritten lösen willst, sondern in einem großen Rutsch, hier noch die Randbedingungen: Die DTD soll dafür sorgen, dass alle Elemente in der Art vorkommen, wie sie im Beispiel genannt sind. Alle Elemente bis auf telefon, namenszusatz, statusmeldung und hinweise müssen verpflichtend vorkommen, wenn sie im Beispiel genannt sind. Adressen können von Privatpersonen (vorname, nachname) oder Firmen (firmenname) angegeben werden. Die Adresse kann als Straße oder Postfach angegeben werden. Eine Rechnung muss mindestens eine Rechnungsposition haben. In hinweise können die drei genannten Elemente beliebig häufig vorkommen, wobei weitereadresse Text oder adresse enthalten darf und notiz beliebigen Inhalt. Die Positionsnummern sollen einzigartig vergeben werden. Aber langsam, Schritt für Schritt…

Du möchtest eigene Aufgaben zum Üben von einem KI-Sprachmodell generieren lassen?

Kopiere den Text in ein KI-Sprachmodell Deiner Wahl und passe Kompetenzstufe, Anzahl, Bearbeitungszeit und Szenario bei Bedarf an. Wie die Aufgaben aufgebaut sind, beschreibt der Artikel Wie sind die Aufgaben aufgebaut?. Prüfe die Ergebnisse mit dem Lehrartikel: KI-Sprachmodelle machen Fehler.

Erstelle neue Übungsaufgaben zum Thema „Übung: Erstellung einer
Document-Type-Definition für XML-Rechnungen“.

Bauplan: Halte Dich an Aufbau, Kompetenzstufen, Operatoren,
Anforderungsbereiche, Punkte und Zeitschätzung, die im Artikel
https://oer-informatik.de/aufgaben-aufbau beschrieben sind.

Fachliche Grundlage:
- https://oer-informatik.de/xml-dtd-uebung
- Stilbeispiel: https://oer-informatik.de/xml-dtd-uebung

Die Aufgaben sollen Inhalte zu diesen Schlagwörtern abdecken:
- XML
- DTD
- Document Type Definition
- Inhaltsmodell
- Mixed Content
- Attributdeklaration
- ID-Attribut
- Validierung

Kompetenzstufe: Kernkompetenz (alternativ: Basiskompetenz, Profilkompetenz, Expertise)
Anzahl: 1 Aufgabe mit Teilaufgaben
Bearbeitungszeit in Minuten ca.: <5 bis 30 min>
Szenario: eines der Szenarien aus dem Bauplan

Vorgehen:
1. Lies zuerst die verlinkten Artikel. Kannst Du keine Webseiten
   abrufen, sag mir das, statt zu raten.
2. Steht bei einer Angabe noch ein Platzhalter in <…>, frag mich
   zuerst danach. Richte Punkte und Zahl der Teilaufgaben nach der
   Bearbeitungszeit (ca. 0,9 min je Punkt).
3. Gib je Aufgabe Titel mit Kompetenzstufe, Ausgangssituation und
   Teilaufgaben mit Operator und Punktzahl aus, dazu die geschätzte
   Bearbeitungszeit.
4. Gib die Beispiellösungen mit Punkteverteilung erst aus, wenn ich
   danach frage.

Aufgabe 1.1: Die Grundstruktur für eine XML-Rechnung (Basiskompetenz)

Die Grundstruktur der Rechnung ist folgende. Das Element hinweise soll optional sein, es wird zunächst angenommen, dass alle Elemente unterhalb von rechnung ausschließlich parsbaren Text enthalten. Erstelle hierfür eine gültige DTD. (3 Punkte)

<?xml version='1.0' encoding='UTF-8'?>
<rechnung>
    <absender></absender>
    <empfaenger></empfaenger>
    <positionen></positionen>
    <summe></summe>
    <status></status>
    <hinweise></hinweise>
</rechnung>
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE rechnung [
<!ELEMENT rechnung (absender, empfaenger, positionen, summe, status, hinweise?)>
<!ELEMENT absender (#PCDATA)>
<!ELEMENT empfaenger (#PCDATA)>
<!ELEMENT positionen (#PCDATA)>
<!ELEMENT summe (#PCDATA)>
<!ELEMENT status (#PCDATA)>
<!ELEMENT hinweise (#PCDATA)>
]>

Aufgabe 1.2: Absender ergänzen als Firmenadresse (Basiskompetenz)

Das Element absender wird angepasst: hier soll eine Firmenadresse nach folgendem Vorbild enthalten sein. Das Element telefon soll optional sein. (3 Punkte)

    <absender>
        <adresse>
            <firmenname>Baschira GmbH</firmenname>
            <postfach>Postfach 12344</postfach>
            <plz>10248</plz>
            <ort>Berlin</ort>
            <telefon>0124 / 6567891</telefon>
            <telefon>0234 / 7567894</telefon>
        </adresse>
    </absender>
<!ELEMENT absender (adresse)>
<!ELEMENT adresse (firmenname, postfach, plz, ort, telefon*)> 
      <!ELEMENT firmenname (#PCDATA)>
      <!ELEMENT postfach (#PCDATA)>
      <!ELEMENT plz (#PCDATA)>
      <!ELEMENT ort (#PCDATA)>
      <!ELEMENT telefon (#PCDATA)>   

Aufgabe 2.1: Empfänger ergänzen als Privatadresse (Kernkompetenz)

Auch für das Element empfaenger soll eine Adresse hinterlegt werden. Diese ist aber anders aufgebaut, daher muss das oben definierte Element adresse angepasst werden: Adressen können von Privatpersonen (vorname, nachname) oder Firmen (firmenname) angegeben werden. Die Adresse kann als Straße oder Postfach angegeben werden. Außerdem soll es die Möglichkeit geben, nach dem Firmen- oder Privatnamen einen namenszusatz zu erfassen. Die obigen Firmenadressen sollen weiterhin in der genannten Form unter absender stehen. (5 Punkte)

    <empfaenger>
        <adresse>
            <vorname>Max</vorname>
            <nachname>Mustermann</nachname>
            <namenszusatz>3. OG links</namenszusatz>
            <strasse>Hauptstraße</strasse>
            <hausnr>23</hausnr>
            <plz>12345</plz>
            <ort>Berlin</ort>
        </adresse>
    </empfaenger>
<!ELEMENT absender (adresse)>
<!ELEMENT empfaenger (adresse)>
  <!ELEMENT adresse (((vorname, nachname)|firmenname), namenszusatz?, ((strasse, hausnr) | postfach), plz, ort, telefon*)> 
    <!ELEMENT vorname (#PCDATA)>
    <!ELEMENT nachname (#PCDATA)>
    <!ELEMENT namenszusatz (#PCDATA)>
    <!ELEMENT firmenname (#PCDATA)>
    <!ELEMENT strasse (#PCDATA)>
    <!ELEMENT hausnr (#PCDATA)>
    <!ELEMENT postfach (#PCDATA)>
    <!ELEMENT plz (#PCDATA)>
    <!ELEMENT ort (#PCDATA)>
    <!ELEMENT telefon (#PCDATA)>   

Aufgabe 1.3: Rechnungspositionen erfassen (Basiskompetenz)

Es sollen die Rechnungspositionen erfasst werden, wobei sichergestellt sein muss, dass mindestens eine Position in jeder Rechnung gespeichert wird. (3 Punkte)

    <positionen>
        <position>
            <anzahl>2</anzahl>
            <artikelNr>12345</artikelNr>
            <artikelName>Produkt1</artikelName>
            <einzelpreis>12.50</einzelpreis>
            <betragNetto>25.00</betragNetto>
        </position>

        <position>
            <anzahl>1</anzahl>
            <artikelNr>54321</artikelNr>
            <artikelName>Produkt2</artikelName>
            <einzelpreis>75.00</einzelpreis>
            <betragNetto>75.00</betragNetto>
        </position>
    </positionen>
<!ELEMENT positionen (position)+>
    <!ELEMENT position (anzahl, artikelNr, artikelName, einzelpreis, betragNetto)>
      <!ELEMENT nr (#PCDATA)>
      <!ELEMENT anzahl (#PCDATA)>
      <!ELEMENT artikelNr (#PCDATA)>
      <!ELEMENT artikelName (#PCDATA)>
      <!ELEMENT einzelpreis (#PCDATA)>
      <!ELEMENT betragNetto (#PCDATA)>  

Aufgabe 1.4: Rechnungssumme (Basiskompetenz)

Die Rechnungssumme soll zwingend in der Reihenfolge netto, mwst, brutto erfasst werden. (2 Punkte)

        <summe>
        <netto>100.00</netto>
        <mwst>19.00</mwst>
        <brutto>119.00</brutto>
    </summe>
  <!ELEMENT summe (netto, mwst, brutto)>
    <!ELEMENT netto (#PCDATA)>
    <!ELEMENT mwst (#PCDATA)>  
    <!ELEMENT brutto (#PCDATA)>

Aufgabe 2.2: Hinweise (Kernkompetenz)

Im Element hinweise können drei verschiedene Einträge stehen. Es muss ein Unterelement geben, es können aber beliebig viele sein. In einer notiz darf alles stehen (beliebiger Text und Unterelemente), in einem text nur Text und in einer weitereadresse zunächst auch nur Text. (3 Punkte)

    <hinweise>
        <notiz>Dies ist eine Korrektur der Rechnung 1234 über <netto>80.00</netto> Euro.</notiz>
        <text>Dies ist eine Korrektur der Rechnung 1234 über 80.00 Euro.</text>
        <weitereadresse>
            Versandadresse
        </weitereadresse>
        <text>Noch ein Text</text>
    </hinweise>
<!ELEMENT hinweise (notiz | text | weitereadresse)+>
  <!ELEMENT notiz ANY>
  <!ELEMENT text (#PCDATA)>
  <!ELEMENT weitereadresse (#PCDATA)>

Aufgabe 2.3: Hinweise: weitere Adresse (Kernkompetenz)

Das Element weitereadresse darf Text enthalten und adresse-Elemente. (2 Punkte)

        <weitereadresse>
            Versandadresse
            <adresse>
                <firmenname>Baschira GmbH Filiale Hamburg</firmenname>
                <postfach>Postfach 12344</postfach>
                <plz>20248</plz>
                <ort>Hamburg</ort>
            </adresse>
        </weitereadresse>

Realisierung als mixed content - eine Bestimmung der Reihenfolge ist nicht möglich, #PCDATA muss als erstes genannt werden.

    <!ELEMENT weitereadresse (#PCDATA |adresse)*>

Aufgabe 2.4: Rechnungsnummer und Datum (Kernkompetenz)

Für jede Rechnung soll im Root-Element die Rechnungsnummer und das Rechnungsdatum erfasst werden.

a) Welche Gründe sprechen dafür, das als Attribut zu realisieren, was spricht dafür, das als Unterelement zu realisieren? (4 Punkte)

Für Elemente spricht:

  • später leichter durch weitere Unterelemente erweiterbar

  • mehrere gleichartige Werte speicherbar (z.B. mehrere Datumsangaben oder mehrere Rechnungsnummern)

  • leichter über Baumstruktur erreichbar / einheitlicher als gemischt Attribut/Element

Für Attribute spricht:

  • kompakt in der Schreibweise

  • Reihenfolge muss nicht / kann nicht festgelegt werden

  • mehr Einschränkungen im Rahmen der DTD möglich (Eindeutigkeit per ID, feste Wertelisten, Defaultwerte)

b) Es wird die Realisierung über Attribute beschlossen, diese sollen zwingend Werte enthalten. Erstelle die entsprechende DTD. (2 Punkte)

    <rechnung nr="1234" datum="12.01.2024">...</rechnung>
<!ATTLIST rechnung
   nr CDATA #REQUIRED
   datum CDATA #REQUIRED >

Aufgabe 1.5: Kundennummer (Basiskompetenz)

Die Kundennummer soll als optionales Attribut erfasst werden, da sie nur beim Empfänger, nicht aber beim Absender in der adresse auftritt. (1 Punkt)

<empfaenger>
        <adresse kundennummer="1234">
   <!ATTLIST adresse
   kundennummer CDATA #IMPLIED >

Aufgabe 2.5: Status (Kernkompetenz)

Für jede Rechnung soll ein status erfasst werden aus beliebig vielen Statusmeldungen, die jeweils nur Datum und eine Statusart (gültig ist nur: vorbereitet, erstellt, versendet, bezahlt, angemahnt oder unbekannt) enthalten. Elementeinhalt darf statusmeldung nicht haben. (4 Punkte)

    <status>
        <statusmeldung datum="22.02.2024" statusart="unbekannt" />
        <statusmeldung datum="24.02.2024" statusart="vorbereitet" />
    </status>
<!ELEMENT status (statusmeldung)*>
      <!ELEMENT statusmeldung EMPTY>
        <!ATTLIST statusmeldung
        datum CDATA #REQUIRED
        statusart (vorbereitet | erstellt | versendet | bezahlt | angemahnt | unbekannt) #REQUIRED>

Aufgabe 2.6: Positionsnummer (Kernkompetenz)

a) Für die einzelnen Rechnungspositionen soll jeweils eine zwingend eindeutige ID vergeben werden. Erstelle die entsprechende DTD. (2 Punkte)

      <positionen>
        <position nr="pos1">
           ...
        </position>

        <position nr="pos2">
            ...
        </position>
    </positionen>
   <!ATTLIST position
   nr ID #REQUIRED >

b) Warum kann das Attribut nr als Attributtyp ID nicht einfach laufende Nummern enthalten? (2 Punkte)

Der Attributtyp ID schreibt fest, dass der Wert des Attributs dieselben Regeln erfüllen muss wie ein XML-Elementname (z. B. keine Ziffer am Anfang). Man muss daher die Werte anpassen, z.B. durch ein führendes “pos”. Wenn der Attributtyp zu CDATA oder NMTOKEN geändert wird, können laufende Nummern genutzt werden. Allerdings entfällt dann die Möglichkeit, zu überprüfen, ob die Werte eindeutig sind.

Die Gesamtlösung – das Big Picture

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE rechnung [
<!ELEMENT rechnung (absender, empfaenger, positionen, summe, status, hinweise?)>
  <!ELEMENT empfaenger (adresse)>
  <!ELEMENT absender (adresse)>
    <!ELEMENT adresse (((vorname, nachname)|firmenname), namenszusatz?, ((strasse, hausnr) | postfach), plz, ort, telefon*)> 
      <!ELEMENT vorname (#PCDATA)>
      <!ELEMENT nachname (#PCDATA)>
      <!ELEMENT namenszusatz (#PCDATA)>
      <!ELEMENT firmenname (#PCDATA)>
      <!ELEMENT strasse (#PCDATA)>
      <!ELEMENT hausnr (#PCDATA)>
      <!ELEMENT postfach (#PCDATA)>
      <!ELEMENT plz (#PCDATA)>
      <!ELEMENT ort (#PCDATA)>
      <!ELEMENT telefon (#PCDATA)>      
  <!ELEMENT positionen (position)+>
    <!ELEMENT position (anzahl, artikelNr, artikelName, einzelpreis, betragNetto)>
      <!ELEMENT anzahl (#PCDATA)>
      <!ELEMENT artikelNr (#PCDATA)>
      <!ELEMENT artikelName (#PCDATA)>
      <!ELEMENT einzelpreis (#PCDATA)>
      <!ELEMENT betragNetto (#PCDATA)>
  <!ELEMENT summe (netto, mwst, brutto)>
    <!ELEMENT netto (#PCDATA)>
    <!ELEMENT mwst (#PCDATA)>  
    <!ELEMENT brutto (#PCDATA)>
  <!ELEMENT status (statusmeldung)*>
  <!ELEMENT statusmeldung EMPTY>
  <!ELEMENT hinweise (notiz | text | weitereadresse)+>
    <!ELEMENT notiz ANY>
    <!ELEMENT text (#PCDATA)>
    <!ELEMENT weitereadresse (#PCDATA |adresse)*>
  <!ATTLIST rechnung
   nr CDATA #REQUIRED
   datum CDATA #REQUIRED >
   <!ATTLIST adresse
   kundennummer CDATA #IMPLIED >
   <!ATTLIST position
   nr ID #REQUIRED >
   <!ATTLIST statusmeldung
   datum CDATA #REQUIRED
   statusart (vorbereitet | erstellt | versendet | bezahlt | angemahnt | unbekannt) #REQUIRED>
]>

<rechnung nr="1234" datum="12.01.2024">
    <absender>
        <adresse>
            <firmenname>Baschira GmbH</firmenname>
            <postfach>Postfach 12344</postfach>
            <plz>10248</plz>
            <ort>Berlin</ort>
            <telefon>0124 / 6567891</telefon>
            <telefon>0234 / 7567894</telefon>
        </adresse>
    </absender>
    <empfaenger>
        <adresse kundennummer="1234">
            <vorname>Max</vorname>
            <nachname>Mustermann</nachname>
            <namenszusatz>3. OG links</namenszusatz>
            <strasse>Hauptstraße</strasse>
            <hausnr>23</hausnr>
            <plz>12345</plz>
            <ort>Berlin</ort>
        </adresse>
    </empfaenger>
    <positionen>
        <position nr="pos1">
            <anzahl>2</anzahl>
            <artikelNr>12345</artikelNr>
            <artikelName>Produkt1</artikelName>
            <einzelpreis>12.50</einzelpreis>
            <betragNetto>25.00</betragNetto>
        </position>

        <position nr="pos2">
            <anzahl>1</anzahl>
            <artikelNr>54321</artikelNr>
            <artikelName>Produkt2</artikelName>
            <einzelpreis>75.00</einzelpreis>
            <betragNetto>75.00</betragNetto>
        </position>
    </positionen>
    <summe>
        <netto>100.00</netto>
        <mwst>19.00</mwst>
        <brutto>119.00</brutto>
    </summe>
    <status>
        <statusmeldung datum="22.02.2024" statusart="unbekannt" />
        <statusmeldung datum="24.02.2024" statusart="vorbereitet" />
    </status>
    <hinweise>
        <notiz>Dies ist eine Korrektur der Rechnung 1234 über <netto>80.00</netto> Euro.</notiz>
        <text>Dies ist eine Korrektur der Rechnung 1234 über 80.00 Euro.</text>
        <weitereadresse>
            Versandadresse
            <adresse>
                <firmenname>Baschira GmbH Filiale Hamburg</firmenname>
                <postfach>Postfach 12344</postfach>
                <plz>20248</plz>
                <ort>Hamburg</ort>
            </adresse>
        </weitereadresse>
        <text>Noch ein Text</text>
    </hinweise>
</rechnung>

Hinweis zur Nachnutzung als Open Educational Resource (OER)

Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: “Übung: Erstellung einer Document-Type-Definition für XML-Rechnungen” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/xml-dtd-uebung veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/datenformate/xml. Erstellt mit KI-Assistenz; von mir umfassend redaktionell überarbeitet, geprüft und freigegeben. Stand: 28.10.2026.

[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]

Kommentare gerne per Mastodon, Verbesserungsvorschläge per gitlab issue (siehe oben). Beitrag teilen: