preserves-nim/src/preserves/xmlhooks.nim

87 lines
2.5 KiB
Nim

# SPDX-FileCopyrightText: ☭ Emery Hemingway
# SPDX-License-Identifier: Unlicense
import std/[parseutils, strtabs, xmltree]
import ../preserves
proc toPreservesFromString*(s: string): Value =
# This is a bad and slow thing to do, but that is XML.
case s
of "false", "no", "off":
result = toPreserves(false)
of "true", "yes", "on":
result = toPreserves(true)
else:
var
n: BiggestInt
f: float
if parseBiggestInt(s, n) == s.len:
result = toPreserves(n)
elif parseHex(s, n) == s.len:
result = toPreserves(n)
elif parseFloat(s, f) == s.len:
result = toPreserves(f)
else:
result = toPreserves(s)
proc toPreservesHook*(xn: XmlNode): Value =
if xn.kind == xnElement:
result = Value(kind: pkRecord)
if not xn.attrs.isNil:
var attrs = initDictionary()
for xk, xv in xn.attrs.pairs:
attrs[toSymbol(xk)] = toPreservesFromString(xv)
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(toPreserves(xn.innerText))
else:
for child in xn.items:
case child.kind
of xnElement:
result.record.add(toPreservesHook(child))
of xnText, xnVerbatimText, xnCData, xnEntity:
result.record.add(toPreserves(text(child)))
of xnComment:
discard
result.record.add(toSymbol(xn.tag))
# record labels are stored after the fields
proc toUnquotedString(pr: Value): string {.inline.} =
case pr.kind
of pkString:
pr.string
of pkBoolean:
if pr.bool: "true" else: "false"
else: $pr
proc fromPreservesHook*(xn: var XmlNode; pr: Value): 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 = fromPreservesHook(child, e)
if not result: return
xn.add child
inc i
result = true
when isMainModule:
var xn = newElement("foobar")
var pr = xn.toPreservesHook()
assert fromPreservesHook(xn, pr)