Feature/xmltree additions (#20988)

* [change] add/insert/delete family of xmltree expanded with several variations. Added replace methods family

* [change] Lifted child limitations on insert methods (consulted with @araq)

* [tests] add/insert/replace/delete of xmltree XmlNodes tests added
This commit is contained in:
Michael Voronin
2022-12-22 10:32:12 +03:00
committed by GitHub
parent 93b59da490
commit 7931bdac95
9 changed files with 552 additions and 3 deletions

View File

@@ -31,7 +31,7 @@ runnableExamples:
## * `htmlgen module <htmlgen.html>`_ for html code generator
import std/private/since
import macros, strtabs, strutils
import macros, strtabs, strutils, sequtils
when defined(nimPreviewSlimSystem):
import std/assertions
@@ -298,26 +298,60 @@ proc innerText*(n: XmlNode): string =
proc add*(father, son: XmlNode) {.inline.} =
## Adds the child `son` to `father`.
## `father` must be of `xnElement` type
##
## See also:
## * `add proc <#add,XmlNode,openArray[XmlNode]>`_
## * `insert proc <#insert,XmlNode,XmlNode,int>`_
## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_
## * `delete proc <#delete,XmlNode,Natural>`_
## * `delete proc <#delete.XmlNode,Slice[int]>`_
## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_
## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_
runnableExamples:
var f = newElement("myTag")
f.add newText("my text")
f.add newElement("sonTag")
f.add newEntity("my entity")
assert $f == "<myTag>my text<sonTag />&my entity;</myTag>"
assert father.k == xnElement
add(father.s, son)
proc add*(father: XmlNode, sons: openArray[XmlNode]) {.inline.} =
## Adds the children `sons` to `father`.
## `father` must be of `xnElement` type
##
## See also:
## * `add proc <#add,XmlNode,XmlNode>`_
## * `insert proc <#insert,XmlNode,XmlNode,int>`_
## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_
## * `delete proc <#delete,XmlNode,Natural>`_
## * `delete proc <#delete.XmlNode,Slice[int]>`_
## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_
## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_
runnableExamples:
var f = newElement("myTag")
f.add(@[newText("my text"), newElement("sonTag"), newEntity("my entity")])
assert $f == "<myTag>my text<sonTag />&my entity;</myTag>"
assert father.k == xnElement
add(father.s, sons)
proc insert*(father, son: XmlNode, index: int) {.inline.} =
## Inserts the child `son` to a given position in `father`.
##
## `father` and `son` must be of `xnElement` kind.
## `father` must be of `xnElement` kind.
##
## See also:
## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_
## * `add proc <#add,XmlNode,XmlNode>`_
## * `add proc <#add,XmlNode,openArray[XmlNode]>`_
## * `delete proc <#delete,XmlNode,Natural>`_
## * `delete proc <#delete.XmlNode,Slice[int]>`_
## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_
## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_
runnableExamples:
var f = newElement("myTag")
f.add newElement("first")
@@ -327,18 +361,52 @@ proc insert*(father, son: XmlNode, index: int) {.inline.} =
<first />
</myTag>"""
assert father.k == xnElement and son.k == xnElement
assert father.k == xnElement
if len(father.s) > index:
insert(father.s, son, index)
else:
insert(father.s, son, len(father.s))
proc insert*(father: XmlNode, sons: openArray[XmlNode], index: int) {.inline.} =
## Inserts the children openArray[`sons`] to a given position in `father`.
##
## `father` must be of `xnElement` kind.
##
## See also:
## * `insert proc <#insert,XmlNode,XmlNode,int>`_
## * `add proc <#add,XmlNode,XmlNode>`_
## * `add proc <#add,XmlNode,openArray[XmlNode]>`_
## * `delete proc <#delete,XmlNode,Natural>`_
## * `delete proc <#delete.XmlNode,Slice[int]>`_
## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_
## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_
runnableExamples:
var f = newElement("myTag")
f.add newElement("first")
f.insert([newElement("second"), newElement("third")], 0)
assert $f == """<myTag>
<second />
<third />
<first />
</myTag>"""
assert father.k == xnElement
if len(father.s) > index:
insert(father.s, sons, index)
else:
insert(father.s, sons, len(father.s))
proc delete*(n: XmlNode, i: Natural) =
## Deletes the `i`'th child of `n`.
##
## See also:
## * `delete proc <#delete.XmlNode,Slice[int]>`_
## * `add proc <#add,XmlNode,XmlNode>`_
## * `add proc <#add,XmlNode,openArray[XmlNode]>`_
## * `insert proc <#insert,XmlNode,XmlNode,int>`_
## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_
## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_
## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_
runnableExamples:
var f = newElement("myTag")
f.add newElement("first")
@@ -351,6 +419,85 @@ proc delete*(n: XmlNode, i: Natural) =
assert n.k == xnElement
n.s.delete(i)
proc delete*(n: XmlNode, slice: Slice[int]) =
## Deletes the items `n[slice]` of `n`.
##
## See also:
## * `delete proc <#delete.XmlNode,int>`_
## * `add proc <#add,XmlNode,XmlNode>`_
## * `add proc <#add,XmlNode,openArray[XmlNode]>`_
## * `insert proc <#insert,XmlNode,XmlNode,int>`_
## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_
## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_
## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_
runnableExamples:
var f = newElement("myTag")
f.add newElement("first")
f.insert([newElement("second"), newElement("third")], 0)
f.delete(0..1)
assert $f == """<myTag>
<first />
</myTag>"""
assert n.k == xnElement
n.s.delete(slice)
proc replace*(n: XmlNode, i: Natural, replacement: openArray[XmlNode]) =
## Replaces the `i`'th child of `n` with `replacement` openArray.
##
## `n` must be of `xnElement` kind.
##
## See also:
## * `replace proc <#replace.XmlNode,Slice[int],openArray[XmlNode]>`_
## * `add proc <#add,XmlNode,XmlNode>`_
## * `add proc <#add,XmlNode,openArray[XmlNode]>`_
## * `delete proc <#delete,XmlNode,Natural>`_
## * `delete proc <#delete.XmlNode,Slice[int]>`_
## * `insert proc <#insert,XmlNode,XmlNode,int>`_
## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_
runnableExamples:
var f = newElement("myTag")
f.add newElement("first")
f.insert(newElement("second"), 0)
f.replace(0, @[newElement("third"), newElement("fourth")])
assert $f == """<myTag>
<third />
<fourth />
<first />
</myTag>"""
assert n.k == xnElement
n.s.delete(i)
n.s.insert(replacement, i)
proc replace*(n: XmlNode, slice: Slice[int], replacement: openArray[XmlNode]) =
## Deletes the items `n[slice]` of `n`.
##
## `n` must be of `xnElement` kind.
##
## See also:
## * `replace proc <#replace.XmlNode,int,openArray[XmlNode]>`_
## * `add proc <#add,XmlNode,XmlNode>`_
## * `add proc <#add,XmlNode,openArray[XmlNode]>`_
## * `delete proc <#delete,XmlNode,Natural>`_
## * `delete proc <#delete.XmlNode,Slice[int]>`_
## * `insert proc <#insert,XmlNode,XmlNode,int>`_
## * `insert proc <#insert,XmlNode,openArray[XmlNode],int>`_
runnableExamples:
var f = newElement("myTag")
f.add newElement("first")
f.insert([newElement("second"), newElement("fifth")], 0)
f.replace(0..1, @[newElement("third"), newElement("fourth")])
assert $f == """<myTag>
<third />
<fourth />
<first />
</myTag>"""
assert n.k == xnElement
n.s.delete(slice)
n.s.insert(replacement, slice.a)
proc len*(n: XmlNode): int {.inline.} =
## Returns the number of `n`'s children.
runnableExamples:

51
tests/xml/ttree_add.nim Normal file
View File

@@ -0,0 +1,51 @@
discard """
output: '''
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
<xml>
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
</xml>
'''
"""
# Test xmltree add/insert/delete/replace operations
import xmlparser
import xmltree
var baseDocHead = """
<xml>
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
</xml>
"""
var baseDocHeadTree = parseXml(baseDocHead)
var baseDocBody = """
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
"""
var baseDocBodyTree = parseXml(baseDocBody)
proc test_add() =
var testDoc = baseDocHeadTree
var newBody = newElement("body")
for item in baseDocBodyTree.items():
newBody.add(item)
echo $newBody
testDoc.add(newBody)
echo $testDoc
test_add()

53
tests/xml/ttree_add1.nim Normal file
View File

@@ -0,0 +1,53 @@
discard """
output: '''
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
<xml>
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
</xml>
'''
"""
# Test xmltree add/insert/delete/replace operations
import xmlparser
import xmltree
var baseDocHead = """
<xml>
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
</xml>
"""
var baseDocHeadTree = parseXml(baseDocHead)
var baseDocBody = """
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
"""
var baseDocBodyTree = parseXml(baseDocBody)
proc test_add() =
var testDoc = baseDocHeadTree
var newBody = newElement("body")
var bodyItems: seq[XmlNode] = @[]
for item in baseDocBodyTree.items():
bodyItems.add(item)
newBody.add(bodyItems)
echo $newBody
testDoc.add(newBody)
echo $testDoc
test_add()

View File

@@ -0,0 +1,47 @@
discard """
output: '''
<xml>
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
</xml>
'''
"""
# Test xmltree add/insert/delete/replace operations
import xmlparser
import xmltree
let initialDocBase = """
<xml>
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
<tag>
<div>MORE TEXT </div>
<div>MORE TEXT Some more text</div>
</tag>
<tag>
<div>MORE TEXT </div>
<div>MORE TEXT Some more text</div>
</tag>
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
</xml>
"""
var initialDocBaseTree = parseXml(initialDocBase)
proc test_delete() =
var testDoc = initialDocBaseTree
testDoc.delete(1..2)
echo $testDoc
test_delete()

View File

@@ -0,0 +1,48 @@
discard """
output: '''
<xml>
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
</xml>
'''
"""
# Test xmltree add/insert/delete/replace operations
import xmlparser
import xmltree
let initialDocBase = """
<xml>
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
<tag>
<div>MORE TEXT </div>
<div>MORE TEXT Some more text</div>
</tag>
<tag>
<div>MORE TEXT </div>
<div>MORE TEXT Some more text</div>
</tag>
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
</xml>
"""
var initialDocBaseTree = parseXml(initialDocBase)
proc test_delete() =
var testDoc = initialDocBaseTree
testDoc.delete(1)
testDoc.delete(1)
echo $testDoc
test_delete()

View File

@@ -0,0 +1,53 @@
discard """
output: '''
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
<xml>
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
</xml>
'''
"""
# Test xmltree add/insert/delete/replace operations
import xmlparser
import xmltree
var baseDocHead = """
<xml>
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
</xml>
"""
var baseDocHeadTree = parseXml(baseDocHead)
var baseDocBody = """
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
"""
var baseDocBodyTree = parseXml(baseDocBody)
proc test_insert() =
var testDoc = baseDocHeadTree
var newBody = newElement("body")
var bodyItems: seq[XmlNode] = @[]
for item in baseDocBodyTree.items():
bodyItems.insert(item, len(bodyItems))
newBody.insert(bodyItems, 1)
echo $newBody
testDoc.insert(newBody, 1)
echo $testDoc
test_insert()

View File

@@ -0,0 +1,51 @@
discard """
output: '''
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
<xml>
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
</xml>
'''
"""
# Test xmltree add/insert/delete/replace operations
import xmlparser
import xmltree
var baseDocHead = """
<xml>
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
</xml>
"""
var baseDocHeadTree = parseXml(baseDocHead)
var baseDocBody = """
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
"""
var baseDocBodyTree = parseXml(baseDocBody)
proc test_insert() =
var testDoc = baseDocHeadTree
var newBody = newElement("body")
for item in baseDocBodyTree.items():
newBody.insert(item, len(newBody))
echo $newBody
testDoc.insert(newBody, 1)
echo $testDoc
test_insert()

View File

@@ -0,0 +1,46 @@
discard """
output: '''
<xml>
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
</xml>
'''
"""
# Test xmltree add/insert/delete/replace operations
import xmlparser
import xmltree
var baseDocBody = """
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
"""
var baseDocBodyTree = parseXml(baseDocBody)
let initialDocBase = """
<xml>
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
<body>
<div>Some text in body before replace </div>
<div>Some more text in body before replace </div>
</body>
</xml>
"""
var initialDocBaseTree = parseXml(initialDocBase)
proc test_replace() =
var testDoc = initialDocBaseTree
testDoc.replace(1, @[baseDocBodyTree])
echo $testDoc
test_replace()

View File

@@ -0,0 +1,53 @@
discard """
output: '''
<xml>
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
</xml>
'''
"""
# Test xmltree add/insert/delete/replace operations
import xmlparser
import xmltree
var baseDocHead = """
<head>
<div>Some text</div>
<div>Some more text </div>
</head>
"""
var baseDocHeadTree = parseXml(baseDocHead)
var baseDocBody = """
<body>
<div>Some text in body</div>
<div>Some more text in body </div>
</body>
"""
var baseDocBodyTree = parseXml(baseDocBody)
let initialDocBase = """
<xml>
<head>
<div>Some text before replace </div>
<div>Some more text before replace </div>
</head>
<body>
<div>Some text in body before replace </div>
<div>Some more text in body before replace </div>
</body>
</xml>
"""
var initialDocBaseTree = parseXml(initialDocBase)
proc test_replace() =
var testDoc = initialDocBaseTree
testDoc.replace(0..1, @[baseDocHeadTree, baseDocBodyTree])
echo $testDoc
test_replace()