Skip to content

Commit c739d9a

Browse files
committed
nodeparse
1 parent fc547ea commit c739d9a

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

src/xmlutils/nodeparse.jl

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# TODO use traits for hasmethod checks
2+
3+
# Scalar parsers
4+
5+
# content input
6+
"""
7+
noedparse(type::Type, node)
8+
nodeparse(type::Type, content)
9+
noedparse(::Type{Vector{T}}, nodes)
10+
nodeparse(::Type{Vector{T}}, contents)
11+
Parses a node content with the specidied type
12+
"""
13+
nodeparse(type::Type{<:Number}, content::String) = parse(type, content)
14+
nodeparse(type::Type{<:AbstractString}, content::String) = content
15+
function nodeparse(type::Type, content::String)
16+
# TODO: better specialized method detection
17+
# https://julialang.slack.com/archives/C6A044SQH/p1578442480438100
18+
if hasmethod(type, Tuple{String}) && Core.Compiler.return_type(type, Tuple{Node})=== Union{}
19+
return type(content)
20+
elseif hasmethod(convert, Tuple{String, type})
21+
return convert(type, content)
22+
elseif hasmethod(parse, Tuple{type, String})
23+
return parse(type, content)
24+
else
25+
error("Could not parse a String as type $type")
26+
end
27+
end
28+
29+
# elm input
30+
nodeparse(type::Type{<:Union{Number, AbstractString}}, elm::Node) = nodeparse(type, elm.content)
31+
function nodeparse(type::Type, elm::Node)
32+
content = elm.content
33+
if hasmethod(type, Tuple{String}) && Core.Compiler.return_type(type, Tuple{Node})=== Union{}
34+
return type(content)
35+
elseif hasmethod(convert, Tuple{String, type})
36+
return convert(type, content)
37+
elseif hasmethod(parse, Tuple{type, String})
38+
return parse(type, content)
39+
else
40+
# should be the last to avoid invoking generic methods
41+
return type(elm)
42+
end
43+
end
44+
45+
# Vector parsers
46+
# both elm and content input
47+
48+
# TODO slow for other than String|Number but compact
49+
numorstr(::Nothing) = [Number, AbstractString]
50+
@transform function nodeparse(type::Type{<:numorstr()}, elmsOrContents::Vector{Node})
51+
return nodeparse.(type, elmsOrContents)
52+
end
53+
@transform function nodeparse(type::Type{<:numorstr()}, elmsOrContents::Vector{String})
54+
return nodeparse.(type, elmsOrContents)
55+
end
56+
# TODO Faster code, but has redundancy:
57+
58+
function nodeparse(::Type{T}, contents::Vector{String}) where {T}
59+
elms_typed = Vector{T}(undef, length(contents))
60+
i = 1
61+
if hasmethod(type, Tuple{String}) && Core.Compiler.return_type(type, Tuple{Node})=== Union{}
62+
for content in contents
63+
elms_typed[i] = type(content)
64+
i+=1
65+
end
66+
elseif hasmethod(convert, Tuple{String, type})
67+
for content in contents
68+
elms_typed[i] = convert(type, content)
69+
i+=1
70+
end
71+
elseif hasmethod(parse, Tuple{type, String})
72+
for content in contents
73+
elms_typed[i] = parse(type, content)
74+
i+=1
75+
end
76+
else
77+
error("Could not parse a String as type $type")
78+
end
79+
return elms_typed
80+
end
81+
82+
function nodeparse(type::Type{T}, elms::Vector{Node}) where {T}
83+
elms_typed = Vector{T}(undef, length(elms))
84+
i = 1
85+
if hasmethod(type, Tuple{String}) && Core.Compiler.return_type(type, Tuple{Node})=== Union{}
86+
for elm in elms
87+
elms_typed[i] = type(elm.content)
88+
i+=1
89+
end
90+
elseif hasmethod(convert, Tuple{String, type})
91+
for elm in elms
92+
elms_typed[i] = convert(type, elm.content)
93+
i+=1
94+
end
95+
elseif hasmethod(parse, Tuple{type, String})
96+
for elm in elms
97+
elms_typed[i] = parse(type, elm.content)
98+
i+=1
99+
end
100+
else
101+
# should be the last to avoid invoking generic methods
102+
for elm in elms
103+
elms_typed[i] = type(elm)
104+
i+=1
105+
end
106+
end
107+
return elms_typed
108+
end

0 commit comments

Comments
 (0)