====== std.xml ====== XML **erzeugen** und einfache Dokumente **zerlegen**: Sonderzeichen maskieren, Deklaration, Elemente und Dokumente schreiben, ein Element in eine binäre Eintragsstruktur überführen, formatieren. Die Unit hat kein Dokumentmodell und keinen Baum — sie arbeitet zeichenweise über den Text. → [[lyx_-_programmiersprache:units:html|std.html]] · [[lyx_-_programmiersprache:units:string|std.string]] · [[lyx_-_programmiersprache:units|Standard Library]] Alle Beispiele dieser Seite sind mit ''lyxc 1.0.21A'' übersetzt und ausgeführt; die gezeigten Ausgaben sind echte Programmausgaben. **Einsatz:** Ausgabe von Konfigurationen, RSS/Atom-Feeds, sitemap.xml, einfacher Datenaustausch. Für das **Lesen** fremder Dokumente ist die Unit nur begrenzt geeignet — siehe die Kästen unten. > **Die Prüf- und Lesefunktionen halten nicht, was ihre Namen versprechen.** Vor dem Einsatz gegen fremde Daten lesen: > > * ''IsValid'' prüft **keine** Wohlgeformtheit — '' * ''ParseString'' liefert **immer ''1''** und schreibt nichts in den Ausgabepuffer ([[https://github.com/SEOLizer/LyX-Compiler/issues/1423|#1423]]). > * ''PrettyPrint'' bricht Textinhalte um und **verändert damit das Dokument** ([[https://github.com/SEOLizer/LyX-Compiler/issues/1424|#1424]]). > > Verlässlich sind die Schreibfunktionen, das Maskieren und die Array-Familie. ---- ===== Maskieren ===== ^ Signatur ^ Maskiert ^ Ergänzt Anführungszeichen ^ | ''EscapeText(input: pchar, output: pchar): int64'' | ''&'', ''<'', ''>'' | nein | | ''EscapeAttribute(input: pchar, output: pchar): int64'' | ''&'', ''<'', ''"'' | **ja** — der Wert wird gleich in ''"…"'' gesetzt | Die Aufteilung folgt der XML-Spezifikation: Im Textinhalt ist ''"'' unkritisch, in einem Attributwert dagegen das Anführungszeichen — und ''>'' ist dort erlaubt. Beide Funktionen hängen ein Nullbyte an und liefern die Länge ohne dieses. > **''EscapeAttribute'' schreibt die Anführungszeichen selbst.** Wer sie im eigenen Text zusätzlich setzt, bekommt doppelte. Für die Ausgabe also ''%%name=%%'' + Ergebnis, ohne weitere Zeichen. > > Anders als ''std.html'' fasst die Unit **kein Byte 160 an** — UTF-8-Text bleibt unversehrt. ---- ===== Schreiben ===== ^ Signatur ^ Beschreibung ^ | ''WriteDeclaration(output, version, encoding): int64'' | '''' | | ''WriteElement(output, tagName, attrs, attrCount, text, indent): int64'' | Ein Element mit Attributen, Text und Einzug; ohne Text entsteht ''<tag/>''. Schließt mit Zeilenumbruch. | | ''WriteDocument(output, rootName, rootText, version, encoding): int64'' | Deklaration + Wurzelelement in einem Aufruf | **Attribut-Format:** ''attrs'' ist ein zusammenhängender Speicherbereich mit **128 Byte je Attribut** — die ersten 64 Byte der Name, die zweiten 64 der Wert, jeweils nullterminiert. Für ''attrCount'' Attribute also ''attrCount × 128'' Byte. Werte werden **nicht** maskiert; wer Sonderzeichen erwartet, ruft vorher ''EscapeText'' (ohne die Anführungszeichen von ''EscapeAttribute''). > **Die drei ''Write…''-Funktionen terminieren ihre Ausgabe nicht.** Sie liefern nur die Länge; ein Nullbyte setzen sie — anders als ''EscapeText'' und ''ArrayToXML'' — nicht ([[https://github.com/SEOLizer/LyX-Compiler/issues/1425|#1425]]). Bei einem wiederverwendeten Puffer stehen sonst die Reste des vorherigen Inhalts dahinter. Deshalb im Beispiel jedes Mal ''%%StrSetChar(o, n, 0);%%''. import std.xml; import std.alloc; import std.string; fn main(): int64 { var o: pchar := alloc(1024) as pchar; // Escapen: Text und Attributwert unterscheiden sich EscapeText("Tom & Jerry \"zitiert\""c, o); PrintLn(StrConcat("EscapeText: ", o)); EscapeAttribute("Tom & Jerry \"zitiert\""c, o); PrintLn(StrConcat("EscapeAttribute: ", o)); // Dokument schreiben - Write... terminiert NICHT, also selbst nullsetzen var n: int64 := WriteDocument(o, "config"c, "Inhalt"c, "1.0"c, "UTF-8"c); StrSetChar(o, n, 0); PrintLn("WriteDocument:"); PrintLn(o); // Element mit zwei Attributen: // Namen liegen bei Offset j*128, Werte bei j*128+64 - je hoechstens 64 Byte var attrs: pchar := alloc(256) as pchar; var i: int64 := 0; while (i < 256) { StrSetChar(attrs, i, 0); i := i + 1; } StrSetChar(attrs, 0, 105); StrSetChar(attrs, 1, 100); // "id" StrSetChar(attrs, 64, 55); // "7" StrSetChar(attrs, 128, 116); StrSetChar(attrs, 129, 121); // "ty" StrSetChar(attrs, 192, 65); // "A" n := WriteElement(o, "item"c, attrs, 2, "Text"c, 2); StrSetChar(o, n, 0); Print(StrConcat("WriteElement: ", o)); n := WriteElement(o, "leer"c, 0 as pchar, 0, ""c, 0); StrSetChar(o, n, 0); Print(StrConcat("leeres Element: ", o)); return 0; } EscapeText: Tom & Jerry <b> "zitiert" EscapeAttribute: "Tom & Jerry <b> "zitiert"" WriteDocument: Inhalt WriteElement: Text leeres Element: ---- ===== Die Array-Familie ===== Der einzige Weg dieser Unit, XML-Inhalt tatsächlich **auszulesen**. Ein Eintrag ist ein binärer Block: ^ Offset ^ Inhalt ^ | 0–1 | Länge des Namens (zwei Byte, niederwertiges zuerst) | | 2 … | Name | | danach 2 Byte | Länge des Textes | | danach | Text | ^ Signatur ^ Beschreibung ^ | ''XMLToArray(xml: pchar, output: pchar): int64'' | Wurzelelement in diese Form überführen; ''1'' bei Erfolg, ''0'' wenn kein ''<'' gefunden wird | | ''CreateArrayEntry(name: pchar, text: pchar, output: pchar): int64'' | Eintrag von Hand aufbauen; liefert die Bytezahl | | ''GetArrayEntryName(arr: pchar, output: pchar): int64'' | Namen herauslesen (nullterminiert) | | ''GetArrayEntryText(arr: pchar, output: pchar): int64'' | Text herauslesen (nullterminiert) | | ''ArrayToXML(arr: pchar, output: pchar): int64'' | Zurück nach ''<name>text</name>'' | import std.xml; import std.alloc; import std.string; fn J(b: bool): pchar { if (b) { return "gueltig"; } return "ungueltig"; } fn Leer(p: pchar, n: int64): void { var i: int64 := 0; while (i < n) { StrSetChar(p, i, 0); i := i + 1; } } fn main(): int64 { var arr: pchar := alloc(1024) as pchar; var o: pchar := alloc(1024) as pchar; Leer(arr, 1024); Leer(o, 1024); // Eintrag anlegen: 2 Byte Namenslaenge, Name, 2 Byte Textlaenge, Text var n: int64 := CreateArrayEntry("titel"c, "Wert"c, arr); PrintLn(StrConcat("CreateArrayEntry, Bytes: ", IntToStr(n))); GetArrayEntryName(arr, o); PrintLn(StrConcat(" Name: ", o)); Leer(o, 1024); GetArrayEntryText(arr, o); PrintLn(StrConcat(" Text: ", o)); // Und zurueck nach XML Leer(o, 1024); PrintLn(StrConcat("ArrayToXML, Bytes: ", IntToStr(ArrayToXML(arr, o)))); PrintLn(StrConcat(" XML: ", o)); // Pruefen und zaehlen PrintLn(StrConcat("IsValid('x'): ", J(IsValid("x"c)))); PrintLn(StrConcat("IsValid(''): ", J(IsValid(""c)))); PrintLn(StrConcat("IsValid('x'): ", IntToStr(CountElements("x"c)))); PrintLn(StrConcat("Count('5 < 7'): ", IntToStr(CountElements("5 < 7"c)))); return 0; } CreateArrayEntry, Bytes: 13 Name: titel Text: Wert ArrayToXML, Bytes: 19 XML: Wert IsValid('x'): gueltig IsValid(''): gueltig IsValid('x'): 3 Count('5 < 7'): 2 Die Eintragsstruktur hält **ein** Element mit Namen und Text — keine Attribute, keine Kinder, keine Liste. Wer mehrere Elemente braucht, legt mehrere Blöcke hintereinander und verwaltet die Offsets selbst. ---- ===== Prüfen und Zählen ===== ^ Signatur ^ Was wirklich geprüft wird ^ | ''IsValid(xml: pchar): bool'' | ob der Text — nach BOM, Leerraum und optionaler Deklaration — mit ''<'' beginnt | | ''CountElements(xml: pchar): int64'' | Zahl der ''<'', denen kein ''/'', ''!'' oder ''?'' folgt | > **Beide arbeiten ohne Unterscheidung zwischen Markup und Text.** ''<a><b></a>'' (Tags über Kreuz), '' > Für eine Eingangsprüfung fremder Dokumente reicht das nicht. Wer sie braucht, baut sie über einen eigenen Tag-Stapel — oder prüft, ob das Dokument nach dem Verarbeiten die erwarteten Elementnamen enthält. ---- ===== Formatieren ===== ''PrettyPrint(input, output, indentSize)'' rückt Elemente ein und setzt Zeilenumbrüche. > **''PrettyPrint'' verändert das Dokument.** Aus ''<a><b>x</b><c/></a>'' wird > > x > > Der Inhalt von ''b'' ist danach ''x\n'' statt ''x'' — in XML ist Leerraum im Textinhalt bedeutsam. Zusätzlich stimmt die Tiefe der schließenden Tags nicht ([[https://github.com/SEOLizer/LyX-Compiler/issues/1424|#1424]]). > > Für die Anzeige im Terminal brauchbar; nicht für Dokumente, die anschließend verglichen, signiert oder weiterverarbeitet werden. ---- ===== Fehlercodes ===== ^ Konstante ^ Wert ^ Bedeutung ^ | ''ERR_XML_OK'' | 0 | kein Fehler | | ''ERR_XML_INVALID'' | 1 | ungültiges Dokument | | ''ERR_XML_EOF'' | 2 | Eingabe endet unerwartet | | ''ERR_XML_TAG_MISMATCH'' | 3 | öffnendes und schließendes Tag passen nicht | | ''ERR_XML_ATTR_ERROR'' | 4 | Attribut nicht lesbar | **Keine Funktion der Unit gibt einen dieser Werte zurück.** Sie stehen für eigene Fehlerbehandlung bereit; die Unit selbst meldet Fehler über ''0'' (kein Ergebnis) beziehungsweise gar nicht. ---- ===== Fallstricke ===== * **Ausgabepuffer gehören dem Aufrufer** und werden nicht auf Größe geprüft. Für ''EscapeText'' sind fünf Byte je Eingabezeichen sicher, für ''EscapeAttribute'' sechs plus zwei für die Anführungszeichen. * **Nach ''Write…'' selbst nullterminieren** ([[https://github.com/SEOLizer/LyX-Compiler/issues/1425|#1425]]). * **Attributwerte werden nicht maskiert** — ''WriteElement'' schreibt sie unverändert zwischen die Anführungszeichen. Ein ''"'' im Wert zerlegt das Dokument. * **64 Byte je Attributname und -wert.** Längere Angaben werden abgeschnitten, weil die Schleifen bei 64 abbrechen. * **Keine Kommentare, keine CDATA, keine Namensräume, keine Entitäten** — ''&'' im Eingabetext bleibt beim Lesen stehen, ein Gegenstück zu ''EscapeText'' gibt es nicht. * **Ein Element je Aufruf.** Verschachtelte Strukturen entstehen, indem man ''WriteElement'' mehrfach in denselben Puffer schreibt und die Einzugstiefe selbst führt. * Für HTML-Text (mit Void-Elementen und ungeschlossenen Tags) ist [[lyx_-_programmiersprache:units:html|std.html]] zuständig — ''std.xml'' erwartet gepaarte Tags. ---- **Weiterführend:** [[lyx_-_programmiersprache:units:html|std.html]] · [[lyx_-_programmiersprache:units:json|std.json]] · [[lyx_-_programmiersprache:units:string|std.string]] · [[lyx_-_programmiersprache:units|Standard Library]] **Quelle:** ''std/xml.lyx'' (967 Zeilen) · **Autor:** Andreas Röne · **Copyright:** 2024–2025 Andreas Röne Letzte Aktualisierung: 2026-08-13 — Seite gegen ''std/xml.lyx'' überarbeitet: zwei lauffähige Beispiele mit echter Ausgabe, Attribut-Speicherformat (128 Byte je Attribut) und Eintragsformat der Array-Familie dokumentiert, Fallstricke ergänzt. Belegt und als Issue erfasst: ''IsValid'' prüft keine Wohlgeformtheit ([[https://github.com/SEOLizer/LyX-Compiler/issues/1422|#1422]]), ''ParseString'' liefert immer ''1'' und schreibt nichts ([[https://github.com/SEOLizer/LyX-Compiler/issues/1423|#1423]]), ''PrettyPrint'' verändert Textinhalte ([[https://github.com/SEOLizer/LyX-Compiler/issues/1424|#1424]]), die ''Write…''-Funktionen terminieren nicht ([[https://github.com/SEOLizer/LyX-Compiler/issues/1425|#1425]]). Geprüft mit ''lyxc 1.0.21A''.