# PureXML [![macOS CI](https://img.shields.io/github/actions/workflow/status/mihaelamj/PureXML/ci.yml?branch=main&label=macOS)](https://github.com/mihaelamj/PureXML/actions/workflows/ci.yml) [![Linux CI](https://img.shields.io/github/actions/workflow/status/mihaelamj/PureXML/ci.yml?branch=main&label=Linux)](https://github.com/mihaelamj/PureXML/actions/workflows/ci.yml) [![WASI CI](https://img.shields.io/github/actions/workflow/status/mihaelamj/PureXML/ci.yml?branch=main&label=WASI)](https://github.com/mihaelamj/PureXML/actions/workflows/ci.yml) PureXML is a dependency-free XML package written entirely in Swift. The goal is a Linux-, Windows-, and WebAssembly-compatible XML reader/writer that does not pull in `libxml2`, `expat`, or Foundation's `XMLParser`. The package is intentionally strict about portability: - no external SwiftPM dependencies - no bundled C sources - no Foundation requirement in the library target - root Swift package layout - macOS, Linux, Windows, and WASI build gates It is a sibling project to [PureYAML](https://github.com/mihaelamj/PureYAML) and follows the same structure, rules, and verification gates. ## Roadmap The roadmap uses the TileDown Mermaid palette: green for shipped work, yellow for review, purple for epic grouping, and gray for open work. ```mermaid flowchart TB classDef done fill:#ddf9e4,stroke:#34c759,color:#111827 classDef review fill:#fff7d6,stroke:#ffcc00,color:#111827 classDef epic fill:#f2e5ff,stroke:#af52de,color:#111827 classDef todo fill:#f2f4f7,stroke:#8e8e93,color:#111827 LDone["In main now"]:::done LReview["PR in review"]:::review LEpic["Epic grouping"]:::epic LTodo["Open issue, no PR"]:::todo LDone --> LReview LReview --> LEpic LEpic --> LTodo ``` Capability is being grown toward libxml2 parity in pure Swift, guided by the private PureXML-research analysis. Shipped vs open work: ```mermaid flowchart TB classDef done fill:#ddf9e4,stroke:#34c759,color:#111827 classDef review fill:#fff7d6,stroke:#ffcc00,color:#111827 classDef epic fill:#f2e5ff,stroke:#af52de,color:#111827 classDef todo fill:#f2f4f7,stroke:#8e8e93,color:#111827 Model["Node model + emitter"]:::done Stream["Streaming pull parser"]:::done Escape["Iterative emitter + escaping"]:::done Limits["Bounded-by-default limits"]:::done Bytes["Byte input + encoding detection"]:::done Namespaces["Namespace resolution"]:::todo ByteStream["Streaming byte decode"]:::todo DTD["Optional DTD + entities"]:::todo Validation["Schema validation"]:::todo XPath["XPath 1.0"]:::todo Model --> Stream Stream --> Escape Escape --> Limits Limits --> Bytes Bytes --> Namespaces Namespaces --> ByteStream ByteStream --> DTD DTD --> Validation Validation --> XPath ``` ## Status The node model, the emitter, and a streaming parser are implemented and usable today. - **Model** (`PureXML.Model`): `Node`, `Element`, `Attribute`, `QualifiedName`. Preserves document order and the distinction between text, CDATA, comments, and processing instructions. - **Emitting** (`PureXML.Emitting`): `Serializer` turns a node tree into well-formed XML, with pretty-printed and compact options and correct text and attribute escaping. - **Validation** (`PureXML.Validation`): structural checks such as duplicate attribute names. Schema validation (DTD/XSD/RELAX NG) is out of scope for the library target. - **Parsing** (`PureXML.Parsing`): a streaming, iterative parser. `EventReader` is a pull-based event core that consumes input through a character-source closure and emits one `Event` at a time, never holding the whole document in memory (it drives chunked input). `Parser` builds a `Model.Node` tree iteratively over the event core. Handles elements, attributes, text, the five predefined entities and numeric character references, comments, CDATA, and processing instructions. Safe by default: `` is rejected, which removes the DTD-based threat classes (XXE, entity-expansion DoS). DTD support, namespaces-as-resolved-URIs, and validation are deliberate future layers. ## Usage ```swift import PureXML // Build a tree and emit it (works today). let element = PureXML.Model.Element( "book", attributes: [.init("id", "bk101")], children: [.element(.init("title", children: [.text("XML Developer's Guide")]))], ) let xml = PureXML.serialize(.element(element)) try PureXML.validate(.element(element)) // Parse it back into a tree. let node = try PureXML.parse(xml) // Or stream events without building a tree (drives chunked input too). var reader = PureXML.events(xml) while let event = try reader.next() { // handle .startElement / .characters / .endElement / ... } ``` ## Attribution PureXML is informed by the behavior of established XML parsers (`libxml2`, `expat`, Foundation's `XMLParser`) and by the W3C XML 1.0 specification, but it does not copy their implementation into `Sources/`. See [ATTRIBUTION.md](ATTRIBUTION.md). ## Development Contract PureXML must stay dependency-free and portable. Before merging changes: - Swift tools version: 6.1 - Package products: `PureXML` - SwiftPM dependencies: none - Hosted CI matrix: macOS, Linux, Windows, and WASM ```sh bash scripts/check-all.sh ``` That command expands to: ```sh bash scripts/check-style.sh bash scripts/check-namespacing.sh bash scripts/check-forbidden-patterns.sh swiftformat . --config .swiftformat --lint swiftlint --config .swiftlint.yml --strict swift build swift test ``` ## License MIT.