cbeta 3.8.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/cbeta.rb +0 -6
- data.tar.gz.sig +0 -0
- metadata +1 -10
- metadata.gz.sig +0 -0
- data/lib/cbeta/html_to_pdf.rb +0 -75
- data/lib/cbeta/html_to_text.rb +0 -151
- data/lib/cbeta/p5a_to_html.rb +0 -813
- data/lib/cbeta/p5a_to_html_for_every_edition.rb +0 -940
- data/lib/cbeta/p5a_to_html_for_pdf.rb +0 -751
- data/lib/cbeta/p5a_to_simple_html.rb +0 -426
- data/lib/data/html-for-pdf.css +0 -144
- data/lib/data/pdf-template.htm +0 -14
- data/lib/data/unicode-1.1.json +0 -1
|
@@ -1,940 +0,0 @@
|
|
|
1
|
-
require 'cgi'
|
|
2
|
-
require 'date'
|
|
3
|
-
require 'fileutils'
|
|
4
|
-
require 'json'
|
|
5
|
-
require 'nokogiri'
|
|
6
|
-
require 'set'
|
|
7
|
-
require_relative 'cbeta_share'
|
|
8
|
-
|
|
9
|
-
# Convert CBETA XML P5a to HTML for every edition
|
|
10
|
-
#
|
|
11
|
-
# 例如 T0001 長阿含經 有 CBETA、元、宋、聖、磧砂、unknown、大、明、麗等版本,
|
|
12
|
-
# 每一個版本都會輸出一個 HTML 檔,以版本為檔名。
|
|
13
|
-
#
|
|
14
|
-
# CBETA XML P5a 可由此取得: https://github.com/cbeta-git/xml-p5a
|
|
15
|
-
#
|
|
16
|
-
# 轉檔規則請參考: http://wiki.dila.edu.tw/pages/CBETA_XML_P5a_轉_HTML
|
|
17
|
-
class CBETA::P5aToHTMLForEveryEdition
|
|
18
|
-
# 內容不輸出的元素
|
|
19
|
-
PASS=['back', 'teiHeader']
|
|
20
|
-
|
|
21
|
-
# 某版用字缺的符號
|
|
22
|
-
MISSING = '-'
|
|
23
|
-
|
|
24
|
-
private_constant :PASS, :MISSING
|
|
25
|
-
|
|
26
|
-
# @param xml_root [String] 來源 CBETA XML P5a 路徑
|
|
27
|
-
# @param out_root [String] 輸出 HTML 路徑
|
|
28
|
-
def initialize(xml_root, out_root)
|
|
29
|
-
@xml_root = xml_root
|
|
30
|
-
@out_root = out_root
|
|
31
|
-
@cbeta = CBETA.new
|
|
32
|
-
@gaijis = CBETA::Gaiji.new
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# 將 CBETA XML P5a 轉為 HTML
|
|
36
|
-
#
|
|
37
|
-
# @example for convert 大正藏全部:
|
|
38
|
-
#
|
|
39
|
-
# x2h = CBETA::P5aToHTML.new('/PATH/TO/CBETA/XML/P5a', '/OUTPUT/FOLDER')
|
|
40
|
-
# x2h.convert('T')
|
|
41
|
-
#
|
|
42
|
-
# T 是大正藏的 ID, CBETA 的藏經 ID 系統請參考: http://www.cbeta.org/format/id.php
|
|
43
|
-
def convert(target=nil)
|
|
44
|
-
return convert_all if target.nil?
|
|
45
|
-
|
|
46
|
-
arg = target.upcase
|
|
47
|
-
if arg.size.between?(1,2)
|
|
48
|
-
convert_canon(arg)
|
|
49
|
-
else
|
|
50
|
-
puts "因為某些典籍單卷跨冊,轉檔必須以某部藏經為單位,例如參數 T 表示轉換整個大正藏。"
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
private
|
|
55
|
-
|
|
56
|
-
include CbetaShare
|
|
57
|
-
|
|
58
|
-
def before_parse_xml(xml_fn)
|
|
59
|
-
@back = { 0 => '' }
|
|
60
|
-
@back_orig = { 0 => '' }
|
|
61
|
-
@char_count = 1
|
|
62
|
-
@dila_note = 0
|
|
63
|
-
@div_count = 0
|
|
64
|
-
@in_l = false
|
|
65
|
-
@juan = 0
|
|
66
|
-
@lg_row_open = false
|
|
67
|
-
@mod_notes = Set.new
|
|
68
|
-
@next_line_buf = ''
|
|
69
|
-
@notes_mod = {}
|
|
70
|
-
@notes_orig = {}
|
|
71
|
-
@notes_dila = {}
|
|
72
|
-
@open_divs = []
|
|
73
|
-
@sutra_no = File.basename(xml_fn, ".xml")
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def convert_all
|
|
77
|
-
Dir.entries(@xml_root).sort.each do |c|
|
|
78
|
-
next unless c.match(CBETA::CANON_ID)
|
|
79
|
-
convert_canon(c)
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def convert_canon(c)
|
|
84
|
-
@series = c
|
|
85
|
-
puts 'convert canon: ' + c
|
|
86
|
-
folder = File.join(@xml_root, @series)
|
|
87
|
-
|
|
88
|
-
@out_folder = File.join(@out_root, @series)
|
|
89
|
-
FileUtils::rm_rf @out_folder
|
|
90
|
-
FileUtils::mkdir_p @out_folder
|
|
91
|
-
|
|
92
|
-
@html_buf = {}
|
|
93
|
-
@back_buf = {}
|
|
94
|
-
|
|
95
|
-
Dir.entries(folder).sort.each do |vol|
|
|
96
|
-
next if vol.start_with? '.'
|
|
97
|
-
convert_vol(vol)
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def convert_sutra(xml_fn)
|
|
102
|
-
puts "convert sutra #{xml_fn}"
|
|
103
|
-
|
|
104
|
-
before_parse_xml(xml_fn)
|
|
105
|
-
|
|
106
|
-
text = parse_xml(xml_fn)
|
|
107
|
-
|
|
108
|
-
# 註標移到 lg-cell 裡面,不然以 table 呈現 lg 會有問題
|
|
109
|
-
text.gsub!(/(<a class='noteAnchor'[^>]*><\/a>)(<div class="lg-cell"[^>]*>)/, '\2\1')
|
|
110
|
-
|
|
111
|
-
juans = text.split(/(<juan \d+>)/)
|
|
112
|
-
juan_no = nil
|
|
113
|
-
buf = ''
|
|
114
|
-
# 一卷一檔
|
|
115
|
-
juans.each { |j|
|
|
116
|
-
if j =~ /<juan (\d+)>$/
|
|
117
|
-
juan_no = $1.to_i
|
|
118
|
-
elsif juan_no.nil?
|
|
119
|
-
buf = j
|
|
120
|
-
else
|
|
121
|
-
write_juan(juan_no, buf+j)
|
|
122
|
-
buf = ''
|
|
123
|
-
end
|
|
124
|
-
}
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def convert_vol(vol)
|
|
128
|
-
puts "convert volumn: #{vol}"
|
|
129
|
-
|
|
130
|
-
canon = CBETA.get_canon_from_vol(vol)
|
|
131
|
-
@orig = @cbeta.get_canon_symbol(canon)
|
|
132
|
-
abort "未處理底本" if @orig.nil?
|
|
133
|
-
@orig_short = @orig.sub(/^【(.*)】$/, '\1')
|
|
134
|
-
|
|
135
|
-
@vol = vol
|
|
136
|
-
|
|
137
|
-
source = File.join(@xml_root, @series, vol)
|
|
138
|
-
Dir.entries(source).sort.each do |f|
|
|
139
|
-
next if f.start_with? '.'
|
|
140
|
-
fn = File.join(source, f)
|
|
141
|
-
convert_sutra(fn)
|
|
142
|
-
end
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
def e_anchor(e)
|
|
146
|
-
id = e['id']
|
|
147
|
-
if e.has_attribute?('id')
|
|
148
|
-
if id.start_with?('nkr_note_orig')
|
|
149
|
-
note = @notes[id]
|
|
150
|
-
note_text = traverse(note)
|
|
151
|
-
n = id[/^nkr_note_orig_(.*)$/, 1]
|
|
152
|
-
@back[@juan] += "<span class='footnote' id='n#{n}'>#{note_text}</span>\n"
|
|
153
|
-
return "<a class='noteAnchor' href='#n#{n}'></a>"
|
|
154
|
-
elsif id.start_with? 'fx'
|
|
155
|
-
return "<span class='star'>[*]</span>"
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
if e.has_attribute?('type')
|
|
160
|
-
if e['type'] == 'circle'
|
|
161
|
-
return '◎'
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
''
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
def e_app(e)
|
|
169
|
-
r = ''
|
|
170
|
-
if e['type'] == 'star'
|
|
171
|
-
c = e['corresp'][1..-1]
|
|
172
|
-
r = "<a class='noteAnchor star' href='#n#{c}'></a>"
|
|
173
|
-
end
|
|
174
|
-
r + traverse(e)
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
def e_byline(e)
|
|
178
|
-
r = '<p class="byline">'
|
|
179
|
-
r += line_info
|
|
180
|
-
r += traverse(e)
|
|
181
|
-
r + '</p>'
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def e_cell(e)
|
|
185
|
-
doc = Nokogiri::XML::Document.new
|
|
186
|
-
cell = doc.create_element('div')
|
|
187
|
-
cell['class'] = 'bip-table-cell'
|
|
188
|
-
cell['rowspan'] = e['rows'] if e.key? 'rows'
|
|
189
|
-
cell['colspan'] = e['cols'] if e.key? 'cols'
|
|
190
|
-
cell.inner_html = traverse(e)
|
|
191
|
-
to_html(cell)
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
def e_corr(e)
|
|
195
|
-
r = ''
|
|
196
|
-
if e.parent.name == 'choice'
|
|
197
|
-
sic = e.parent.at_xpath('sic')
|
|
198
|
-
unless sic.nil?
|
|
199
|
-
n = @notes_dila[@juan].size + 1
|
|
200
|
-
r = "<a class='noteAnchor dila' href='#dila_note#{n}'></a>"
|
|
201
|
-
|
|
202
|
-
note = @orig
|
|
203
|
-
sic_text = traverse(sic, 'back')
|
|
204
|
-
if sic_text.empty?
|
|
205
|
-
note += MISSING
|
|
206
|
-
else
|
|
207
|
-
note += sic_text
|
|
208
|
-
end
|
|
209
|
-
@notes_dila[@juan] << "<span class='footnote dila' id='dila_note#{n}'>#{note}</span>"
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
r + "<r w='【CBETA】' l='#{@lb}'><span class='cbeta'>%s</span></r>" % traverse(e)
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
def e_div(e)
|
|
216
|
-
@div_count += 1
|
|
217
|
-
n = @div_count
|
|
218
|
-
if e.has_attribute? 'type'
|
|
219
|
-
@open_divs << e
|
|
220
|
-
r = traverse(e)
|
|
221
|
-
@open_divs.pop
|
|
222
|
-
return "<!-- begin div#{n}--><div class='div-#{e['type']}'>#{r}</div><!-- end of div#{n} -->"
|
|
223
|
-
else
|
|
224
|
-
return traverse(e)
|
|
225
|
-
end
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
def e_figure(e)
|
|
229
|
-
"<p class='figure'>%s</p>" % traverse(e)
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
def e_foreign(e)
|
|
233
|
-
return '' if e.key?('place') and e['place'].include?('foot')
|
|
234
|
-
traverse(e)
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
def e_g(e, mode)
|
|
238
|
-
# if 有 <mapping type="unicode">
|
|
239
|
-
# if 不在 Unicode Extension C, D, E 範圍裡
|
|
240
|
-
# 直接採用
|
|
241
|
-
# else
|
|
242
|
-
# 預設呈現 unicode, 但仍包缺字資訊,供點選開 popup
|
|
243
|
-
# else if 有 <mapping type="normal_unicode">
|
|
244
|
-
# 預設呈現 normal_unicode, 但仍包缺字資訊,供點選開 popup
|
|
245
|
-
# else if 有 normalized form
|
|
246
|
-
# 預設呈現 normalized form, 但仍包缺字資訊,供點選開 popup
|
|
247
|
-
# else
|
|
248
|
-
# 預設呈現組字式, 但仍包缺字資訊,供點選開 popup
|
|
249
|
-
gid = e['ref'][1..-1]
|
|
250
|
-
g = @gaijis[gid]
|
|
251
|
-
abort "Line:#{__LINE__} 無缺字資料:#{gid}" if g.nil?
|
|
252
|
-
zzs = g['zzs']
|
|
253
|
-
|
|
254
|
-
if mode == 'txt'
|
|
255
|
-
return g['roman'] if gid.start_with?('SD')
|
|
256
|
-
if zzs.nil?
|
|
257
|
-
abort "缺組字式:#{g}"
|
|
258
|
-
else
|
|
259
|
-
return zzs
|
|
260
|
-
end
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
@char_count += 1
|
|
264
|
-
|
|
265
|
-
if gid.start_with?('SD')
|
|
266
|
-
case gid
|
|
267
|
-
when 'SD-E35A'
|
|
268
|
-
return '('
|
|
269
|
-
when 'SD-E35B'
|
|
270
|
-
return ')'
|
|
271
|
-
else
|
|
272
|
-
return "<span class='siddam' roman='#{g['roman']}' code='#{gid}' char='#{g['sd-char']}'/>"
|
|
273
|
-
end
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
if gid.start_with?('RJ')
|
|
277
|
-
return "<span class='ranja' roman='#{g['roman']}' code='#{gid}' char='#{g['rj-char']}'/>"
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
default = ''
|
|
281
|
-
if g.has_key?('unicode')
|
|
282
|
-
#if @unicode1.include?(g['unicode'])
|
|
283
|
-
# 如果在 unicode ext-C, ext-D, ext-E 範圍內
|
|
284
|
-
if (0x2A700..0x2CEAF).include? g['unicode'].hex
|
|
285
|
-
default = g['unicode-char']
|
|
286
|
-
else
|
|
287
|
-
return g['unicode-char'] # 直接採用 unicode
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
nor = ''
|
|
292
|
-
if g.has_key?('normal_unicode')
|
|
293
|
-
nor = g['normal_unicode']
|
|
294
|
-
default = nor if default.empty?
|
|
295
|
-
end
|
|
296
|
-
|
|
297
|
-
if g.has_key?('normal')
|
|
298
|
-
nor += ', ' unless nor==''
|
|
299
|
-
nor += g['normal']
|
|
300
|
-
default = g['normal'] if default.empty?
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
default = zzs if default.empty?
|
|
304
|
-
|
|
305
|
-
href = 'http://dict.cbeta.org/dict_word/gaiji-cb/%s/%s.gif' % [gid[2, 2], gid]
|
|
306
|
-
unless @back[@juan].include?(href)
|
|
307
|
-
@back[@juan] += "<span id='#{gid}' class='gaijiInfo' figure_url='#{href}' zzs='#{zzs}' nor='#{nor}'>#{default}</span>\n"
|
|
308
|
-
end
|
|
309
|
-
unless @back_orig[@juan].include?(href)
|
|
310
|
-
@back_orig[@juan] += "<span id='#{gid}' class='gaijiInfo' figure_url='#{href}' zzs='#{zzs}' nor='#{nor}'>#{default}</span>\n"
|
|
311
|
-
end
|
|
312
|
-
"<a class='gaijiAnchor' href='##{gid}'>#{default}</a>"
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
def e_graphic(e)
|
|
316
|
-
url = File.basename(e['url'])
|
|
317
|
-
"<span imgsrc='#{url}' class='graphic'></span>"
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
def e_head(e)
|
|
321
|
-
r = ''
|
|
322
|
-
unless e['type'] == 'added'
|
|
323
|
-
i = @open_divs.size
|
|
324
|
-
r = "<p class='head' data-head-level='#{i}'>%s</p>" % traverse(e)
|
|
325
|
-
end
|
|
326
|
-
r
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
def e_item(e)
|
|
330
|
-
"<li>%s</li>\n" % traverse(e)
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
def e_juan(e)
|
|
334
|
-
"<p class='juan'>%s</p>" % traverse(e)
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
def e_l(e)
|
|
338
|
-
if @lg_type == 'abnormal'
|
|
339
|
-
return traverse(e)
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
@in_l = true
|
|
343
|
-
|
|
344
|
-
doc = Nokogiri::XML::Document.new
|
|
345
|
-
cell = doc.create_element('div')
|
|
346
|
-
cell['class'] = 'lg-cell'
|
|
347
|
-
cell.inner_html = traverse(e)
|
|
348
|
-
|
|
349
|
-
if @first_l
|
|
350
|
-
parent = e.parent()
|
|
351
|
-
if parent.has_attribute?('rend')
|
|
352
|
-
indent = parent['rend'].scan(/text-indent:[^:]*/)
|
|
353
|
-
unless indent.empty?
|
|
354
|
-
cell['style'] = indent[0]
|
|
355
|
-
end
|
|
356
|
-
end
|
|
357
|
-
@first_l = false
|
|
358
|
-
end
|
|
359
|
-
r = to_html(cell)
|
|
360
|
-
|
|
361
|
-
unless @lg_row_open
|
|
362
|
-
r = "\n<div class='lg-row'>" + r
|
|
363
|
-
@lg_row_open = true
|
|
364
|
-
end
|
|
365
|
-
@in_l = false
|
|
366
|
-
r
|
|
367
|
-
end
|
|
368
|
-
|
|
369
|
-
def e_lb(e)
|
|
370
|
-
return '' if e['type']=='old'
|
|
371
|
-
|
|
372
|
-
# 卍續藏有 X 跟 R 兩種 lb
|
|
373
|
-
if @series=='X' and e['ed'].start_with? 'R'
|
|
374
|
-
@lb_r = e['ed'] + '.' + e['n']
|
|
375
|
-
return ''
|
|
376
|
-
end
|
|
377
|
-
|
|
378
|
-
@char_count = 1
|
|
379
|
-
@lb = e['n']
|
|
380
|
-
line_head = CBETA.get_linehead(@sutra_no, e['n'])
|
|
381
|
-
r = ''
|
|
382
|
-
#if e.parent.name == 'lg' and $lg_row_open
|
|
383
|
-
if @lg_row_open && !@in_l
|
|
384
|
-
# 每行偈頌放在一個 lg-row 裡面
|
|
385
|
-
# T46n1937, p. 914a01, l 包雙行夾註跨行
|
|
386
|
-
# T20n1092, 337c16, lb 在 l 中間,不結束 lg-row
|
|
387
|
-
r += "</div><!-- end of lg-row -->"
|
|
388
|
-
@lg_row_open = false
|
|
389
|
-
end
|
|
390
|
-
|
|
391
|
-
c = 'lb'
|
|
392
|
-
c += ' honorific' if e['type'] == 'honorific'
|
|
393
|
-
r += "<span \nclass='#{c}' id='#{line_head}'>#{line_head}</span>"
|
|
394
|
-
|
|
395
|
-
unless @next_line_buf.empty?
|
|
396
|
-
r += @next_line_buf
|
|
397
|
-
@next_line_buf = ''
|
|
398
|
-
end
|
|
399
|
-
r
|
|
400
|
-
end
|
|
401
|
-
|
|
402
|
-
def e_lem(e)
|
|
403
|
-
r = ''
|
|
404
|
-
content = traverse(e)
|
|
405
|
-
wit = e['wit']
|
|
406
|
-
if wit.include? 'CBETA' and not wit.include? @orig
|
|
407
|
-
n = @notes_dila[@juan].size + 1
|
|
408
|
-
r = "<a class='noteAnchor dila' href='#dila_note#{n}'></a>"
|
|
409
|
-
r += "<span class='cbeta'>%s</span>" % content
|
|
410
|
-
r = "<r w='#{wit}' l='#{@lb}'>#{r}</r>"
|
|
411
|
-
|
|
412
|
-
note = lem_note_cf(e)
|
|
413
|
-
note += lem_note_rdg(e)
|
|
414
|
-
@notes_dila[@juan] << "<span class='footnote dila' id='dila_note#{n}'>#{note}</span>"
|
|
415
|
-
end
|
|
416
|
-
|
|
417
|
-
# 沒有 rdg 的版本,用字同 lem
|
|
418
|
-
editions = Set.new @editions
|
|
419
|
-
e.xpath('./following-sibling::rdg').each do |rdg|
|
|
420
|
-
rdg['wit'].scan(/【.*?】/).each do |w|
|
|
421
|
-
editions.delete w
|
|
422
|
-
end
|
|
423
|
-
end
|
|
424
|
-
|
|
425
|
-
editions.delete('【CBETA】') unless r.empty?
|
|
426
|
-
w = editions.to_a.join(' ')
|
|
427
|
-
r + ("<r w='#{w}' l='#{@lb}'>%s</r>" % content)
|
|
428
|
-
end
|
|
429
|
-
|
|
430
|
-
def e_lg(e)
|
|
431
|
-
r = ''
|
|
432
|
-
@lg_type = e['type']
|
|
433
|
-
if @lg_type == 'abnormal'
|
|
434
|
-
r = "<p class='lg-abnormal'>" + traverse(e) + "</p>"
|
|
435
|
-
else
|
|
436
|
-
@first_l = true
|
|
437
|
-
doc = Nokogiri::XML::Document.new
|
|
438
|
-
node = doc.create_element('div')
|
|
439
|
-
node['class'] = 'lg'
|
|
440
|
-
if e.has_attribute?('rend')
|
|
441
|
-
rend = e['rend'].gsub(/text-indent:[^:]*/, '')
|
|
442
|
-
node['style'] = rend
|
|
443
|
-
end
|
|
444
|
-
@lg_row_open = false
|
|
445
|
-
node.inner_html = traverse(e)
|
|
446
|
-
if @lg_row_open
|
|
447
|
-
node.inner_html += '</div><!-- end of lg -->'
|
|
448
|
-
@lg_row_open = false
|
|
449
|
-
end
|
|
450
|
-
r = "\n" + to_html(node)
|
|
451
|
-
end
|
|
452
|
-
r
|
|
453
|
-
end
|
|
454
|
-
|
|
455
|
-
def e_list(e)
|
|
456
|
-
"<ul>%s</ul>" % traverse(e)
|
|
457
|
-
end
|
|
458
|
-
|
|
459
|
-
def e_milestone(e)
|
|
460
|
-
r = ''
|
|
461
|
-
if e['unit'] == 'juan'
|
|
462
|
-
|
|
463
|
-
r += "</div>" * @open_divs.size # 如果有 div 跨卷,要先結束, ex: T55n2154, p. 680a29, 跨 19, 20 兩卷
|
|
464
|
-
@juan = e['n'].to_i
|
|
465
|
-
@back[@juan] = @back[0]
|
|
466
|
-
@back_orig[@juan] = @back_orig[0]
|
|
467
|
-
@notes_mod[@juan] = {}
|
|
468
|
-
@notes_orig[@juan] = {}
|
|
469
|
-
@notes_dila[@juan] = []
|
|
470
|
-
r += "<juan #{@juan}>"
|
|
471
|
-
@open_divs.each { |d|
|
|
472
|
-
r += "<div class='div-#{d['type']}'>"
|
|
473
|
-
}
|
|
474
|
-
end
|
|
475
|
-
r
|
|
476
|
-
end
|
|
477
|
-
|
|
478
|
-
def e_mulu(e)
|
|
479
|
-
r = ''
|
|
480
|
-
if e['type'] == '品'
|
|
481
|
-
@pass << false
|
|
482
|
-
r = "<mulu class='pin' s='%s'/>" % traverse(e, 'txt')
|
|
483
|
-
@pass.pop
|
|
484
|
-
end
|
|
485
|
-
r
|
|
486
|
-
end
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
def e_note(e)
|
|
490
|
-
n = e['n']
|
|
491
|
-
if e.has_attribute?('type')
|
|
492
|
-
t = e['type']
|
|
493
|
-
case t
|
|
494
|
-
when 'equivalent'
|
|
495
|
-
return ''
|
|
496
|
-
when 'orig'
|
|
497
|
-
return handle_note_orig(e)
|
|
498
|
-
when 'orig_biao'
|
|
499
|
-
return handle_note_orig(e, 'biao')
|
|
500
|
-
when 'orig_ke'
|
|
501
|
-
return handle_note_orig(e, 'ke')
|
|
502
|
-
when 'mod'
|
|
503
|
-
@pass << false
|
|
504
|
-
s = traverse(e)
|
|
505
|
-
@pass.pop
|
|
506
|
-
#@back[@juan] = "<span class='footnote_cb' id='n#{n}'>#{s}</span>\n"
|
|
507
|
-
@notes_mod[@juan][n] = s
|
|
508
|
-
return "<r w='【CBETA】'><a class='noteAnchor cb' href='#n#{n}'></a></r>"
|
|
509
|
-
when 'rest'
|
|
510
|
-
return ''
|
|
511
|
-
else
|
|
512
|
-
return '' if t.start_with?('cf')
|
|
513
|
-
end
|
|
514
|
-
end
|
|
515
|
-
|
|
516
|
-
if e.has_attribute?('resp')
|
|
517
|
-
return '' if e['resp'].start_with? 'CBETA'
|
|
518
|
-
end
|
|
519
|
-
|
|
520
|
-
if e.has_attribute?('place')
|
|
521
|
-
r = traverse(e)
|
|
522
|
-
|
|
523
|
-
c = case e['place']
|
|
524
|
-
when 'interlinear' then 'interlinear-note'
|
|
525
|
-
when 'inline' then 'doube-line-note'
|
|
526
|
-
end
|
|
527
|
-
|
|
528
|
-
return "<span class='#{c}'>#{r}</span>"
|
|
529
|
-
else
|
|
530
|
-
return traverse(e)
|
|
531
|
-
end
|
|
532
|
-
end
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
def e_p(e)
|
|
536
|
-
if e.key? 'type'
|
|
537
|
-
r = "<p class='%s'>" % e['type']
|
|
538
|
-
else
|
|
539
|
-
r = '<p>'
|
|
540
|
-
end
|
|
541
|
-
r += line_info
|
|
542
|
-
r += traverse(e)
|
|
543
|
-
r + '</p>'
|
|
544
|
-
end
|
|
545
|
-
|
|
546
|
-
def e_rdg(e)
|
|
547
|
-
r = traverse(e)
|
|
548
|
-
"<r w='#{e['wit']}' l='#{@lb}' w='#{@char_count}'>#{r}</r>"
|
|
549
|
-
end
|
|
550
|
-
|
|
551
|
-
def e_row(e)
|
|
552
|
-
"<div class='bip-table-row'>" + traverse(e) + "</div>"
|
|
553
|
-
end
|
|
554
|
-
|
|
555
|
-
def e_sg(e)
|
|
556
|
-
'(' + traverse(e) + ')'
|
|
557
|
-
end
|
|
558
|
-
|
|
559
|
-
def e_sic(e)
|
|
560
|
-
"<r w='#{@orig}' l='#{@lb}'>" + traverse(e) + "</r>"
|
|
561
|
-
end
|
|
562
|
-
|
|
563
|
-
def e_t(e)
|
|
564
|
-
if e.has_attribute? 'place'
|
|
565
|
-
return '' if e['place'].include? 'foot'
|
|
566
|
-
end
|
|
567
|
-
r = traverse(e)
|
|
568
|
-
|
|
569
|
-
# <tt type="app"> 不是 悉漢雙行對照
|
|
570
|
-
return r if @tt_type == 'app'
|
|
571
|
-
|
|
572
|
-
# 處理雙行對照
|
|
573
|
-
i = e.xpath('../t').index(e)
|
|
574
|
-
case i
|
|
575
|
-
when 0
|
|
576
|
-
return r + ' '
|
|
577
|
-
when 1
|
|
578
|
-
@next_line_buf += r + ' '
|
|
579
|
-
return ''
|
|
580
|
-
else
|
|
581
|
-
return r
|
|
582
|
-
end
|
|
583
|
-
end
|
|
584
|
-
|
|
585
|
-
def e_tt(e)
|
|
586
|
-
@tt_type = e['type']
|
|
587
|
-
traverse(e)
|
|
588
|
-
end
|
|
589
|
-
|
|
590
|
-
def e_table(e)
|
|
591
|
-
"<div class='bip-table'>" + traverse(e) + "</div>"
|
|
592
|
-
end
|
|
593
|
-
|
|
594
|
-
def e_unclear(e)
|
|
595
|
-
'▆'
|
|
596
|
-
end
|
|
597
|
-
|
|
598
|
-
def filter_html(html, ed)
|
|
599
|
-
frag = Nokogiri::HTML.fragment(html)
|
|
600
|
-
frag.search("r").each do |node|
|
|
601
|
-
if node['w'].include? ed
|
|
602
|
-
html_only_this_edition = filter_html(node.inner_html, ed)
|
|
603
|
-
node.add_previous_sibling html_only_this_edition
|
|
604
|
-
end
|
|
605
|
-
node.remove
|
|
606
|
-
end
|
|
607
|
-
frag.to_html
|
|
608
|
-
end
|
|
609
|
-
|
|
610
|
-
def get_editions(doc)
|
|
611
|
-
r = Set.new [@orig, "【CBETA】"] # 至少有底本及 CBETA 兩個版本
|
|
612
|
-
doc.xpath('//lem|//rdg').each do |e|
|
|
613
|
-
w = e['wit'].scan(/【.*?】/)
|
|
614
|
-
r.merge w
|
|
615
|
-
end
|
|
616
|
-
r
|
|
617
|
-
end
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
def handle_node(e, mode)
|
|
621
|
-
return '' if e.comment?
|
|
622
|
-
return handle_text(e, mode) if e.text?
|
|
623
|
-
return '' if PASS.include?(e.name)
|
|
624
|
-
r = case e.name
|
|
625
|
-
when 'anchor' then e_anchor(e)
|
|
626
|
-
when 'app' then e_app(e)
|
|
627
|
-
when 'byline' then e_byline(e)
|
|
628
|
-
when 'cell' then e_cell(e)
|
|
629
|
-
when 'corr' then e_corr(e)
|
|
630
|
-
when 'div' then e_div(e)
|
|
631
|
-
when 'figure' then e_figure(e)
|
|
632
|
-
when 'foreign' then e_foreign(e)
|
|
633
|
-
when 'g' then e_g(e, mode)
|
|
634
|
-
when 'graphic' then e_graphic(e)
|
|
635
|
-
when 'head' then e_head(e)
|
|
636
|
-
when 'item' then e_item(e)
|
|
637
|
-
when 'juan' then e_juan(e)
|
|
638
|
-
when 'l' then e_l(e)
|
|
639
|
-
when 'lb' then e_lb(e)
|
|
640
|
-
when 'lem' then e_lem(e)
|
|
641
|
-
when 'lg' then e_lg(e)
|
|
642
|
-
when 'list' then e_list(e)
|
|
643
|
-
when 'mulu' then e_mulu(e)
|
|
644
|
-
when 'note' then e_note(e)
|
|
645
|
-
when 'milestone' then e_milestone(e)
|
|
646
|
-
when 'p' then e_p(e)
|
|
647
|
-
when 'rdg' then e_rdg(e)
|
|
648
|
-
when 'reg' then ''
|
|
649
|
-
when 'row' then e_row(e)
|
|
650
|
-
when 'sic' then e_sic(e)
|
|
651
|
-
when 'sg' then e_sg(e)
|
|
652
|
-
when 't' then e_t(e)
|
|
653
|
-
when 'tt' then e_tt(e)
|
|
654
|
-
when 'table' then e_table(e)
|
|
655
|
-
when 'unclear' then e_unclear(e)
|
|
656
|
-
else traverse(e)
|
|
657
|
-
end
|
|
658
|
-
r
|
|
659
|
-
end
|
|
660
|
-
|
|
661
|
-
def handle_note_orig(e, anchor_type=nil)
|
|
662
|
-
n = e['n']
|
|
663
|
-
@pass << false
|
|
664
|
-
s = traverse(e)
|
|
665
|
-
@pass.pop
|
|
666
|
-
@notes_orig[@juan][n] = s
|
|
667
|
-
@notes_mod[@juan][n] = s
|
|
668
|
-
|
|
669
|
-
c = @series
|
|
670
|
-
|
|
671
|
-
# 如果 CBETA 沒有修訂,就跟底本的註一樣
|
|
672
|
-
# 但是 CBETA 修訂後的編號,有時會加上 a, b
|
|
673
|
-
# T01n0026, p. 506b07, 大正藏校勘 0506007, CBETA 拆為 0506007a, 0506007b
|
|
674
|
-
c += " cb" unless @mod_notes.include?(n) or @mod_notes.include?(n+'a')
|
|
675
|
-
|
|
676
|
-
label = case anchor_type
|
|
677
|
-
when 'biao' then " data-label='標#{n[-2..-1]}'"
|
|
678
|
-
when 'ke' then " data-label='科#{n[-2..-1]}'"
|
|
679
|
-
else ''
|
|
680
|
-
end
|
|
681
|
-
s = "<a class='noteAnchor #{c}' href='#n#{n}'#{label}></a>"
|
|
682
|
-
r = "<r w='#{@orig}'>#{s}</r>"
|
|
683
|
-
|
|
684
|
-
unless @mod_notes.include?(n)
|
|
685
|
-
r += "<r w='【CBETA】'>#{s}</r>"
|
|
686
|
-
end
|
|
687
|
-
r
|
|
688
|
-
end
|
|
689
|
-
|
|
690
|
-
def handle_text(e, mode)
|
|
691
|
-
s = e.content().chomp
|
|
692
|
-
return '' if s.empty?
|
|
693
|
-
return '' if e.parent.name == 'app'
|
|
694
|
-
|
|
695
|
-
# cbeta xml 文字之間會有多餘的換行
|
|
696
|
-
r = s.gsub(/[\n\r]/, '')
|
|
697
|
-
|
|
698
|
-
text_size = r.size
|
|
699
|
-
|
|
700
|
-
# 把 & 轉為 &
|
|
701
|
-
r = CGI.escapeHTML(r)
|
|
702
|
-
|
|
703
|
-
# 正文區的文字外面要包 span
|
|
704
|
-
if @pass.last and mode=='html'
|
|
705
|
-
doc = Nokogiri::XML::Document.new
|
|
706
|
-
node = doc.create_element('span')
|
|
707
|
-
node['class'] = 't'
|
|
708
|
-
node['l'] = @lb
|
|
709
|
-
node['lr'] = @lb_r if @series=='X'
|
|
710
|
-
node['w'] = @char_count
|
|
711
|
-
node.inner_html = r
|
|
712
|
-
r = to_html(node)
|
|
713
|
-
@char_count += text_size
|
|
714
|
-
end
|
|
715
|
-
r
|
|
716
|
-
end
|
|
717
|
-
|
|
718
|
-
def html_back(juan_no, ed)
|
|
719
|
-
r = ''
|
|
720
|
-
case ed
|
|
721
|
-
when '【CBETA】'
|
|
722
|
-
r = @back[juan_no]
|
|
723
|
-
@notes_mod[juan_no].each_pair do |k,v|
|
|
724
|
-
r += "<span class='footnote cb' id='n#{k}'>#{v}</span>\n"
|
|
725
|
-
end
|
|
726
|
-
r += @notes_dila[juan_no].join("\n")
|
|
727
|
-
when @orig
|
|
728
|
-
r = @back_orig[juan_no]
|
|
729
|
-
@notes_orig[juan_no].each_pair do |k,v|
|
|
730
|
-
r += "<span class='footnote #{@series}' id='n#{k}'>#{v}</span>\n"
|
|
731
|
-
end
|
|
732
|
-
end
|
|
733
|
-
r
|
|
734
|
-
end
|
|
735
|
-
|
|
736
|
-
def html_copyright(work, juan)
|
|
737
|
-
r = "<div id='cbeta-copyright'><p>\n"
|
|
738
|
-
|
|
739
|
-
orig = @cbeta.get_canon_nickname(@series)
|
|
740
|
-
|
|
741
|
-
# 處理 卷跨冊
|
|
742
|
-
if work=='L1557'
|
|
743
|
-
@title = '大方廣佛華嚴經疏鈔會本'
|
|
744
|
-
if @vol=='L131' and juan==17
|
|
745
|
-
v = '130-131'
|
|
746
|
-
elsif @vol=='L132' and juan==34
|
|
747
|
-
v = '131-132'
|
|
748
|
-
elsif @vol=='L133' and juan==51
|
|
749
|
-
v = '132-133'
|
|
750
|
-
end
|
|
751
|
-
elsif work=='X0714' and @vol=='X40' and juan==3
|
|
752
|
-
@title = '四分律含注戒本疏行宗記'
|
|
753
|
-
v = '39-40'
|
|
754
|
-
else
|
|
755
|
-
v = @vol.sub(/^[A-Z]0*([^0].*)$/, '\1')
|
|
756
|
-
end
|
|
757
|
-
|
|
758
|
-
n = @sutra_no.sub(/^[A-Z]\d{2,3}n0*([^0].*)$/, '\1')
|
|
759
|
-
r += "【經文資訊】#{orig}第 #{v} 冊 No. #{n} #{@title}<br/>\n"
|
|
760
|
-
r += "【版本記錄】CBETA 電子佛典 版本日期:#{@edition_date}<br/>\n"
|
|
761
|
-
r += "【編輯說明】本資料庫由中華電子佛典協會(CBETA)依#{orig}所編輯<br/>\n"
|
|
762
|
-
|
|
763
|
-
r += "【原始資料】#{@contributors}<br/>\n"
|
|
764
|
-
r += "【其他事項】本資料庫可自由免費流通,詳細內容請參閱【中華電子佛典協會資料庫版權宣告】\n"
|
|
765
|
-
r += "</p></div><!-- end of cbeta-copyright -->\n"
|
|
766
|
-
end
|
|
767
|
-
|
|
768
|
-
def lem_note_cf(e)
|
|
769
|
-
# ex: T32n1670A.xml, p. 703a16
|
|
770
|
-
# <note type="cf1">K30n1002_p0257a01-a23</note>
|
|
771
|
-
refs = []
|
|
772
|
-
e.xpath('./note').each { |n|
|
|
773
|
-
if n.key?('type') and n['type'].start_with? 'cf'
|
|
774
|
-
s = n.content
|
|
775
|
-
if linehead_exist_in_cbeta(s)
|
|
776
|
-
s = "<span class='note_cf'>#{s}</span>"
|
|
777
|
-
end
|
|
778
|
-
refs << s
|
|
779
|
-
end
|
|
780
|
-
}
|
|
781
|
-
if refs.empty?
|
|
782
|
-
''
|
|
783
|
-
else
|
|
784
|
-
'修訂依據:' + refs.join(';') + '。'
|
|
785
|
-
end
|
|
786
|
-
end
|
|
787
|
-
|
|
788
|
-
def lem_note_rdg(lem)
|
|
789
|
-
r = ''
|
|
790
|
-
app = lem.parent
|
|
791
|
-
@pass << false
|
|
792
|
-
app.xpath('rdg').each { |rdg|
|
|
793
|
-
if rdg['wit'].include? @orig
|
|
794
|
-
s = traverse(rdg, 'back')
|
|
795
|
-
s = MISSING if s.empty?
|
|
796
|
-
r += @orig + s
|
|
797
|
-
end
|
|
798
|
-
}
|
|
799
|
-
@pass.pop
|
|
800
|
-
r += '。' unless r.empty?
|
|
801
|
-
r
|
|
802
|
-
end
|
|
803
|
-
|
|
804
|
-
def line_info
|
|
805
|
-
"<span class='lineInfo' line='#{@lb}'></span>"
|
|
806
|
-
end
|
|
807
|
-
|
|
808
|
-
def linehead_exist_in_cbeta(s)
|
|
809
|
-
fn = CBETA.linehead_to_xml_file_path(s)
|
|
810
|
-
return false if fn.nil?
|
|
811
|
-
|
|
812
|
-
path = File.join(@xml_root, fn)
|
|
813
|
-
File.exist? path
|
|
814
|
-
end
|
|
815
|
-
|
|
816
|
-
def open_xml(fn)
|
|
817
|
-
s = File.read(fn)
|
|
818
|
-
|
|
819
|
-
if fn.include? 'T16n0657'
|
|
820
|
-
# 這個地方 雙行夾註 跨兩行偈頌
|
|
821
|
-
# 把 lb 移到 note 結束之前
|
|
822
|
-
# 讓 lg-row 先結束,再結束雙行夾註
|
|
823
|
-
s.sub!(/(<\/note>)(\n<lb n="0206b29" ed="T"\/>)/, '\2\1')
|
|
824
|
-
end
|
|
825
|
-
|
|
826
|
-
# <milestone unit="juan"> 前面的 lb 屬於新的這一卷
|
|
827
|
-
s.gsub!(%r{((?:<pb [^>]+>\n?)?(?:<lb [^>]+>\n?)+)(<milestone [^>]*unit="juan"[^/>]*/>)}, '\2\1')
|
|
828
|
-
|
|
829
|
-
doc = Nokogiri::XML(s)
|
|
830
|
-
doc.remove_namespaces!()
|
|
831
|
-
doc
|
|
832
|
-
end
|
|
833
|
-
|
|
834
|
-
def read_mod_notes(doc)
|
|
835
|
-
doc.xpath("//note[@type='mod']").each { |e|
|
|
836
|
-
@mod_notes << e['n']
|
|
837
|
-
}
|
|
838
|
-
end
|
|
839
|
-
|
|
840
|
-
def parse_xml(xml_fn)
|
|
841
|
-
@pass = [false]
|
|
842
|
-
|
|
843
|
-
doc = open_xml(xml_fn)
|
|
844
|
-
|
|
845
|
-
e = doc.xpath("//titleStmt/title")[0]
|
|
846
|
-
@title = traverse(e, 'txt')
|
|
847
|
-
@title = @title.split()[-1]
|
|
848
|
-
|
|
849
|
-
e = doc.at_xpath("//editionStmt/edition/date")
|
|
850
|
-
abort "找不到版本日期" if e.nil?
|
|
851
|
-
@edition_date = e.text.sub(/\$Date: (.*?) \$$/, '\1')
|
|
852
|
-
|
|
853
|
-
e = doc.at_xpath("//projectDesc/p[@lang='zh']")
|
|
854
|
-
abort "找不到貢獻者" if e.nil?
|
|
855
|
-
@contributors = e.text
|
|
856
|
-
|
|
857
|
-
read_mod_notes(doc)
|
|
858
|
-
|
|
859
|
-
root = doc.root()
|
|
860
|
-
body = root.xpath("text/body")[0]
|
|
861
|
-
@pass = [true]
|
|
862
|
-
|
|
863
|
-
@editions = get_editions(doc)
|
|
864
|
-
|
|
865
|
-
text = traverse(body)
|
|
866
|
-
text
|
|
867
|
-
end
|
|
868
|
-
|
|
869
|
-
def traverse(e, mode='html')
|
|
870
|
-
r = ''
|
|
871
|
-
e.children.each { |c|
|
|
872
|
-
s = handle_node(c, mode)
|
|
873
|
-
r += s
|
|
874
|
-
}
|
|
875
|
-
r
|
|
876
|
-
end
|
|
877
|
-
|
|
878
|
-
def write_juan(juan_no, html)
|
|
879
|
-
if @sutra_no.match(/^(T05|T06|T07)n0220/)
|
|
880
|
-
work = "T0220"
|
|
881
|
-
else
|
|
882
|
-
work = @sutra_no.sub(/^([A-Z]{1,2})\d{2,3}n(.*)$/, '\1\2')
|
|
883
|
-
end
|
|
884
|
-
juan = "%03d" % juan_no
|
|
885
|
-
folder = File.join(@out_folder, work, juan)
|
|
886
|
-
FileUtils.remove_dir(folder, true)
|
|
887
|
-
FileUtils.makedirs folder
|
|
888
|
-
|
|
889
|
-
@editions.each do |ed|
|
|
890
|
-
ed_html = filter_html(html, ed)
|
|
891
|
-
back = html_back(juan_no, ed)
|
|
892
|
-
|
|
893
|
-
# 如果是卷跨冊的上半部
|
|
894
|
-
if (work=='L1557' and @vol=='L130' and juan_no==17) or
|
|
895
|
-
(work=='L1557' and @vol=='L131' and juan_no==34) or
|
|
896
|
-
(work=='L1557' and @vol=='L132' and juan_no==51) or
|
|
897
|
-
(work=='X0714' and @vol=='X39' and juan_no==3)
|
|
898
|
-
@html_buf[ed] = ed_html
|
|
899
|
-
@back_buf[ed] = back
|
|
900
|
-
next
|
|
901
|
-
else
|
|
902
|
-
body = ed_html
|
|
903
|
-
unless @html_buf.empty?
|
|
904
|
-
body = @html_buf[ed] + body
|
|
905
|
-
@html_buf.delete ed
|
|
906
|
-
end
|
|
907
|
-
back = @back_buf[ed] + back unless @back_buf.empty?
|
|
908
|
-
copyright = html_copyright(work, juan_no)
|
|
909
|
-
write_juan_ed(folder, ed, body, back, copyright)
|
|
910
|
-
|
|
911
|
-
@back_buf.delete ed
|
|
912
|
-
end
|
|
913
|
-
end
|
|
914
|
-
end
|
|
915
|
-
|
|
916
|
-
def write_juan_ed(folder, ed, body, back, copyright)
|
|
917
|
-
fn = ed.sub(/^【(.*)】$/, '\1')
|
|
918
|
-
if fn != 'CBETA' and fn != @orig_short
|
|
919
|
-
fn = @orig_short + '→' + fn
|
|
920
|
-
end
|
|
921
|
-
fn += '.htm'
|
|
922
|
-
output_path = File.join(folder, fn)
|
|
923
|
-
text = <<eos
|
|
924
|
-
<html>
|
|
925
|
-
<head>
|
|
926
|
-
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
927
|
-
<title>#{@title}</title>
|
|
928
|
-
</head>
|
|
929
|
-
<body>
|
|
930
|
-
<div id='body'>#{body}</div>
|
|
931
|
-
<div id='back'>
|
|
932
|
-
#{back}
|
|
933
|
-
</div>
|
|
934
|
-
#{copyright}
|
|
935
|
-
</body></html>
|
|
936
|
-
eos
|
|
937
|
-
File.write(output_path, text)
|
|
938
|
-
end
|
|
939
|
-
|
|
940
|
-
end
|