preserves-nim/src/preserves/xmlhooks.nim

87 lines
2.6 KiB
Nim

# SPDX-FileCopyrightText: 2021 ☭ Emery Hemingway
# SPDX-License-Identifier: Unlicense
import std/[parseutils, strtabs, tables, xmltree]
import ../preserves
proc toPreserveFromString*(s: string; E: typedesc): Preserve[E] =
# This is a bad and slow thing to do, but that is XML.
case s
of "false", "no", "off":
result = toPreserve(false, E)
of "true", "yes", "on":
result = toPreserve(true, E)
else:
var
n: BiggestInt
f: BiggestFloat
if parseBiggestInt(s, n) == s.len:
result = toPreserve(n, E)
elif parseHex(s, n) == s.len:
result = toPreserve(n, E)
elif parseFloat(s, f) == s.len:
result = toPreserve(f, E)
else:
result = toPreserve(s, E)
proc toPreserveHook*(xn: XmlNode; E: typedesc): Preserve[E] =
if xn.kind == xnElement:
result = Preserve[E](kind: pkRecord)
if not xn.attrs.isNil:
var attrs = initDictionary[E]()
for xk, xv in xn.attrs.pairs:
attrs[toSymbol(xk, E)] = toPreserveFromString(xv, E)
result.record.add(attrs)
var isText = xn.len > 0
# escaped text is broken up and must be concatenated
for child in xn.items:
if child.kind == xnElement:
isText = false
break
if isText:
result.record.add(toPreserve(xn.innerText, E))
else:
for child in xn.items:
case child.kind
of xnElement:
result.record.add(toPreserveHook(child, E))
of xnText, xnVerbatimText, xnCData, xnEntity:
result.record.add(toPreserve(text(child), E))
of xnComment:
discard
result.record.add(toSymbol(xn.tag, E))
# record labels are stored after the fields
proc toUnquotedString[E](pr: Preserve[E]): string {.inline.} =
case pr.kind
of pkString:
pr.string
of pkBoolean:
if pr.bool: "true" else: "false"
else: $pr
proc fromPreserveHook*[E](xn: var XmlNode; pr: Preserve[E]): bool =
if pr.kind == pkRecord and pr.label.kind == pkSymbol:
xn = newElement($pr.label)
var i: int
for e in pr.fields:
if i == 0 and e.kind == pkDictionary:
var pairs = newSeqOfCap[tuple[key, val: string]](e.dict.len)
for key, val in e.dict.items:
pairs.add((key.toUnquotedString, val.toUnquotedString,))
xn.attrs = pairs.toXmlAttributes
elif e.kind == pkString:
xn.add newText(e.string)
else:
var child: XmlNode
result = fromPreserveHook(child, e)
if not result: return
xn.add child
inc i
result = true
when isMainModule:
var xn = newElement("foobar")
var pr = xn.toPreserveHook(void)
assert fromPreserveHook(xn, pr)