parseXmlRecords
import { parseXmlRecords } from "jsr:@ende/xml";function
async function* parseXmlRecords<T>(source: AsyncIterable<string>, createCallbacks: (emit: (record: T) => void) => XmlEventCallbacks, options: ParseStreamOptions = [UNSUPPORTED]): AsyncGenerator<T>Parses an async iterable of XML chunks and yields records assembled inside SAX-style event callbacks.
Each input chunk is parsed synchronously and the records emitted from that chunk are buffered before any are yielded; the consumer then pulls records one at a time. Yield rate (and downstream backpressure) is per-record while peak memory is bounded by the records produced by a single chunk — for example, a 1 MB chunk containing 1000 items will buffer all 1000 records before the consumer sees the first.
If parsing throws (XML syntax error or a user callback that throws), the iteration rejects immediately; records buffered within the failing chunk are discarded. Records yielded by earlier chunks remain visible.
For pipeThrough composition, wrap the result with
ReadableStream.from.
source: AsyncIterable<string>An async iterable of XML string chunks. For byte sources, use
parseXmlRecordsFromBytes.createCallbacks: (emit: (record: T) => void) => XmlEventCallbacksFactory that builds the SAX callbacks; receives an
emitfunction to push completed records.options: ParseStreamOptions = [UNSUPPORTED]Parser options forwarded to the underlying tokenizer/parser.
Returns
An async generator that yields records as the document is parsed.
Example: Parse items from an XML feed into typed records
import { parseXmlRecords } from "@ende/xml/parse-records";
import { assertEquals } from "@ende/assert";
type Item = { id: string; title: string };
const xml =
`<feed><item id="1" title="First"/><item id="2" title="Second"/></feed>`;
const items: Item[] = [];
for await (
const item of parseXmlRecords<Item>(
ReadableStream.from([xml]),
(emit) => ({
onStartElement(name, _colonIndex, _uri, attributes) {
if (name !== "item") return;
let id = "";
let title = "";
for (let i = 0; i < attributes.count; i++) {
const attrName = attributes.getName(i);
if (attrName === "id") id = attributes.getValue(i);
else if (attrName === "title") title = attributes.getValue(i);
}
emit({ id, title });
},
}),
)
) {
items.push(item);
}
assertEquals(items, [
{ id: "1", title: "First" },
{ id: "2", title: "Second" },
]);