2023-12-27 15:05:30 +00:00
|
|
|
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
2021-12-06 23:28:00 +00:00
|
|
|
# SPDX-License-Identifier: Unlicense
|
|
|
|
|
2023-12-27 15:05:30 +00:00
|
|
|
import std/[parseutils, strtabs, xmltree]
|
2021-12-06 23:28:00 +00:00
|
|
|
import ../preserves
|
|
|
|
|
2023-12-27 15:05:30 +00:00
|
|
|
proc toPreservesFromString*(s: string): Value =
|
2022-10-25 17:13:05 +00:00
|
|
|
# This is a bad and slow thing to do, but that is XML.
|
|
|
|
case s
|
|
|
|
of "false", "no", "off":
|
2023-12-27 15:05:30 +00:00
|
|
|
result = toPreserves(false)
|
2022-10-25 17:13:05 +00:00
|
|
|
of "true", "yes", "on":
|
2023-12-27 15:05:30 +00:00
|
|
|
result = toPreserves(true)
|
2022-10-25 17:13:05 +00:00
|
|
|
else:
|
|
|
|
var
|
|
|
|
n: BiggestInt
|
|
|
|
f: BiggestFloat
|
|
|
|
if parseBiggestInt(s, n) == s.len:
|
2023-12-27 15:05:30 +00:00
|
|
|
result = toPreserves(n)
|
2022-10-25 17:13:05 +00:00
|
|
|
elif parseHex(s, n) == s.len:
|
2023-12-27 15:05:30 +00:00
|
|
|
result = toPreserves(n)
|
2022-10-25 17:13:05 +00:00
|
|
|
elif parseFloat(s, f) == s.len:
|
2023-12-27 15:05:30 +00:00
|
|
|
result = toPreserves(f)
|
2022-10-25 17:13:05 +00:00
|
|
|
else:
|
2023-12-27 15:05:30 +00:00
|
|
|
result = toPreserves(s)
|
2022-10-25 17:13:05 +00:00
|
|
|
|
2023-12-27 15:05:30 +00:00
|
|
|
proc toPreservesHook*(xn: XmlNode): Value =
|
2022-10-20 18:38:49 +00:00
|
|
|
if xn.kind == xnElement:
|
2023-12-27 15:05:30 +00:00
|
|
|
result = Value(kind: pkRecord)
|
2021-12-06 23:28:00 +00:00
|
|
|
if not xn.attrs.isNil:
|
2023-12-27 15:05:30 +00:00
|
|
|
var attrs = initDictionary()
|
2022-10-25 17:13:05 +00:00
|
|
|
for xk, xv in xn.attrs.pairs:
|
2023-12-27 15:05:30 +00:00
|
|
|
attrs[toSymbol(xk)] = toPreservesFromString(xv)
|
2022-10-20 18:38:49 +00:00
|
|
|
result.record.add(attrs)
|
2022-10-25 17:13:05 +00:00
|
|
|
var isText = xn.len > 0
|
|
|
|
# escaped text is broken up and must be concatenated
|
2021-12-22 21:27:18 +00:00
|
|
|
for child in xn.items:
|
2022-10-25 17:13:05 +00:00
|
|
|
if child.kind == xnElement:
|
|
|
|
isText = false
|
|
|
|
break
|
|
|
|
if isText:
|
2023-12-27 15:05:30 +00:00
|
|
|
result.record.add(toPreserves(xn.innerText))
|
2022-10-25 17:13:05 +00:00
|
|
|
else:
|
|
|
|
for child in xn.items:
|
|
|
|
case child.kind
|
|
|
|
of xnElement:
|
2023-12-27 15:05:30 +00:00
|
|
|
result.record.add(toPreservesHook(child))
|
2022-10-25 17:13:05 +00:00
|
|
|
of xnText, xnVerbatimText, xnCData, xnEntity:
|
2023-12-27 15:05:30 +00:00
|
|
|
result.record.add(toPreserves(text(child)))
|
2022-10-25 17:13:05 +00:00
|
|
|
of xnComment:
|
|
|
|
discard
|
2023-12-27 15:05:30 +00:00
|
|
|
result.record.add(toSymbol(xn.tag))
|
2022-10-25 17:13:05 +00:00
|
|
|
# record labels are stored after the fields
|
2022-10-20 18:38:49 +00:00
|
|
|
|
2023-12-27 15:05:30 +00:00
|
|
|
proc toUnquotedString(pr: Value): string {.inline.} =
|
2022-10-20 18:38:49 +00:00
|
|
|
case pr.kind
|
2022-10-25 17:13:05 +00:00
|
|
|
of pkString:
|
|
|
|
pr.string
|
2022-10-20 18:38:49 +00:00
|
|
|
of pkBoolean:
|
|
|
|
if pr.bool: "true" else: "false"
|
|
|
|
else: $pr
|
2021-12-06 23:28:00 +00:00
|
|
|
|
2023-12-27 15:05:30 +00:00
|
|
|
proc fromPreservesHook*(xn: var XmlNode; pr: Value): bool =
|
2022-10-20 18:38:49 +00:00
|
|
|
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:
|
2022-10-25 17:13:05 +00:00
|
|
|
pairs.add((key.toUnquotedString, val.toUnquotedString,))
|
2022-10-20 18:38:49 +00:00
|
|
|
xn.attrs = pairs.toXmlAttributes
|
|
|
|
elif e.kind == pkString:
|
|
|
|
xn.add newText(e.string)
|
2021-12-06 23:28:00 +00:00
|
|
|
else:
|
2022-10-20 18:38:49 +00:00
|
|
|
var child: XmlNode
|
2023-12-27 15:05:30 +00:00
|
|
|
result = fromPreservesHook(child, e)
|
2022-10-20 18:38:49 +00:00
|
|
|
if not result: return
|
|
|
|
xn.add child
|
|
|
|
inc i
|
|
|
|
result = true
|
2021-12-06 23:28:00 +00:00
|
|
|
|
|
|
|
when isMainModule:
|
2022-10-25 17:13:05 +00:00
|
|
|
var xn = newElement("foobar")
|
2023-12-27 15:05:30 +00:00
|
|
|
var pr = xn.toPreservesHook()
|
|
|
|
assert fromPreservesHook(xn, pr)
|