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.
→ std.html · std.string · 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 vier Mängel dieser Unit sind behoben — nachgemessen mitlyxc 1.1.11Bgegen die ausgeliefertestd/xml.lyx:
*IsValidprüft Wohlgeformtheit:<awird abgewiesen,<a></a>gilt als gültig (#1422).
*ParseStringschreibt in den Ausgabepuffer und meldet0, wenn kein Wurzelelement da ist (#1423) — Format siehe unten.
*PrettyPrintrührt Textinhalte nicht mehr an (#1424).
* Die dreiWrite…-Funktionen terminieren ihre Ausgabe (#1425).
ParseString(input, output) füllt einen festen Satz von Feldern im Ausgabepuffer, keine Zeichenkette. Der Puffer muss XML_PARSE_BUFFER_SIZE (576 Byte) groß sein; die Feldanfänge sind exportierte Konstanten:
| Konstante | Versatz | Feld | Größe |
|---|---|---|---|
XML_OFF_VERSION | 0 | Version aus der Deklaration | 32 |
XML_OFF_ENCODING | 32 | Kodierung aus der Deklaration | 32 |
XML_OFF_ROOTNAME | 64 | Name des Wurzelelements | 256 |
XML_OFF_ROOTTEXT | 320 | Textinhalt des Wurzelelements | 256 |
import std.io;
import std.xml;
import std.alloc;
fn main(): int64 {
var o: pchar := alloc(XML_PARSE_BUFFER_SIZE) as pchar;
var rc: int64 := ParseString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><gruss>hallo</gruss>"c, o);
Print("rc="c); Print(rc); PrintLn(""c);
Print("Version : "c); PrintLn((o as int64 + XML_OFF_VERSION) as pchar);
Print("Encoding: "c); PrintLn((o as int64 + XML_OFF_ENCODING) as pchar);
Print("Wurzel : "c); PrintLn((o as int64 + XML_OFF_ROOTNAME) as pchar);
Print("Text : "c); PrintLn((o as int64 + XML_OFF_ROOTTEXT) as pchar);
return 0;
}
rc=1
Version : 1.0
Encoding: UTF-8
Wurzel : gruss
Text : hallo
Ohne Wurzelelement — etwa bei „kein xml“ — liefert ParseString 0, und ROOTNAME wie ROOTTEXT sind leer. Der Rückgabewert ist damit brauchbar; die frühere Ausgabe „immer 1„ gibt es nicht mehr.
| 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.
EscapeAttributeschreibt die Anführungszeichen selbst. Wer sie im eigenen Text zusätzlich setzt, bekommt doppelte. Für die Ausgabe alsoname=+ Ergebnis, ohne weitere Zeichen.
Anders alsstd.htmlfasst die Unit kein Byte 160 an — UTF-8-Text bleibt unversehrt.
| Signatur | Beschreibung |
|---|---|
WriteDeclaration(output, version, encoding): int64 | <?xml version=„1.0“ encoding=„UTF-8“?> |
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 dreiWrite…-Funktionen terminieren ihre Ausgabe (#1425, nachgemessen mitlyxc 1.1.11Bin einem vorher mitXgefüllten Puffer): nach dem geschriebenen Text steht ein Nullbyte, Reste eines früheren Inhalts scheinen nicht mehr durch. Der Rückgabewert ist weiterhin die Länge. DasStrSetChar(o, n, 0);in älteren Beispielen ist damit überflüssig, schadet aber nicht.
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 <b> \"zitiert\""c, o);
PrintLn(StrConcat("EscapeText: ", o));
EscapeAttribute("Tom & Jerry <b> \"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:
<?xml version="1.0" encoding="UTF-8"?>
<config>Inhalt</config>
WriteElement: <item id="7" ty="A">Text</item>
leeres Element: <leer/>
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('<a>x</a>'): ", J(IsValid("<a>x</a>"c))));
PrintLn(StrConcat("IsValid('<a><b></a>'): ", J(IsValid("<a><b></a>"c))));
PrintLn(StrConcat("IsValid('<a'): ", J(IsValid("<a"c))));
PrintLn(StrConcat("IsValid('kein XML'): ", J(IsValid("kein XML"c))));
PrintLn(StrConcat("Count('<a><b/><c>x</c></a>'): ", IntToStr(CountElements("<a><b/><c>x</c></a>"c))));
PrintLn(StrConcat("Count('<a>5 < 7</a>'): ", IntToStr(CountElements("<a>5 < 7</a>"c))));
return 0;
}
CreateArrayEntry, Bytes: 13
Name: titel
Text: Wert
ArrayToXML, Bytes: 19
XML: <titel>Wert</titel>
IsValid('<a>x</a>'): gueltig
IsValid('<a><b></a>'): ungueltig
IsValid('<a'): ungueltig
IsValid('kein XML'): ungueltig
Count('<a><b/><c>x</c></a>'): 3
Count('<a>5 < 7</a>'): 1
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.
| Signatur | Was wirklich geprüft wird |
|---|---|
IsValid(xml: pchar): bool | prüft Wohlgeformtheit: <a>x</a> ist gültig, <a><b></a> (nicht geschlossenes Element) und <a (abgeschnitten) sind es nicht — gemessen mit 1.1.14A, #1422 behoben |
CountElements(xml: pchar): int64 | Zahl der <, denen kein /, ! oder ? folgt |
IsValidprüft inzwischen die Struktur (#1422, nachgemessen mit lyxc 1.2.2B):<a>ohne Schluss und</a>allein liefern 0,<a></a>liefert 1, und Tags über Kreuz (<a><b></a>) werden ebenfalls abgewiesen. Auch ein nacktes<im Text (<a>5 < 7</a>) gilt als ungültig — das ist XML-konform, in XML muss dort<stehen.
Was die Prüfung nicht leistet: Namensraum-Auflösung, DTD- oder Schema-Prüfung und die Kontrolle von Attributwerten.
PrettyPrint(input, output, indentSize) rückt Elemente ein und setzt Zeilenumbrüche.
PrettyPrintlässt Textinhalte in Ruhe (#1424, nachgemessen mit lyxc 1.2.2B). Aus<a><b>x</b><c/></a>wird mitindentSize = 2:
<a> <b>x</b> <c/> </a>
Der Text bleibt in seiner Zeile; frühere Fassungen brachen ihn um und veränderten damit das Dokument.indentSizeist das dritte Argument — ein zu großer Wert (etwa eine Puffergröße) rückt entsprechend absurd weit ein.
| 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.
EscapeText sind fünf Byte je Eingabezeichen sicher, für EscapeAttribute sechs plus zwei für die Anführungszeichen.Write… selbst nullterminieren (#1425).WriteElement schreibt sie unverändert zwischen die Anführungszeichen. Ein “ im Wert zerlegt das Dokument.& im Eingabetext bleibt beim Lesen stehen, ein Gegenstück zu EscapeText gibt es nicht.WriteElement mehrfach in denselben Puffer schreibt und die Einzugstiefe selbst führt.std.xml erwartet gepaarte Tags.Weiterführend: std.html · std.json · std.string · Standard Library
Quelle: std/xml.lyx (967 Zeilen) · Autor: Andreas Röne · Copyright: 2024–2025 Andreas Röne
Letzte Aktualisierung: 2026-09-05 (#1422 und #1424, nachgemessen mit lyxc 1.2.2B) — IsValid- und PrettyPrint-Kästen auf den behobenen Stand gezogen.
Vorherige letzte Aktualisierung: 2026-09-05 (#1422 und #1424, nachgemessen mit lyxc 1.2.2B) — IsValid- und PrettyPrint-Kästen auf den behobenen Stand gezogen.
Vorherige letzte Aktualisierung: 2026-08-30 — gegen lyxc 1.1.14A nachgemessen: IsValid prüft jetzt die Wohlgeformtheit (#1422), und CountElements zählt ein < in gewöhnlichem Text nicht mehr als Element. Beispielausgabe und Funktionstabelle berichtigt.
Vorherige 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 (#1422), ParseString liefert immer 1 und schreibt nichts (#1423), PrettyPrint verändert Textinhalte (#1424), die Write…-Funktionen terminieren nicht (#1425). Geprüft mit lyxc 1.0.21A.
Letzte Aktualisierung: 2026-08-27 — alle vier Mängel gegen lyxc 1.1.11B nachgemessen und als behoben ausgewiesen (#1422, #1423, #1424, #1425); Ergebnisformat von ParseString mit Feldtabelle und laufendem Beispiel ergänzt.
Codebeispiele geprüft: gegen lyxc 1.2.5C übersetzt (Prüflauf 2026-09-08 über die gesamte Doku: 574 Vollprogramme, 0 echte Fehler; zusätzlich 5159 Aufrufe gegen die pub fn-Signaturen in aurum/std gehalten, 0 Abweichungen).