README.md

# xmlm

Xmlm is a pull-based XML parser for Gleam, in a similar style as the OCaml [xmlm](https://erratique.ch/software/xmlm/doc/Xmlm/index.html) library.

## Documentation & Usage

- For documentation and some usage examples, see the API docs in `src/xmlm.gleam`
- For complete XML processing examples, see the `test/examples` directory.
- Tests include XML spec conformance tests (currently the OASIS/NIST suite only), which also is currently serving as the "documentation" for where it diverges from the XML spec (i.e., in the same ways as the OCaml library on which it is based does), as well as the integration tests from this Rust library (https://github.com/RazrFalcon/xmlparser/tree/master/tests/integration).

## Hacking

Check out the `justfile` for various utilities and helpers.  (You will need [just](https://just.systems/) installed to use it.)

### XML Conformance Tests

- XML Conformance tests are located in `test/xmlconf`. 
  - Within each subdirectory, there is a `gen.gleam` file that auto-generates the tests.
  - These files include some rules about when tests that are expected to fail according to the spec will actually pass in this package, and vice-versa.
- Corresponding XML test files are located in `test/test_files/xmlconf`. 
- To generate the tests, run `just gen_xmlconf_tests`.
  - Currently, only the oasis tests are used, but more will be incorporated.

### Benchmarks

You can run various benchmarks with:

- `just bench_compare_erlang`
- `just bench_compare_javascript`
- `just bench_signals_erlang`
- `just bench_signals_javascript`

Note that the JavaScript benchmarks are fairly slow to run.

### Profiling Erlang Code

Run the Erlang shell with `gleam shell`.  Then input the following:

```
fprof:trace(start).
bench@run_in_shell:main().
fprof:trace(stop).
fprof:profile().
fprof:analyse({dest, "_output/profile.fprof"}).
```

If you want to profile using a longer file, you can run the following instead.


```
Input = bench@run_in_shell:make_input("/home/ryan/projects/gleam/xmlm/test/test_files/33397721_long.xml").
fprof:trace(start).
bench@run_in_shell:no_op(Input).
fprof:trace(stop).
fprof:profile().
fprof:analyse({dest, "_output/profile.fprof"}).
```

(You can also use `bench@run_in_shell:count_start_signals(Input)` rather than `no_op`.)

Once either one of the above finishes running (it shouldn't take more than a few moments), then run `just erlgrind` to view the profile with kchachegrind.

Note that this requires both [kcachegrind](https://kcachegrind.sourceforge.net/html/Home.html) and [erlgrind](https://github.com/isacssouza/erlgrind) to be installed.

## Roadmap

- [ ] Accept input sources other than string or bit array.  (Ideally, some sort of abstraction that would also allow processing a stream of data.)

## Acknowledgements

Very heavily inspired by OCaml's [xmlm](https://erratique.ch/software/xmlm) package by Daniel Bünzli.

## License

[![license MIT or Apache
2.0](https://img.shields.io/badge/license-MIT%20or%20Apache%202.0-blue)](https://github.com/mooreryan/gleam_qcheck)

Copyright (c) 2024 Ryan M. Moore

Licensed under the Apache License, Version 2.0 or the MIT license, at your option. This program may not be copied, modified, or distributed except according to those terms.