smelly
Sometimes you have to parse XML
Summary
| Latest Version | 0.1.6 |
|---|---|
| License | MIT |
| CI Status | Failing |
| Downloads | 0 |
| Last Indexed | 2026-07-21 05:26 |
Tags
Authors
- Ryan Oldenburg
Installation
nimble install smelly
choosenim install smelly
git clone https://github.com/guzba/smelly
OS Compatibility
| Platform | Linux | macOS | Windows | FreeBSD | OpenBSD | NetBSD | Android | iOS | WASM | Embedded |
|---|---|---|---|---|---|---|---|---|---|---|
| smelly | ✓ | ✓ | ✓ | - | - | - | - | - | - | - |
Dependencies
| Package | Version | Optional |
|---|---|---|
| nim >= | 2.0.0 | No |
| nimsimd >= | 1.3.2 | No |
| unicody >= | 0.1.8 | No |
Source
| Repository | https://github.com/guzba/smelly |
|---|---|
| Homepage | https://github.com/guzba/smelly |
| Registry Source | nimble_official |
README
Smelly
nimble install smelly
Sometimes you need to parse XML. Pinch your nose and get it over with.
This package is an alternative to Nim's standard library XML parser (std/xmlparser + std/xmltree).
Using Smelly
import smelly
let s = """
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 1200 400" xmlns="http://www.w3.org/2000/svg" version="1.1">
<rect x="1" y="1" width="1198" height="398" fill="none" stroke="blue" stroke-width="2" />
<ellipse transform="translate(900 200) rotate(-30)" rx="250" ry="100" fill="none" stroke="blue" stroke-width="20" />
Some text content here
</svg>
"""
let root = parseXml(s)
for child in root.children:
case child.kind:
of ElementNode:
echo child.tag, ' ', child.attributes["stroke-width"]
of TextNode:
echo child.content
rect 2
ellipse 20
Some text content here
Why create an alternative?
After working with Nim's standard lib XML parsing for a while I have found some sources of frustration that I want to avoid.
Nim's std/xmltree uses [] on a node to access it's children and uses .attr[] to access attributes. This isn't so bad (it makes accessing deep into a node tree easy), however I always have to re-learn if [] accesses children or attributes after I've been away from XML parsing for a bit. With Smelly there is no amibguity, it's just .children[] and .attributes[].
Even more annoyingly, Nim's std/xml considers every single entity encoding (eg <) to be independent elements in the node tree instead of just a text encoding detail.
If an encoded entity is present:
import std/xmlparser, std/xmltree
let root = parseXml("<thing>1 < 2</thing>")
echo root.tag # thing
echo root.len # 4 ?????
echo '"', root[0], '"' # "1 " ?????
And if an encoded entity is not present:
import std/xmlparser, std/xmltree
let root = parseXml("<thing>1 or 2</thing>")
echo root.tag # thing
echo root.len # 1
echo '"', root[0], '"' # "1 or 2"
This drastic difference in behavior based on the presence of an encoded entity is not cool with me.
Here is how Smelly handles this:
import smelly
let root = parseXml("<thing>1 < 2</thing>")
echo root.tag # thing
echo root.children.len # 1
echo '"', root.children[0].content, '"' # "1 < 2"
And if an encoded entity is not present:
import smelly
let root = parseXml("<thing>1 or 2</thing>")
echo root.tag # thing
echo root.children.len # 1
echo '"', root.children[0].content, '"' # "1 or 2"
Performance
Smelly is between 2x and 7x faster than std/xmlparser depending on the XML input.
See tests/bench.nim to test this for yourself.
Testing
nimble test