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,426 +0,0 @@
1
- require 'cgi'
2
- require 'fileutils'
3
- require 'json'
4
- require 'nokogiri'
5
- require 'set'
6
- require_relative 'cbeta_share'
7
-
8
- # Convert CBETA XML P5a to simple HTML
9
- #
10
- # * HTML 中除了純文字之外,只有行號標記
11
- # * 每一卷、每個校勘版本都產生一個檔案
12
- #
13
- # CBETA XML P5a 可由此取得: https://github.com/cbeta-git/xml-p5a
14
- #
15
- # @example for convert 大正藏第一冊:
16
- #
17
- # c = CBETA::P5aToSimpleHTML.new('/PATH/TO/CBETA/XML/P5a', '/OUTPUT/FOLDER')
18
- # c.convert('T01')
19
- #
20
- class CBETA::P5aToSimpleHTML
21
- # 內容不輸出的元素
22
- PASS=['back', 'teiHeader']
23
-
24
- private_constant :PASS
25
-
26
- # @param xml_root [String] 來源 CBETA XML P5a 路徑
27
- # @param output_root [String] 輸出 Text 路徑
28
- def initialize(xml_root, output_root, gaiji_base, opts={})
29
- @xml_root = xml_root
30
- @output_root = output_root
31
- @cbeta = CBETA.new
32
- @gaijis = CBETA::Gaiji.new(gaiji_base)
33
- @config = { multi_edition: false }
34
- @config.merge!(opts)
35
- end
36
-
37
- # 將 CBETA XML P5a 轉為 Simple HTML
38
- #
39
- # @example for convert 大正藏第一冊:
40
- #
41
- # x2h = CBETA::P5aToText.new('/PATH/TO/CBETA/XML/P5a', '/OUTPUT/FOLDER')
42
- # x2h.convert('T01')
43
- #
44
- # @example for convert 大正藏全部:
45
- #
46
- # x2h = CBETA::P5aToText.new('/PATH/TO/CBETA/XML/P5a', '/OUTPUT/FOLDER')
47
- # x2h.convert('T')
48
- #
49
- # @example for convert 大正藏第五冊至第七冊:
50
- #
51
- # x2h = CBETA::P5aToText.new('/PATH/TO/CBETA/XML/P5a', '/OUTPUT/FOLDER')
52
- # x2h.convert('T05..T07')
53
- #
54
- # T 是大正藏的 ID, CBETA 的藏經 ID 系統請參考: http://www.cbeta.org/format/id.php
55
- def convert(target=nil)
56
- return convert_all if target.nil?
57
-
58
- arg = target.upcase
59
- if arg.size <= 2
60
- handle_collection(arg)
61
- else
62
- if arg.include? '..'
63
- arg.match(/^([^\.]+?)\.\.([^\.]+)$/) {
64
- handle_vols($1, $2)
65
- }
66
- else
67
- handle_vol(arg)
68
- end
69
- end
70
- end
71
-
72
- private
73
-
74
- include CbetaShare
75
-
76
- def convert_all
77
- Dir.entries(@xml_root).sort.each { |c|
78
- next if c.start_with? '.'
79
- next if c.size > 2
80
- handle_collection(c)
81
- }
82
- end
83
-
84
- def handle_anchor(e)
85
- if e.has_attribute?('type')
86
- if e['type'] == 'circle'
87
- return '◎'
88
- end
89
- end
90
-
91
- ''
92
- end
93
-
94
- def handle_collection(c)
95
- @series = c
96
- puts 'handle_collection ' + c
97
- folder = File.join(@xml_root, @series)
98
- Dir.entries(folder).sort.each { |vol|
99
- next if vol.start_with? '.'
100
- handle_vol(vol)
101
- }
102
- end
103
-
104
- def handle_corr(e)
105
- r = traverse(e)
106
- if @config[:multi_edition]
107
- r = "<r w='【CBETA】'>#{r}</r>"
108
- end
109
- r
110
- end
111
-
112
- def handle_foreign(e)
113
- return '' if e.key?('place') and e['place'].include?('foot')
114
- traverse(e)
115
- end
116
-
117
- def handle_g(e)
118
- # if 悉曇字、蘭札體
119
- # 使用 Unicode PUA
120
- # else if 有 <mapping type="unicode">
121
- # 直接採用
122
- # else if 有 <mapping type="normal_unicode">
123
- # 採用 normal_unicode
124
- # else if 有 normalized form
125
- # 採用 normalized form
126
- # else
127
- # Unicode PUA
128
- gid = e['ref'][1..-1]
129
- g = @gaijis[gid]
130
- abort "Line:#{__LINE__} 無缺字資料:#{gid}" if g.nil?
131
-
132
- # 悉曇字 or 蘭札體
133
- if gid.start_with?('SD') or gid.start_with? 'RJ'
134
- return g['symbol'] if g.key?('symbol')
135
- return g['romanized'] if g.key?('romanized')
136
- return g['pua']
137
- end
138
-
139
- return g['uni_char'] unless g['uni_char'].empty?
140
- return g['norm_uni_char'] unless g['norm_uni_char'].empty?
141
- return g['norm_big5_char'] unless g['norm_big5_char'].empty?
142
-
143
- # Unicode PUA
144
- [0xf0000 + gid[2..-1].to_i].pack 'U'
145
- end
146
-
147
- def handle_item(e)
148
- r = traverse(e)
149
- if e.key? 'n'
150
- r = e['n'] + r
151
- end
152
- r
153
- end
154
-
155
- def handle_lb(e)
156
- return '' if e['type']=='old'
157
- @lb = e['n']
158
- r = %(<a id="lb#{@lb}"></a>)
159
- unless @next_line_buf.empty?
160
- r += @next_line_buf + "\n"
161
- @next_line_buf = ''
162
- end
163
- r
164
- end
165
-
166
- def handle_lem(e)
167
- r = traverse(e)
168
- if @config[:multi_edition]
169
- w = e['wit'].scan(/【.*?】/)
170
- @editions.merge w
171
- w = w.join(' ')
172
- r = "<r w='#{w}'>#{r}</r>"
173
- end
174
- r
175
- end
176
-
177
- def handle_milestone(e)
178
- r = ''
179
- if e['unit'] == 'juan'
180
- @juan = e['n'].to_i
181
- r += "<juan #{@juan}>"
182
- r += %(<a id="lb#{@lb}"></a>) unless @lb.nil?
183
- end
184
- r
185
- end
186
-
187
- def handle_node(e)
188
- return '' if e.comment?
189
- return handle_text(e) if e.text?
190
- return '' if PASS.include?(e.name)
191
- r = case e.name
192
- when 'anchor' then handle_anchor(e)
193
- when 'back' then ''
194
- when 'corr' then handle_corr(e)
195
- when 'foreign' then handle_foreign(e)
196
- when 'g' then handle_g(e)
197
- when 'graphic' then ''
198
- when 'item' then handle_item(e)
199
- when 'lb' then handle_lb(e)
200
- when 'lem' then handle_lem(e)
201
- when 'mulu' then ''
202
- when 'note' then handle_note(e)
203
- when 'milestone' then handle_milestone(e)
204
- when 'rdg' then handle_rdg(e)
205
- when 'reg' then ''
206
- when 'sic' then handle_sic(e)
207
- when 'sg' then handle_sg(e)
208
- when 'tt' then handle_tt(e)
209
- when 't' then handle_t(e)
210
- when 'teiHeader' then ''
211
- when 'unclear' then '▆'
212
- else traverse(e)
213
- end
214
- r
215
- end
216
-
217
- def handle_note(e)
218
- if e.has_attribute?('place') && e['place']=='inline'
219
- r = traverse(e)
220
- return "(#{r})"
221
- end
222
- ''
223
- end
224
-
225
- def handle_rdg(e)
226
- return '' unless @config[:multi_edition]
227
-
228
- r = traverse(e)
229
- w = e['wit'].scan(/【.*?】/)
230
- @editions.merge w
231
- "<r w='#{e['wit']}'>#{r}</r>"
232
- end
233
-
234
- def handle_sg(e)
235
- '(' + traverse(e) + ')'
236
- end
237
-
238
- def handle_sic(e)
239
- return '' unless@config[:multi_edition]
240
-
241
- "<r w='#{@orig}'>" + traverse(e) + "</r>"
242
- end
243
-
244
- def handle_sutra(xml_fn)
245
- puts "convert sutra #{xml_fn}"
246
- @dila_note = 0
247
- @div_count = 0
248
- @editions = Set.new ["【CBETA】"]
249
- @in_l = false
250
- @juan = 0
251
- @lg_row_open = false
252
- @mod_notes = Set.new
253
- @next_line_buf = ''
254
- @open_divs = []
255
- @sutra_no = File.basename(xml_fn, ".xml")
256
- @lb = nil
257
-
258
- text = parse_xml(xml_fn)
259
-
260
- # 大正藏 No. 220 大般若經跨冊,CBETA 分成多檔並在檔尾加上 a, b, c....
261
- # 輸出時去掉這些檔尾的 a, b, b....
262
- if @sutra_no.match(/^(T05|T06|T07)n0220/)
263
- @sutra_no = "#{$1}n0220"
264
- end
265
-
266
- @out_sutra = File.join(@out_vol, @sutra_no)
267
- FileUtils.makedirs @out_sutra
268
-
269
- juans = text.split(/(<juan \d+>)/)
270
- juan_no = nil
271
- buf = ''
272
- # 一卷一檔
273
- juans.each { |j|
274
- if j =~ /<juan (\d+)>$/
275
- juan_no = $1.to_i
276
- else
277
- if juan_no.nil?
278
- buf = j
279
- else
280
- write_juan(juan_no, buf+j)
281
- buf = ''
282
- end
283
- end
284
- }
285
- end
286
-
287
- def handle_t(e)
288
- if e.has_attribute? 'place'
289
- return '' if e['place'].include? 'foot'
290
- end
291
- r = traverse(e)
292
-
293
- # 不是雙行對照
294
- return r if @tt_type == 'app'
295
-
296
- # 處理雙行對照
297
- i = e.xpath('../t').index(e)
298
- case i
299
- when 0
300
- return r + ' '
301
- when 1
302
- @next_line_buf += r + ' '
303
- return ''
304
- else
305
- return r
306
- end
307
- end
308
-
309
- def handle_text(e)
310
- s = e.content().chomp
311
- return '' if s.empty?
312
- return '' if e.parent.name == 'app'
313
-
314
- # cbeta xml 文字之間會有多餘的換行
315
- r = s.gsub(/[\n\r]/, '')
316
-
317
- # 把 & 轉為 &amp;
318
- CGI.escapeHTML(r)
319
- end
320
-
321
- def handle_tt(e)
322
- @tt_type = e['type']
323
- traverse(e)
324
- end
325
-
326
- def handle_vol(vol)
327
- puts "convert volumn: #{vol}"
328
-
329
-
330
- @vol = vol
331
- @series = CBETA.get_canon_from_vol(vol)
332
-
333
- @orig = @cbeta.get_canon_symbol(@series)
334
- abort "未處理底本" if @orig.nil?
335
- @orig_short = @orig.sub(/^【(.*)】$/, '\1')
336
-
337
- @out_vol = File.join(@output_root, @series, vol)
338
- FileUtils.remove_dir(@out_vol, true)
339
- FileUtils.makedirs @out_vol
340
-
341
- source = File.join(@xml_root, @series, vol)
342
- Dir[source+"/*"].each { |f|
343
- handle_sutra(f)
344
- }
345
- end
346
-
347
- def handle_vols(v1, v2)
348
- puts "convert volumns: #{v1}..#{v2}"
349
- @series = CBETA.get_canon_from_vol(v1)
350
- folder = File.join(@xml_root, @series)
351
- Dir.foreach(folder) { |vol|
352
- next if vol < v1
353
- next if vol > v2
354
- handle_vol(vol)
355
- }
356
- end
357
-
358
- def open_xml(fn)
359
- s = File.read(fn)
360
- doc = Nokogiri::XML(s)
361
- doc.remove_namespaces!()
362
- doc
363
- end
364
-
365
- def parse_xml(xml_fn)
366
- doc = open_xml(xml_fn)
367
- root = doc.root()
368
-
369
- body = root.xpath("text/body")[0]
370
- traverse(body)
371
- end
372
-
373
- def traverse(e)
374
- r = ''
375
- e.children.each { |c|
376
- s = handle_node(c)
377
- r += s
378
- }
379
- r
380
- end
381
-
382
- def write_juan(juan_no, txt)
383
- if @config[:multi_edition]
384
- write_juan_for_editions(juan_no, txt)
385
- else
386
- fn = File.join(@out_sutra, "%03d.html" % juan_no)
387
- write_juan_to_file(fn, txt)
388
- end
389
- end
390
-
391
- def write_juan_for_editions(juan_no, txt)
392
- folder = File.join(@out_sutra, "%03d" % juan_no)
393
- FileUtils.makedirs(folder)
394
- @editions.each do |ed|
395
- frag = Nokogiri::XML.fragment(txt)
396
- frag.search("r").each do |node|
397
- if node['w'] == ed
398
- node.add_previous_sibling(node.text)
399
- end
400
- node.remove
401
- end
402
- html = to_html(frag)
403
-
404
- fn = ed.sub(/^【(.*?)】$/, '\1')
405
- if fn != 'CBETA' and fn != @orig_short
406
- fn = @orig_short + '→' + fn
407
- end
408
- fn = "#{fn}.html"
409
- output_path = File.join(folder, fn)
410
- write_juan_to_file(output_path, html)
411
- end
412
- end
413
-
414
- def write_juan_to_file(fn, html)
415
- text = <<-END.gsub(/^\s+\|/, '')
416
- |<!DOCTYPE html>
417
- |<html>
418
- |<head>
419
- | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
420
- |</head>
421
- END
422
- text += "<body>#{html}</body></html>"
423
- File.write(fn, text)
424
- end
425
-
426
- end
@@ -1,144 +0,0 @@
1
- @font-face {
2
- font-family: extb;
3
- font-style: normal;
4
- font-weight: normal;
5
- src: url("/Library/Fonts/Microsoft/PMingLiU-ExtB.ttf")
6
- }
7
- @font-face {
8
- font-family: PMingLiU;
9
- font-style: normal;
10
- font-weight: normal;
11
- src: url("/Library/Fonts/Microsoft/PMingLiU.ttf")
12
- }
13
- a {
14
- text-decoration: none;
15
- }
16
- body {
17
- font-family: PMingLiU, extb;
18
- }
19
-
20
- div#cover {
21
- page-break-after: always
22
- }
23
-
24
- div.lg {
25
- display: table;
26
- margin-left: 1em;
27
- }
28
- div.lg-cell {
29
- display: table-cell;
30
- }
31
- div.lg-row {
32
- display: table-row;
33
- }
34
- div.p {
35
- margin-bottom: 1em;
36
- margin-top: 1em;
37
- line-height: 1.4;
38
- text-indent: 2em;
39
- }
40
- li div.p {
41
- text-indent: 0;
42
- }
43
- p.h1 {
44
- margin-left: 1em;
45
- font-size: 1.2em;
46
- font-weight: bold;
47
- }
48
- p.h2 {
49
- margin-left: 2em;
50
- font-size: 1.2em;
51
- font-weight: bold;
52
- }
53
- p.h3 {
54
- margin-left: 3em;
55
- font-size: 1.2em;
56
- font-weight: bold;
57
- }
58
- p.h4 {
59
- margin-left: 2em;
60
- font-size: 1.2em;
61
- font-weight: bold;
62
- }
63
- p.h5 {
64
- margin-left: 3em;
65
- font-size: 1.2em;
66
- font-weight: bold;
67
- }
68
- p.h6 {
69
- margin-left: 4em;
70
- font-size: 1.2em;
71
- font-weight: bold;
72
- }
73
-
74
- /*
75
- mulu 標記是用來產生 pdf bookmark 用的
76
- 參考: http://www.princexml.com/doc/pdf-bookmarks/
77
- */
78
- mulu1 {
79
- prince-bookmark-level: 1;
80
- prince-bookmark-label: attr(title)
81
- }
82
- mulu2 {
83
- prince-bookmark-level: 2;
84
- prince-bookmark-label: attr(title)
85
- }
86
- mulu3 {
87
- prince-bookmark-level: 3;
88
- prince-bookmark-label: attr(title)
89
- }
90
- mulu4 {
91
- prince-bookmark-level: 4;
92
- prince-bookmark-label: attr(title)
93
- }
94
- mulu5 {
95
- prince-bookmark-level: 5;
96
- prince-bookmark-label: attr(title)
97
- }
98
- mulu6 {
99
- prince-bookmark-level: 6;
100
- prince-bookmark-label: attr(title)
101
- }
102
- p.author {
103
- font-size: 1.6em;
104
- text-align: center;
105
- }
106
- p.byline {
107
- text-align: right;
108
- }
109
- p.h7 {
110
- text-indent: 2em;
111
- font-weight: bold;
112
- }
113
- p.h8 {
114
- text-indent: 2em;
115
- font-weight: bold;
116
- }
117
- p.title {
118
- font-size: 2em;
119
- text-align: center;
120
- }
121
- span.corr {
122
- color: red;
123
- }
124
- span.extb {
125
- font-family: extb;
126
- }
127
- table {
128
- border-collapse: collapse;
129
- }
130
- table.tt, table.tt tbody, table.tt tbody tr, table.tt tbody tr td {
131
- border: none;
132
- }
133
- th, td {
134
- border: solid;
135
- border-width: 1px;
136
- padding: 5px;
137
- word-wrap: break-word;
138
- word-break: break-all;
139
- text-indent: 0;
140
- }
141
-
142
- ul.simple {
143
- list-style-type: none;
144
- }
@@ -1,14 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5
- <link rel=stylesheet type='text/css' href='html-for-pdf.css'>
6
- </head>
7
- <body>
8
- %{cover}
9
- %{toc}
10
- %{front}
11
- %{text}
12
- %{back}
13
- </body>
14
- </html>