====== 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''.