Follow the mihaela-agents mermaid rule: add a README roadmap using the TileDown Apple-color status classes (done/review/epic/todo), legend block first, then a libxml2-parity roadmap showing shipped vs open work. Add docs/rules/mermaid.md and scripts/check-roadmap.sh (wired into check-all.sh) so the diagrams stay mechanically checkable.
156 lines
5.4 KiB
Markdown
156 lines
5.4 KiB
Markdown
# PureXML
|
|
|
|
[](https://github.com/mihaelamj/PureXML/actions/workflows/ci.yml)
|
|
[](https://github.com/mihaelamj/PureXML/actions/workflows/ci.yml)
|
|
[](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: `<!DOCTYPE>` 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.
|