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.
@@ -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
- # 把 & 轉為 &amp;
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