Skip to content

Commit

Permalink
update readme, change where depth prints for Node, update benchmarks/…
Browse files Browse the repository at this point in the history
…suite.jl
  • Loading branch information
joshday committed May 21, 2024
1 parent 11a6a55 commit c336152
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 95 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,15 @@ Similar to [Cobweb.jl](https://github.com/JuliaComputing/Cobweb.jl#-creating-nod
using XML: h

julia> node = h.parent(
h.child("content", id="my id")
h.child("first child content", id="id1"),
h.child("second child content", id="id2")
)
# Node Element <parent> (1 child)
# Node Element <parent> (2 children)

julia> XML.write(node)
julia> print(XML.write(node))
# <parent>
# <child id=\"my id\">content</child>
# <child id="id1">first child content</child>
# <child id="id2">second child content</child>
# </parent>
```

Expand Down
100 changes: 19 additions & 81 deletions benchmarks/suite.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,90 +20,32 @@ file = joinpath(@__DIR__, "nasa.xml")

df = DataFrame(kind=String[], name=String[], bench=BenchmarkTools.Trial[])

macro add_benchmark(kind, name, expr...)
esc(:(let
@info string($kind, " - ", $name)
bench = @benchmark $(expr...)
push!(df, (; kind=$kind, name=$name, bench))
end))
end

#-----------------------------------------------------------------------------# Write
kind = "Write"
output = tempname()

name = "XML.write 2"
@info name
node1 = read(file, Node)
bench = @benchmark XML.write($output, $node1)
push!(df, (;kind, name, bench))


name = "EzXML.writexml"
@info name
node2 = EzXML.readxml(file)
bench = @benchmark EzXML.write($output, $node2)
push!(df, (;kind, name, bench))


@add_benchmark "Write" "XML.write" XML.write($(tempname()), o) setup = (o = read(file, Node))
@add_benchmark "Write" "EzXML.writexml" EzXML.write($(tempname()), o) setup = (o = EzXML.readxml(file))

#-----------------------------------------------------------------------------# Read
kind = "Read"

# name = "XML.Raw"
# @info name
# bench = @benchmark read($file, XML.Raw)
# push!(df, (;kind, name, bench))


name = "XML.LazyNode"
@info name
bench = @benchmark read($file, LazyNode)
push!(df, (;kind, name, bench))

name = "XML.Node"
@info name
bench = @benchmark read($file, Node)
push!(df, (;kind, name, bench))


name = "EzXML.readxml"
@info name
bench = @benchmark EzXML.readxml($file)
push!(df, (;kind, name, bench))


name = "XMLDict.xml_dict"
@info name
bench = @benchmark XMLDict.xml_dict(read($file, String))
push!(df, (;kind, name, bench))

@add_benchmark "Read" "XML.LazyNode" read($file, LazyNode)
@add_benchmark "Read" "XML.Node" read($file, Node)
@add_benchmark "Read" "EzXML.readxml" EzXML.readxml($file)
@add_benchmark "Read" "XMLDict.xml_dict" XMLDict.xml_dict(read($file, String))

#-----------------------------------------------------------------------------# Lazy Iteration
kind = "Lazy Iteration"

name = "for x in read(file, LazyNode); end"
@info name
bench = @benchmark (for x in read($file, LazyNode); end)
push!(df, (;kind, name, bench))


name = "for x in open(EzXML.StreamReader, file); end"
@info name
bench = @benchmark (reader = open(EzXML.StreamReader, $file); for x in reader; end; close(reader))
push!(df, (;kind, name, bench))

@add_benchmark "Lazy Iteration" "LazyNode" for x in read($file, LazyNode); end
@add_benchmark "Lazy Iteration" "EzXML.StreamReader" (reader = open(EzXML.StreamReader, $file); for x in reader; end; close(reader))

#-----------------------------------------------------------------------------# Lazy Iteration: Collect Tags
kind = "Collect Tags"

name = "via XML.LazyNode"
@info name
bench = @benchmark [tag(x) for x in o] setup=(o = read(file, LazyNode))
push!(df, (;kind, name, bench))
@add_benchmark "Collect Tags" "LazyNode" [tag(x) for x in o] setup = (o = read(file, LazyNode))
@add_benchmark "Collect Tags" "EzXML.StreamReader" [r.name for x in r if x == EzXML.READER_ELEMENT] setup=(r=open(EzXML.StreamReader, file)) teardown=(close(r))


name = "via EzXML.StreamReader"
@info name
bench = @benchmark [r.name for x in r if x == EzXML.READER_ELEMENT] setup=(r=open(EzXML.StreamReader, file)) teardown=(close(r))
push!(df, (;kind, name, bench))


name = "via EzXML.readxml"
@info name
function get_tags(o::EzXML.Node)
out = String[]
for node in EzXML.eachelement(o)
Expand All @@ -114,18 +56,14 @@ function get_tags(o::EzXML.Node)
end
out
end
bench = @benchmark get_tags(o.root) setup=(o = EzXML.readxml(file))
push!(df, (;kind, name, bench))



@add_benchmark "Collect Tags" "EzXML.readxml" get_tags(o.root) setup=(o = EzXML.readxml(file))


#-----------------------------------------------------------------------------# Plots
function plot(df, kind)
g = groupby(df, :kind)
sub = g[(;kind)]
x = map(row -> "$(row.kind): $(row.name)", eachrow(sub))
x = map(row -> "$(row.name)", eachrow(sub))
y = map(x -> median(x).time / 1000^2, sub.bench)
display(barplot(x, y, title = "$kind Time (ms)", border=:none, width=50))
end
Expand Down
15 changes: 8 additions & 7 deletions src/XML.jl
Original file line number Diff line number Diff line change
Expand Up @@ -253,17 +253,19 @@ nodetype(o) = o.nodetype
tag(o) = o.tag
attributes(o) = o.attributes
value(o) = o.value
children(o::T) where {T} = isnothing(o.children) ? T[] : o.children
children(o::T) where {T} = isnothing(o.children) ? () : o.children

depth(o) = missing
depth(o) = 1
parent(o) = missing
next(o) = missing
prev(o) = missing

is_simple(o) = nodetype(o) == Element && (isnothing(attributes(o)) || isempty(attributes(o))) &&
length(children(o)) == 1 && nodetype(only(o)) in [Text, CData]
length(children(o)) == 1 && nodetype(only(o)) in (Text, CData)

simplevalue(o) = is_simple(o) ? value(only(o)) : error("`XML.simplevalue(o)` is only defined for simple nodes.")
simple_value(o) = is_simple(o) ? value(only(o)) : error("`XML.simple_value` is only defined for simple nodes.")

Base.@deprecate_binding simplevalue simple_value

#-----------------------------------------------------------------------------# nodes_equal
function nodes_equal(a, b)
Expand Down Expand Up @@ -293,8 +295,8 @@ Base.length(o::AbstractXMLNode) = length(children(o))

#-----------------------------------------------------------------------------# printing
function _show_node(io::IO, o)
!ismissing(depth(o)) && print(io, depth(o), ':')
printstyled(io, typeof(o), ' '; color=:light_black)
!ismissing(depth(o)) && printstyled(io, "(depth=", depth(o), ") ", color=:light_black)
printstyled(io, nodetype(o), ; color=:light_green)
if o.nodetype === Text
printstyled(io, ' ', repr(value(o)))
Expand Down Expand Up @@ -352,13 +354,12 @@ write(x; kw...) = (io = IOBuffer(); write(io, x; kw...); String(take!(io)))

write(filename::AbstractString, x; kw...) = open(io -> write(io, x; kw...), filename, "w")

function write(io::IO, x; indentsize::Int=2, depth::Union{Missing,Int}=depth(x))
function write(io::IO, x; indentsize::Int=2, depth::Int=depth(x))
indent = ' ' ^ indentsize
nodetype = XML.nodetype(x)
tag = XML.tag(x)
value = XML.value(x)
children = XML.children(x)
depth = ismissing(depth) ? 1 : depth

padding = indent ^ max(0, depth - 1)
print(io, padding)
Expand Down
6 changes: 3 additions & 3 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ end
@test s == unescape(unescape(escape(s)))

n = Element("tag", Text(s))
@test XML.simplevalue(n) == s
@test XML.simple_value(n) == s

XML.escape!(n)
@test XML.simplevalue(n) == escape(s)
@test XML.simple_value(n) == escape(s)

XML.unescape!(n)
@test XML.simplevalue(n) == s
@test XML.simple_value(n) == s
end

#-----------------------------------------------------------------------------# DTD
Expand Down

0 comments on commit c336152

Please sign in to comment.