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) => XmlEventCallbacks

Factory that builds the SAX callbacks; receives an emit function 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" },
]);

Source