-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathluahml.lua
293 lines (252 loc) · 6.29 KB
/
luahml.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
local xselec = require"xselec"
local mt_common, mt_para, mt_char
, make_elem, iter
---------------------------------------
-- 모든 요소의 기본 메서드들
---------------------------------------
local function forward_attr(mt)
mt = mt or {}
mt.__index = function(t, key)
local val = rawget(mt, key)
if val then return val end
val = rawget(t, key)
if val then return val end
local node = rawget(t, 'node')
if node then
if type(node[key]) == 'table' and node[key].tag then
return make_elem(node[key])
else
return node.attr[key]
end
end
end
mt.__newindex = function(t, key, val)
local v = rawget(t, key)
if v ~= nil then
rawset(t, key, val)
elseif type(key) == 'string' and key:find('^%u') then
if rawget(t.node.attr, key) == nil then
table.insert(t.node.attr, key)
end
rawset(t.node.attr, key, val)
else
rawset(t, key, val)
end
end
mt.__call = function(t, filter)
local result = {}
for i, v in ipairs(t.node(filter)) do
table.insert(result, make_elem(v))
end
return result
end
mt.val = function(t, val)
if type(t.node[1]) ~= 'string' then return end
if val then
rawset(t.node, 1, tostring(val))
else
return tostring(t.node[1])
end
end
mt.iter = iter
return mt
end
iter = function(t, filter)
local state = { index = 0}
if filter then
state.items = t.node(filter)
else
state.items = t.node
end
return function(state)
local item
while true do
state.index = state.index + 1
if state.index > #(state.items) then return end
item = rawget(state.items, state.index)
if item.tag then break end
end
return make_elem(item)
end, state
end
mt_common = forward_attr()
make_elem = function(node, mt)
local metatable_map = {P = mt_para, CHAR = mt_char}
local elem = {node = xselec.make_selectable(node)}
local mt_ = mt or metatable_map[node.tag] or mt_common
setmetatable(elem, mt_)
return elem
end
-- P 요소용 메서드
mt_para = forward_attr()
mt_para.append = function(self, para)
table.insert(self.section.node, self.nth+1, para)
end
mt_para.prepend = function(self, para)
table.insert(self.section.node, self.nth, para)
return make_elem(para)
end
-- CHAR용 메서드
mt_char = forward_attr()
mt_char.val = function(elem, str)
local charmap = {TAB = '\t', LINEBREAK = '\n',
NBSPACE = string.char(160)
}
if str then
for k, v in pairs(charmap) do
str = str:gsub(v, '<' .. k .. '/>')
end
local nodes = xselec.load_from_string('<DUMMY>' .. str .. '</DUMMY>')
for i, v in ipairs(nodes) do
elem.node[i] = v
end
elem.node[#nodes+1] = nil
return
else
local str = ''
for i, v in ipairs(elem.node) do
if type(v) == 'table' and v.tag then
local cd = charmap[v.tag] or xselec.make_selectable(v):toxml()
str = str .. cd
else
str = str .. v
end
end
return str
end
end
---------------------------------------------
-- 기타 함수들
---------------------------------------------
local function get_fonts(doc)
local fonts = {}
for e in doc:iter'HEAD MAPPINGTABLE FONT' do
table.insert(fonts, e)
fonts[e.Id] = e
end
return fonts
end
local function get_shapes(doc)
local para_shapes, char_shapes = {}, {}
for i, e in ipairs(doc'HEAD>MAPPINGTABLE>PARASHAPELIST>PARASHAPE') do
e.margin = make_elem(e.node'PARAMARGIN'[1])
local border = make_elem(e.node'PARABORDER'[1])
local bd = border.BorderFill
local brush = doc('BORDERFILL[Id="' .. bd .. '"]>FILLBRUSH>WINDOWBRUSH')[1]
if brush then
e.shade_color = brush.node.attr['FaceColor']
end
para_shapes[tostring(i)] = e
para_shapes[i] = e
end
for i, e in ipairs(doc'HEAD>MAPPINGTABLE>CHARSHAPELIST>CHARSHAPE') do
e.font = {}
local fontid = e'FONTID'[1]
for i, v in ipairs(fontid.node.attr) do
local font_lang = fontid.node.attr[i]
e.font[font_lang] = doc.fonts[fontid.node.attr[font_lang]]
end
e.italic = (e'ITALIC'[1] and true)
e.bold = (e'BOLD'[1] and true)
e.sub = (e'SUBSCRIPT'[1] and true)
e.sup = (e'SUPERSCRIPT'[1] and true)
char_shapes[tostring(i)] = e
char_shapes[i] = e
end
return para_shapes, char_shapes
end
local function Style(node,doc)
local elem = make_elem(node)
if node.attr.ParaShape then
elem.para_shape = doc.para_shapes[node.attr.ParaShape+1]
end
if node.attr.CharShape then
elem.char_shape = doc.char_shapes[node.attr.CharShape+1]
end
return elem
end
local function get_styles(doc)
local styles = doc.node'HEAD>MAPPINGTABLE>STYLELIST>STYLE'
local para_styles, char_styles = {doc=doc}, {doc=doc}
for node in styles:iter() do
if node.attr.Type == 'Para' then
target_list = para_styles
else
target_list = char_styles
end
local style = Style(node, doc)
table.insert(target_list, style)
target_list[style.Name] = style
target_list[style.Id] = style
if style.EngName then
target_list[style.EngName] = style
end
end
return para_styles, char_styles
end
local function get_chars(doc)
local result = {}
for _, p in ipairs(doc:get_paras()) do
local first_c = true
local last_c
for t in p:iter'TEXT' do
local item
for c in t:iter'CHAR' do
item = make_elem(c.node)
item.text = t
item.para = p
item.first = first_c
first_c = nil
last_c = item
table.insert(result, item)
item.nth = #result
end
end
if last_c then last_c.last = true end
end
return result
end
local function get_paras(doc)
local result = {}
for s in doc.node'BODY SECTION':iter() do
local section = make_elem(s)
for i, p in ipairs(s) do
local elem = make_elem(p, mt_paras)
elem.section = section
elem.nth = i
table.insert(result, elem)
end
end
return result
end
local function load(filename)
local xml, err = xselec.load_from_file(filename)
if xml == nil then
return nil, err
end
local doc = make_elem(xml)
-- HML 문서 객체의 속성, 메서드
doc.iter = iter
doc.filename = filename
doc.fonts = get_fonts(doc)
doc.para_shapes, doc.char_shapes = get_shapes(doc)
doc.para_styles, doc.char_styles = get_styles(doc)
doc.save = function(self, filename)
filename = filename or self.filename
local f = io.open(filename,'wb')
f:write(self.node:toxml())
f:close()
end
doc.output = function(self, puts)
puts = puts or io.write
self.node:output(puts)
end
doc.get_paras = get_paras
doc.get_chars = get_chars
return doc
end
-- 모듈 인터페이스 --
return {
load = load
, make_elem = make_elem
}