Reliably make a clean copy of an XML node

On a random walk through options, I seem to have hit upon

copynode(o)=XML.Node(o.nodetype, o.tag, o.attributes, o.value, isnothing(o.children) ? nothing : [copynode(x) for x in o.children])

Which recursively copies a node and all its children.

As far as I can tell, this gives the same result as deepcopy but is quite a bit faster. Here, I’m just using an XML file representing an Excel worksheet (nested a few levels deep).

julia> using XML, BenchmarkTools, XLSX

julia> copynode(o)=XML.Node(o.nodetype, o.tag, o.attributes, o.value, isnothing(o.children) ? nothing : [copynode(x) for x in o.children])
copynode (generic function with 1 method)

julia> deepcopynode(o) = deepcopy(o)
deepcopynode (generic function with 1 method)

julia> function createCfx(rule, f)                                                                                                                                                                     
           cfx=f(rule)                                                                                                                                                                                 
           cfvo = XML.Element("x14:cfvo", type="percent")                                                                                                                                              
           push!(cfvo, XML.Element("xm:f", XML.Text("dummy")))                                                                                                                                     
           push!(cfx[end], f(cfvo))                                                                                                                                                            
           push!(cfx[end], f(cfvo))                                                                                                                                                        
           push!(cfx[end], f(cfvo))                                                                                                                                                                    
           cfx[1]["iconSet"] = "4Arrows"                                                                                                                                                               
           return cfx                                                                                                                                                                              
       end
createCfx (generic function with 1 method)

julia> f=XLSX.opentemplate(raw"C:\Users\tim\OneDrive\Documents\Julia\XLSX\iconKey.xlsx")
XLSXFile("C:\Users\tim\OneDrive\Documents\Julia\XLSX\iconKey.xlsx") containing 1 Worksheet
            sheetname size          range
-------------------------------------------------
               Sheet1 4x13          A1:M4

julia> rule = XLSX.get_worksheet_xml_document(f[1])
Node Document (2 children)

julia> @benchmark cfx=createCfx($rule, $copynode)
BenchmarkTools.Trial: 10000 samples with 1 evaluation per sample.
 Range (min … max):   86.100 μs …   7.979 ms  ┊ GC (min … max): 0.00% … 97.99%
 Time  (median):      93.900 μs               ┊ GC (median):    0.00%
 Time  (mean ± σ):   109.910 μs ± 153.160 μs  ┊ GC (mean ± σ):  6.75% ±  5.06%

     ▁▇█▃
  ▁▂▄████▇▄▂▂▂▁▁▁▁▂▂▂▂▃▃▂▂▂▂▂▂▁▂▂▃▃▃▃▂▂▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▂
  86.1 μs          Histogram: frequency by time          159 μs <

 Memory estimate: 205.73 KiB, allocs estimate: 4520.

julia> rule2 = XLSX.get_worksheet_xml_document(f[1])
Node Document (2 children)

julia> cfx2=createCfx(rule2, deepcopynode)
Node Document (2 children)

julia> rule2 = XLSX.get_worksheet_xml_document(f[1])
Node Document (2 children)

julia> @benchmark cfx2=createCfx($rule2, $deepcopynode)
BenchmarkTools.Trial: 9872 samples with 1 evaluation per sample.
 Range (min … max):  438.400 μs …   4.798 ms  ┊ GC (min … max): 0.00% … 87.00%
 Time  (median):     456.900 μs               ┊ GC (median):    0.00%
 Time  (mean ± σ):   505.863 μs ± 259.013 μs  ┊ GC (mean ± σ):  4.52% ±  7.66%

   ▅▇█▇▆▆▅▄▂▁▁▁            ▁▂▂▂▂▁          ▁▁▁▁▁▁▁▂▁▁           ▂
  ▆██████████████▇▆▆▅▆▇▇▆▇██████████▇▆▇▇▇▇████████████▇▇▆▅▅▄▄▄▄ █
  438 μs        Histogram: log(frequency) by time        698 μs <

 Memory estimate: 537.81 KiB, allocs estimate: 12190.

julia> cfx=createCfx(rule, copynode)
Node Document (2 children)

julia> rule = XLSX.get_worksheet_xml_document(f[1])
Node Document (2 children)

julia> cfx=createCfx(rule, copynode)
Node Document (2 children)

julia> rule2 = XLSX.get_worksheet_xml_document(f[1])
Node Document (2 children)

julia> cfx2=createCfx(rule2, copynode)
Node Document (2 children)

julia> cfx==cfx2
true