Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 23 additions & 10 deletions src/XML.jl
Original file line number Diff line number Diff line change
Expand Up @@ -357,56 +357,69 @@ 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::Int=1)
function write(io::IO, x, ctx::Vector{Bool}=[false]; indentsize::Int=2, depth::Int=1)
indent = ' ' ^ indentsize
nodetype = XML.nodetype(x)
tag = XML.tag(x)
value = XML.value(x)
children = XML.children(x)

padding = indent ^ max(0, depth - 1)
print(io, padding)
!ctx[end] && print(io, padding)

if nodetype === Text
print(io, value)

elseif nodetype === Element
push!(ctx, ctx[end])
update_ctx!(ctx, x)
print(io, '<', tag)
_print_attrs(io, x)
print(io, isempty(children) ? '/' : "", '>')
if !isempty(children)
if length(children) == 1 && XML.nodetype(only(children)) === Text
write(io, only(children); indentsize=0)
write(io, only(children), ctx; indentsize=0)
print(io, "</", tag, '>')
else
println(io)
!ctx[end] && println(io)
foreach(children) do child
write(io, child; indentsize, depth = depth + 1)
println(io)
write(io, child, ctx; indentsize, depth=depth + 1)
!ctx[end] && println(io)
end
print(io, padding, "</", tag, '>')
print(io, !ctx[end] ? padding : "", "</", tag, '>')
end
end
pop!(ctx)

elseif nodetype === DTD
print(io, "<!DOCTYPE ", value, '>')

elseif nodetype === Declaration
print(io, "<?xml")
_print_attrs(io, x)
print(io, "?>")

elseif nodetype === ProcessingInstruction
print(io, "<?", tag)
_print_attrs(io, x)
print(io, "?>")

elseif nodetype === Comment
print(io, "<!--", value, "-->")

elseif nodetype === CData
print(io, "<![CData[", value, "]]>")

elseif nodetype === Document
foreach(children) do child
write(io, child; indentsize)
println(io)
write(io, child, ctx; indentsize)
!ctx[end] && println(io)
end

else
error("Unreachable case reached during XML.write")
end
end

end

end # module XML
20 changes: 12 additions & 8 deletions src/raw.jl
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,11 @@ function parent(o::Raw)
end

#-----------------------------------------------------------------------------# next Raw
isspace(x::UInt8) = Base.isspace(Char(x))
# isspace(x::UInt8) = Base.isspace(Char(x))

# XML whitespace per XML 1.0/1.1 production S:
# S ::= (#x20 | #x9 | #xD | #xA)+
@inline xml_isspace(b::UInt8)::Bool = (b == 0x20) | (b == 0x09) | (b == 0x0A) | (b == 0x0D)

"""
next(node) --> typeof(node) or Nothing
Expand All @@ -353,7 +357,7 @@ function next_xml_space(o::Raw)
has_xml_space = o.has_xml_space
ctx = copy(o.ctx)
last_type = type
k = findnext(!isspace, data, i)
k = findnext(!xml_isspace, data, i)
if isnothing(k)
return nothing
end
Expand All @@ -369,11 +373,11 @@ function next_xml_space(o::Raw)
if c !== '<' || ctx[end] && c === '<' && b === ' ' && last_type === RawElementOpen && d === '/'
type = RawText
j = findnext(==(UInt8('<')), data, i) - 1
j = ctx[end] ? j : findprev(!isspace, data, j) # preserving whitespace if needed
j = ctx[end] ? j : findprev(!xml_isspace, data, j) # preserving whitespace if needed
if last_type === RawElementClose || last_type === RawElementSelfClosed|| last_type === RawDocument
# Maybe drop pure-whitespace inter-element text nodes?
# (e.g. whitespace between a closing and an opening tag which would otherwise make an orphan text node)
#if all(isspace, @view data[i:j]) && depth > 1
#if all(xml_isspace, @view data[i:j]) && depth > 1
# return next(Raw(type, depth, j, 0, data, ctx, has_xml_space))
#end
end
Expand Down Expand Up @@ -429,7 +433,7 @@ function next_no_xml_space(o::Raw) # same as v0.3.5
type = o.type
has_xml_space = o.has_xml_space
ctx = [false]
i = findnext(!isspace, data, i)
i = findnext(!xml_isspace, data, i)
if isnothing(i)
return nothing
end
Expand All @@ -441,7 +445,7 @@ function next_no_xml_space(o::Raw) # same as v0.3.5
if c !== '<'
type = RawText
j = findnext(==(UInt8('<')), data, i) - 1
j = findprev(!isspace, data, j) # "rstrip"
j = findprev(!xml_isspace, data, j) # "rstrip"
elseif c === '<'
c2 = Char(o.data[i+1])
if c2 === '!'
Expand Down Expand Up @@ -514,7 +518,7 @@ function prev_no_xml_space(o::Raw) # same as v0.3.5
ctx = has_xml_space ? copy(o.ctx) : [false]
type === RawDocument && return nothing
j = o.pos - 1
j = findprev(!isspace, data, j)
j = findprev(!xml_isspace, data, j)
if isnothing(j)
return Raw(data, has_xml_space, ctx) # RawDocument
end
Expand All @@ -523,7 +527,7 @@ function prev_no_xml_space(o::Raw) # same as v0.3.5
if c !== '>' # text
type = RawText
i = findprev(==(UInt8('>')), data, j) + 1
i = findnext(!isspace, data, i) # "lstrip"
i = findnext(!xml_isspace, data, i) # "lstrip"
elseif c === '>'
c2 = Char(o.data[j-1])
if c2 === '-'
Expand Down
Loading