2021/FEB/23
更新履歴
日付
変更内容 2018秋
新規作成 2018/SEP/17
漢字
入力データのHTML自動判定
HTMLからYAMLへの変換2018/SEP/18
preタグのyamlダンプ
liタグの改行の辺りを
fileコマンドの判定の甘さ対策
大きいデータの標準入力への書き込み対応2018/SEP/20
preタグの中のタグの改行対応
タグ中のタグの中身はstirp()かけない対応
コメント対応2020/FEB/01
kon_ut対応 2021/FEB/23
bare対応
自分のページのHTMLは、簡素で限られたHTMLタグしか使われてません。
なぜか?
HTMLを手打ちしてるからです。
別に凝ったことはしないので「まぁこれでいいか」と。
にしても、HTMLのタグのタイプにボチボチ疲れてきました。
後でちょっと手を加えたいときなど、今どこにいるのか、ちょいちょい迷子になることしばしば。
どうせ自分で使う分には、限られたパターンしか使ってないし、 HTML形式を簡単にYAML形式に変換できないものか?
HTMLからYAMLに変換して、編集して、またYAMLからHTMLに戻せれないものか?
という事でpythonでツールを作ってみます。
HTMLのタグと文字列をYAML形式でどう表現すべしか?
私の中では「YAML形式」イコール「pythonの辞書とリストと文字列」
pythonのオブジェクトとしてどう保持したら良いか?
辞書は便利そうですが順番が保証されません。 かと言ってリストだけでは、ネスとが深くなると訳が分からなくなりそうです。
方針
これくらいで行けそうかな?
「/」という一文字の文字列を特別な値として使うので、 例えば <p>/</p> を読み込んだとすると、 終了タグがない <p>/ の扱いになりますね。
まぁ自分でそんなパターンを使う事は滅多にないだろうし、 後でもし困ったら何とかすれば良いでしょ。
例えば
ck1.html
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>foo</h1>
<p>bar hoge</p>
<pre>
fuga
guha
</pre>
<p><hr></p>
</body>
</html>
の場合のYAML形式は
ck1.yaml
- html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |
fuga
guha
- p:
hr: /
てな具合に。
このYAML形式への「慣れ」が必要ですが、かなりスッキリした感じに見えます。
まずは、こちら方向の変換から。
これは、チョー簡単です。
ezhtml.py
#!/usr/bin/env python
import sys
import yaml
import six
def cv_amp(s, d='enc'):
lst = [ ('&','&'), ('<','<'), ('>','>') ]
if d != 'enc':
lst = reversed(lst)
for (f, t) in lst:
if d != 'enc':
(f, t) = (t, f)
s = s.replace(f, t)
return s
def html_dump(o):
if not o:
return ''
if type(o) == list:
return '\n'.join( map(html_dump, o) )
if type(o) == dict:
(tag, v) = list( o.items() )[0]
s = '<' + tag + '>'
if v != '/':
s += html_dump(v) + '</' + tag.split(' ')[0] + '>'
return s
return cv_amp(o)
if __name__ == "__main__":
fi = sys.stdin if six.PY2 else sys.stdin.buffer
s = fi.read()
s = unicode(s, 'utf-8') if six.PY2 else s.decode()
o = yaml.load(s)
s = html_dump(o) + '\n'
s = s.encode('utf-8') if six.PY2 else s.encode()
fo = sys.stdout if six.PY2 else sys.stdout.buffer
fo.write(s)
# EOF
python2, python3 でも動くようにとした箇所がちょっと煩雑ですが、 核心部分はシンプルです。
$ cat ck1.yaml | ./ezhtml.py <html><head><title>Title</title></head> <body><h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p><hr></p></body></html> $ cat ck1.html <html> <head> <title>Title</title> </head> <body> <h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p><hr></p> </body> </html>
改行の違いはしょうがないのでOK。
漢字が扱えるように対応しておきます。
nkfのお力を借ります。
pythonでとりあえずutf-8で読み込んで、内部はunicodeで処理します。
python2 と python3 で、その辺りの文字列の取り扱いの変更がややこしそうですが...
nkf.py を作ってみたので、ここで吸収させる事にします。
v2.patch
diff -urN v1/ezhtml.py v2/ezhtml.py
--- v1/ezhtml.py 2018-09-16 16:32:39.000000000 +0900
+++ v2/ezhtml.py 2018-09-17 00:15:20.000000000 +0900
@@ -3,6 +3,7 @@
import sys
import yaml
import six
+import nkf
def cv_amp(s, d='enc'):
lst = [ ('&','&'), ('<','<'), ('>','>') ]
@@ -28,15 +29,16 @@
return cv_amp(o)
if __name__ == "__main__":
- fi = sys.stdin if six.PY2 else sys.stdin.buffer
- s = fi.read()
- s = unicode(s, 'utf-8') if six.PY2 else s.decode()
+ b = nkf.get_stdin()
+ opt = nkf.guess(b)
+ u8 = nkf.cvt(b, '-u')
+ s = nkf.dec(u8)
o = yaml.load(s)
s = html_dump(o) + '\n'
- s = s.encode('utf-8') if six.PY2 else s.encode()
- fo = sys.stdout if six.PY2 else sys.stdout.buffer
- fo.write(s)
+ u8 = nkf.enc(s)
+ b = nkf.cvt(u8, opt)
+ nkf.put_stdout(b)
# EOF
diff -urN v1/nkf.py v2/nkf.py
--- v1/nkf.py 1970-01-01 09:00:00.000000000 +0900
+++ v2/nkf.py 2018-09-17 00:15:20.000000000 +0900
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+import sys
+import six
+import subprocess
+
+PIPE = subprocess.PIPE
+
+enc = lambda s: s.encode('utf-8') if six.PY2 else s.encode()
+dec = lambda b: unicode(b, 'utf-8') if six.PY2 else b.decode()
+
+def do_cmd(cmd, in_b):
+ cmd = enc(cmd)
+ proc = subprocess.Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE)
+ proc.stdin.write(in_b)
+ proc.stdin.close()
+ r = proc.stdout.read()
+ proc.wait()
+ return r # out_b
+
+def get_stdin():
+ fi = sys.stdin if six.PY2 else sys.stdin.buffer
+ return fi.read() # b
+
+def put_stdout(b):
+ fo = sys.stdout if six.PY2 else sys.stdout.buffer
+ fo.write(b)
+
+def guess(b):
+ b = do_cmd('nkf -g', b)
+ return dec(b).strip()
+
+def cvt(b, opt):
+ if opt == 'ASCII':
+ return b
+ d = {
+ 'ISO-2022-JP': '-j',
+ 'EUC-JP': '-e',
+ 'Shift_JIS': '-s',
+ 'UTF-8': '-u',
+ }
+ if opt not in d.values():
+ opt = d.get(opt, '-u')
+ return do_cmd('nkf ' + opt, b)
+
+if __name__ == "__main__":
+ b = get_stdin()
+ opt = guess(b)
+ u8 = cvt(b, '-u')
+ s = dec(u8)
+ # ...
+ u8 = enc(s)
+ b = cvt(u8, opt)
+ put_stdout(b)
+# EOF
$ cat v2.patch | patch -p1 $ cat nkf.py #!/usr/bin/env python import sys import six import subprocess PIPE = subprocess.PIPE enc = lambda s: s.encode('utf-8') if six.PY2 else s.encode() dec = lambda b: unicode(b, 'utf-8') if six.PY2 else b.decode() def do_cmd(cmd, in_b): cmd = enc(cmd) proc = subprocess.Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE) proc.stdin.write(in_b) proc.stdin.close() r = proc.stdout.read() proc.wait() return r # out_b def get_stdin(): fi = sys.stdin if six.PY2 else sys.stdin.buffer return fi.read() # b def put_stdout(b): fo = sys.stdout if six.PY2 else sys.stdout.buffer fo.write(b) def guess(b): b = do_cmd('nkf -g', b) return dec(b).strip() def cvt(b, opt): if opt == 'ASCII': return b d = { 'ISO-2022-JP': '-j', 'EUC-JP': '-e', 'Shift_JIS': '-s', 'UTF-8': '-u', } if opt not in d.values(): opt = d.get(opt, '-u') return do_cmd('nkf ' + opt, b) if __name__ == "__main__": b = get_stdin() opt = guess(b) u8 = cvt(b, '-u') s = dec(u8) # ... u8 = enc(s) b = cvt(u8, opt) put_stdout(b) # EOF $
mainの箇所の例では
$ cat jis.yaml | nkf -g ISO-2022-JP $ cat jis.yaml | nkf -u - html: - head: title: タイトル - body: - h1: ふー - p: ばー ほげ - pre: | ふが ぐは - p: hr: / $ chmod +x nkf.py $ cat jis.yaml | ./nkf.py | nkf -g ISO-2022-JP $ cat jis.yaml | ./nkf.py | diff jis.yaml - $
JISコードからUTF-8, unicode を経て UTF-8, JISコードに戻って、一致。
同様にEUCの場合も
$ cat jis.yaml | nkf -e | tee euc.yaml | ./nkf.py | nkf -g EUC-JP $ cat euc.yaml | ./nkf.py | diff euc.yaml - $
その他
$ cat jis.yaml | nkf -s | tee sjis.yaml | ./nkf.py | nkf -g Shift_JIS $ cat sjis.yaml | ./nkf.py | diff sjis.yaml - $ $ cat jis.yaml | nkf -u | tee utf8.yaml | ./nkf.py | nkf -g UTF-8 $ cat utf8.yaml | ./nkf.py | diff utf8.yaml - $ $ cat ck1.yaml - html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: | fuga guha - p: hr: / $ cat ck1.yaml | nkf -g ASCII $ cat ck1.yaml | ./nkf.py - html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: | fuga guha - p: hr: / $ cat ck1.yaml | ./nkf.py | diff ck1.yaml - $
上記はpython3の環境で試しているので、同じ事をpython2でも確認しておきます。
$ cat jis.yaml | python2 ./nkf.py | diff jis.yaml - $ cat euc.yaml | python2 ./nkf.py | diff euc.yaml - $ cat sjis.yaml | python2 ./nkf.py | diff sjis.yaml - $ cat utf8.yaml | python2 ./nkf.py | diff utf8.yaml - $ cat ck1.yaml | python2 ./nkf.py | diff ck1.yaml - $
大丈夫そうですね。
このnkf.pyをezhtml.pyから使うように変更してみました。
$ cat jis.yaml | ./ezhtml.py | nkf -u <html><head><title>タイトル</title></head> <body><h1>ふー</h1> <p>ばー ほげ</p> <pre> ふが ぐは </pre> <p><hr></p></body></html> $ cat jis.yaml | ./ezhtml.py | nkf -g ISO-2022-JP $ cat euc.yaml | ./ezhtml.py | nkf -g EUC-JP $ cat sjis.yaml | ./ezhtml.py | nkf -g Shift_JIS $ cat utf8.yaml | ./ezhtml.py | nkf -g UTF-8 $ cat ck1.yaml | ./ezhtml.py | nkf -g ASCII $ cat ck1.yaml | ./ezhtml.py <html><head><title>Title</title></head> <body><h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p><hr></p></body></html>
一応 python2 でも同様に
$ cat jis.yaml | python2 ./ezhtml.py | nkf -u <html><head><title>タイトル</title></head> <body><h1>ふー</h1> <p>ばー ほげ</p> <pre> ふが ぐは </pre> <p><hr></p></body></html> $ cat jis.yaml | python2 ./ezhtml.py | nkf -g ISO-2022-JP $ cat euc.yaml | python2 ./ezhtml.py | nkf -g EUC-JP $ cat sjis.yaml | python2 ./ezhtml.py | nkf -g Shift_JIS $ cat utf8.yaml | python2 ./ezhtml.py | nkf -g UTF-8 $ cat ck1.yaml | python2 ./ezhtml.py | nkf -g ASCII
OK。
標準入力からのデータの形式を自動判定させてみます。
HTMLならYAMLに変換して出力し、HTML以外ならYAMLとみなしてHTMLに変換して出力するようにしてみます。
といっても、今のところはYAMLからHTMLの方向の変換しか実装してませんが...
v3.patch
diff -urN v2/ezhtml.py v3/ezhtml.py
--- v2/ezhtml.py 2018-09-17 00:15:20.000000000 +0900
+++ v3/ezhtml.py 2018-09-17 20:15:22.000000000 +0900
@@ -28,15 +28,23 @@
return s
return cv_amp(o)
+def html_load(s):
+ # ...
+ return { 'html': { 'body': { 'p': 'to be continued' } } }
+
if __name__ == "__main__":
b = nkf.get_stdin()
opt = nkf.guess(b)
+ html = nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip()
u8 = nkf.cvt(b, '-u')
s = nkf.dec(u8)
- o = yaml.load(s)
-
- s = html_dump(o) + '\n'
+ if html:
+ o = html_load(s)
+ s = yaml.dump( o, default_flow_style=False )
+ else:
+ o = yaml.load(s)
+ s = html_dump(o) + '\n'
u8 = nkf.enc(s)
b = nkf.cvt(u8, opt)
$ cat v3.patch | patch -p1 $ cat v3.patch : if __name__ == "__main__": b = nkf.get_stdin() opt = nkf.guess(b) + html = nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip() u8 = nkf.cvt(b, '-u') s = nkf.dec(u8) :
この1行でHTML形式かどうかを判定します。
fileコマンドの標準入力にデータを与えて、結果の文字列からgrepコマンドでhtmlの文字列を大文字小文字を無視して探します。
$ cat ck1.yaml - html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: | fuga guha - p: hr: / $ cat ck1.yaml | ./ezhtml.py <html><head><title>Title</title></head> <body><h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p><hr></p></body></html> $ cat ck1.yaml | ./ezhtml.py | ./ezhtml.py html: body: p: to be continued
HTMLからYAMLへの変換は、乞うご期待。
漢字の確認もいくつか
$ cat jis.yaml | nkf -u - html: - head: title: タイトル - body: - h1: ふー - p: ばー ほげ - pre: | ふが ぐは - p: hr: / $ cat jis.yaml | ./ezhtml.py | nkf -u <html><head><title>タイトル</title></head> <body><h1>ふー</h1> <p>ばー ほげ</p> <pre> ふが ぐは </pre> <p><hr></p></body></html> $ cat jis.yaml | ./ezhtml.py | ./ezhtml.py | nkf -u html: body: p: to be continued $ cat jis.yaml | nkf -u | ./ezhtml.py <html><head><title>タイトル</title></head> <body><h1>ふー</h1> <p>ばー ほげ</p> <pre> ふが ぐは </pre> <p><hr></p></body></html> $ cat jis.yaml | nkf -u | ./ezhtml.py | ./ezhtml.py html: body: p: to be continued $ cat jis.yaml | nkf -u | python2 ./ezhtml.py <html><head><title>タイトル</title></head> <body><h1>ふー</h1> <p>ばー ほげ</p> <pre> ふが ぐは </pre> <p><hr></p></body></html> $ cat jis.yaml | nkf -u | python2 ./ezhtml.py | python2 ./ezhtml.py html: body: p: to be continued
OK。
HTMLからYAMLへの変換。
すなわち、HTMLをロードしてpythonのオブジェクトで保持して、 それをPyYAMLでdumpとなります。
とりあえず一発目のHTMLのロードを書いてみました。
v4.patch
diff -urN v3/ezhtml.py v4/ezhtml.py
--- v3/ezhtml.py 2018-09-17 20:15:22.000000000 +0900
+++ v4/ezhtml.py 2018-09-17 23:46:44.000000000 +0900
@@ -28,9 +28,107 @@
return s
return cv_amp(o)
+def get_tag(s):
+ (p, tag) = ('', [])
+
+ while '<' in s:
+ i = s.index('<')
+ (t, s) = ( s[:i], s[i+1:] )
+ p += t
+ tag.append('<')
+ n = s[:1]
+ if n == '/':
+ tag.append('/')
+ s = s[1:]
+ n = s[:1]
+ if n.isalpha():
+ if '>' not in s:
+ err( "not found '>'", 'tag={}'.format(tag) )
+ i = s.index('>')
+ tag = tag[1:] + s[:i].split(' ')
+ s = s[i+1:]
+ break
+ p += ''.join(tag)
+ tag = []
+
+ if not tag:
+ (p, s) = (p+s, '')
+
+ return (p, tag, s)
+
+def start_idx(stk, s):
+ for i in reversed( range( len(stk) ) ):
+ e = stk[i]
+ if type(e) == list and e[0] == s:
+ return i
+ return -1
+
+def solo_tag(e):
+ if type(e) == list:
+ (h, e) = ( '/', e[1:] ) if e[0] == '/' else ('', e)
+ return { h + ' '.join(e): '/' }
+ return e
+
+def solo_tags(lst):
+ return list( map( solo_tag, lst ) )
+
+def untabify(s, n=8):
+ def f(s):
+ r = ''
+ for c in s:
+ if c == '\t':
+ c = ' ' * ( n - len(r) % n )
+ r += c
+ return r
+
+ lst = s.split('\n')
+ lst = map(f, lst)
+ return '\n'.join(lst)
+
+def strip_lst(lst, pre=False):
+ def f(e):
+ if type(e) == dict:
+ return e
+ if pre:
+ while ' \n' in e:
+ e = e.replace(' \n', '\n')
+ return untabify(e)
+ return e.replace('\n', ' ').strip()
+
+ return list( filter( lambda e: e != '', map(f, lst) ) )
+
+def close_tag(lst):
+ tag = lst[0]
+ lst = solo_tags( lst[1:] )
+ lst = strip_lst( lst, tag[0].lower() == 'pre' )
+ v = lst
+ if len(lst) == 1:
+ v = lst[0]
+ elif not lst:
+ v = ''
+ return { ' '.join(tag): v }
+
def html_load(s):
- # ...
- return { 'html': { 'body': { 'p': 'to be continued' } } }
+ stk = []
+ while True:
+ (p, tag, s) = get_tag(s)
+ if not tag:
+ break
+ if p:
+ stk.append( cv_amp(p, 'dec') )
+ if tag[0] != '/':
+ stk.append(tag)
+ continue
+ i = start_idx( stk, tag[1] )
+ if i >= 0:
+ stk = stk[:i] + [ close_tag( stk[i:] ) ]
+ else:
+ stk.append( solo_tag(tag) )
+
+ o = strip_lst( solo_tags(stk) )
+ while type(o) == list and len(o) == 1:
+ o = o[0]
+ return o
if __name__ == "__main__":
b = nkf.get_stdin()
$ cat v4.patch | patch -p1
逆方向のHTMLのダンプに比べるとコードが多いですが、 できるだけシンプルにまとめてみました。
$ cat ck1.html <html> <head> <title>Title</title> </head> <body> <h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p><hr></p> </body> </html> $ cat ck1.html | ./ezhtml.py | tee ck2.yaml html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: "\nfuga\n guha\n" - p: hr: / $ diff ck1.yaml ck2.yaml 1,12c1,9 < - html: < - head: < title: Title < - body: < - h1: foo < - p: bar hoge < - pre: | < < fuga < guha < - p: < hr: / --- > html: > - head: > title: Title > - body: > - h1: foo > - p: bar hoge > - pre: "\nfuga\n guha\n" > - p: > hr: /
おっと、最初に手打ちで作ったck1.yaml。 全体を要素数1のリストにしてましたが、 htmlタグ1つなので、全体を辞書にしても大丈夫でした。
あとpreタグ。縦棒「|」の形式でダンプさせたいところ...
$ cat ck2.yaml html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: "\nfuga\n guha\n" - p: hr: / $ cat ck2.yaml | ./ezhtml.py | tee ck2.html <html><head><title>Title</title></head> <body><h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p><hr></p></body></html> $ cat ck1.yaml | ./ezhtml.py | diff ck2.html - $ $ cat ck2.yaml | ./ezhtml.py | diff ck2.html - $ $ cat ck2.html | ./ezhtml.py | diff ck2.yaml - $ $ cat ck2.html <html><head><title>Title</title></head> <body><h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p><hr></p></body></html> $ cat ck2.html | ./ezhtml.py html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: "\nfuga\n guha\n" - p: hr: / $ cat ck2.html | ./ezhtml.py | ./ezhtml.py <html><head><title>Title</title></head> <body><h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p><hr></p></body></html> $ cat ck2.html | ./ezhtml.py | ./ezhtml.py | ./ezhtml.py html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: "\nfuga\n guha\n" - p: hr: /
とりあえず動いて嬉しいです。
TODO
preタグのyamlダンプを「|」形式に。
PyYAMLに頼ってる箇所ではありますが...どうしたものか? ぐぐってみると、ヒントが。
「PyYAMLで改行含む文字列の出力結果を変えたい(`|` を使いたい)」
まさにそうです!
参考にさせて頂きました。ありがとうございます。
v5.patch
diff -urN v4/ezhtml.py v5/ezhtml.py
--- v4/ezhtml.py 2018-09-17 23:46:44.000000000 +0900
+++ v5/ezhtml.py 2018-09-18 00:31:27.000000000 +0900
@@ -130,6 +130,18 @@
o = o[0]
return o
+def yaml_dump(o):
+ def represent_str(dumper, instance):
+ tag = 'tag:yaml.org,2002:str'
+ style = '|' if '\n' in instance else None
+ return dumper.represent_scalar( tag, instance, style=style )
+
+ for typ in [ str ] + ( [ unicode ] if six.PY2 else [] ):
+ yaml.add_representer(typ, represent_str)
+
+ u8 = yaml.dump( o, default_flow_style=False, allow_unicode=True, encoding='utf-8' )
+ return nkf.dec(u8)
+
if __name__ == "__main__":
b = nkf.get_stdin()
opt = nkf.guess(b)
@@ -139,7 +151,7 @@
if html:
o = html_load(s)
- s = yaml.dump( o, default_flow_style=False )
+ s = yaml_dump(o)
else:
o = yaml.load(s)
s = html_dump(o) + '\n'
$ cat v5.patch | patch -p1
他 allow_unicode, encoding の引数指定追加で yaml.dump()の漢字対応もしてます。
これでyaml.dump()がutf-8にまで変換してくれるようになったのですが、 後続の共通処理でのutf-8への変換を残しときたいので、 nkf.dec()でunicodeの状態に戻してから、後続に渡すようにしてます。
$ cat ck1.html <html> <head> <title>Title</title> </head> <body> <h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p><hr></p> </body> </html> $ cat ck1.html | ./ezhtml.py html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: |2 fuga guha - p: hr: / $ cat ck1.html | ./ezhtml.py | ./ezhtml.py <html><head><title>Title</title></head> <body><h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p><hr></p></body></html> $ cat ck1.html | ./ezhtml.py | ./ezhtml.py | ./ezhtml.py html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: |2 fuga guha - p: hr: /
なんか「|」に「2」とか付いてます。
字下げの数を明示的に指定だそうです。ふむふむ。
$ cat jis.html | nkf -u <html><head><title>タイトル</title></head> <body><h1>ふー</h1> <p>ばー ほげ</p> <pre> ふが ぐは </pre> <p><hr></p></body></html> $ cat jis.html | ./ezhtml.py | nkf -u html: - head: title: タイトル - body: - h1: ふー - p: ばー ほげ - pre: |2 ふが ぐは - p: hr: / $ cat jis.html | ./ezhtml.py | ./ezhtml.py | nkf -u <html><head><title>タイトル</title></head> <body><h1>ふー</h1> <p>ばー ほげ</p> <pre> ふが ぐは </pre> <p><hr></p></body></html> $ cat jis.html | ./ezhtml.py | ./ezhtml.py | ./ezhtml.py | nkf -u html: - head: title: タイトル - body: - h1: ふー - p: ばー ほげ - pre: |2 ふが ぐは - p: hr: /
大丈夫そうですね。
$ cat jis.html | ./ezhtml.py > jis.yaml $ cat jis.yaml | ./ezhtml.py | diff jis.html - $ $ cat jis.html | ./ezhtml.py | ./ezhtml.py | diff jis.html - $ cat jis.html | python2 ./ezhtml.py | python2 ./ezhtml.py | diff jis.html - $ cat jis.html | nkf -e > euc.html $ cat euc.html | nkf -g EUC-JP $ cat euc.html | ./ezhtml.py | ./ezhtml.py | diff euc.html - $ cat euc.html | python2 ./ezhtml.py | python2 ./ezhtml.py | diff euc.html - $
OK。
それではひとつ、それがしの トップページ なぞを。
$ wget -q -O- http://kondoh.html.xdomain.jp/index.html | tee top.html | nkf -u <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp"> <title> kon </title> </head> <body> <h1> kon page </h1> <p><hr></p> <p><img src="beat.jpg"></p> <p><hr></p> <ul> <li><a href="bike-kon.html"> バイク </a> <li><a href=hist.html> 更新履歴 </a> <li><a href=me.html> 自己紹介 </a> <li><a href=java/index.html> Javaのテスト </a> <li><a href=color-sample.html> 色見本 </a> <li><a href=qP2240018.jpg> ライトネス Qちゃん 2002年頃 </a> <li><a href="murakami-sho-ji-090329/index.html"> 村上商事 2009 </a> <li><a href="copen-090419.jpg"> Copen 2009 湯っぷる </a> <li><a href="txtbl.html"> 簡単なテキストの表組みツール (C言語) </a> <li><a href="txtblcnt.html"> TXTBLCNT (簡単なテキストの表組みツールのためのさらなるツール) </a> <li><a href="midi.html"> SMFを読み込み音の波形データを作るプログラム (C言語) </a> <li><a href="cui14/index.html"> CUI14 </a> <li><a href="wf.html"> ワイヤーフレームのプログラム </a> <li><a href="es16/index.html"> Pythonで作るなんちゃってCインタプリタ </a> <li><a href="nand17/index.html"> Pythonで作るなんちゃってNANDゲートシミュレータ </a> <li><a href="tete17/index.html"> テテリス2017夏 </a> <li><a href="pac/index.html"> パックマンもどき2017秋 </a> <li><a href="bktool/index.html"> バックアップツール </a> <li><a href="http://kondoh2.html.xdomain.jp/rt/index.html"> レイトレーシング 2018春 </a> <li><a href="py3.html"> python3 対応のメモ </a> <li><a href="ezyaml/index.html"> 簡易なYAMLパーサ 2018夏 </a> <li><a href="ezhtml/index.html"> 簡易なHTMLパーサ 2018秋 </a> </ul> <p><video src="http://kondoh2.html.xdomain.jp/rt/out_v44/fix_1.mp4" controls playsinline></video></p> <p><video src="http://kondoh2.html.xdomain.jp/rt/out_v62/cut.mp4" controls playsinline></video></p> <p><hr></p> </body> </html> $ cat top.html | ./ezhtml.py | tee top.yaml | nkf -u html: - head: - meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp": / - title: kon - body: - h1: kon page - p: hr: / - p: img src="beat.jpg": / - p: hr: / - ul: - li: / - a href="bike-kon.html": バイク - li: / - a href=hist.html: 更新履歴 - li: / - a href=me.html: 自己紹介 - li: / - a href=java/index.html: Javaのテスト - li: / - a href=color-sample.html: 色見本 - li: / - a href=qP2240018.jpg: ライトネス Qちゃん 2002年頃 - li: / - a href="murakami-sho-ji-090329/index.html": 村上商事 2009 - li: / - a href="copen-090419.jpg": Copen 2009 湯っぷる - li: / - a href="txtbl.html": 簡単なテキストの表組みツール (C言語) - li: / - a href="txtblcnt.html": TXTBLCNT (簡単なテキストの表組みツールのためのさらなるツール) - li: / - a href="midi.html": SMFを読み込み音の波形データを作るプログラム (C言語) - li: / - a href="cui14/index.html": CUI14 - li: / - a href="wf.html": ワイヤーフレームのプログラム - li: / - a href="es16/index.html": Pythonで作るなんちゃってCインタプリタ - li: / - a href="nand17/index.html": Pythonで作るなんちゃってNANDゲートシミュレータ - li: / - a href="tete17/index.html": テテリス2017夏 - li: / - a href="pac/index.html": パックマンもどき2017秋 - li: / - a href="bktool/index.html": バックアップツール - li: / - a href="http://kondoh2.html.xdomain.jp/rt/index.html": レイトレーシング 2018春 - li: / - a href="py3.html": python3 対応のメモ - li: / - a href="ezyaml/index.html": 簡易なYAMLパーサ 2018夏 - li: / - a href="ezhtml/index.html": 簡易なHTMLパーサ 2018秋 - p: video src="http://kondoh2.html.xdomain.jp/rt/out_v44/fix_1.mp4" controls playsinline: '' - p: video src="http://kondoh2.html.xdomain.jp/rt/out_v62/cut.mp4" controls playsinline: '' - p: hr: / $ cat top.html | ./ezhtml.py | ./ezhtml.py | tee top2.html | nkf -u <html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp"> <title>kon</title></head> <body><h1>kon page</h1> <p><hr></p> <p><img src="beat.jpg"></p> <p><hr></p> <ul><li> <a href="bike-kon.html">バイク</a> <li> <a href=hist.html>更新履歴</a> <li> <a href=me.html>自己紹介</a> <li> <a href=java/index.html>Javaのテスト</a> <li> <a href=color-sample.html>色見本</a> <li> <a href=qP2240018.jpg>ライトネス Qちゃん 2002年頃</a> <li> <a href="murakami-sho-ji-090329/index.html">村上商事 2009</a> <li> <a href="copen-090419.jpg">Copen 2009 湯っぷる</a> <li> <a href="txtbl.html">簡単なテキストの表組みツール (C言語)</a> <li> <a href="txtblcnt.html">TXTBLCNT (簡単なテキストの表組みツールのためのさらなるツール)</a> <li> <a href="midi.html">SMFを読み込み音の波形データを作るプログラム (C言語)</a> <li> <a href="cui14/index.html">CUI14</a> <li> <a href="wf.html">ワイヤーフレームのプログラム</a> <li> <a href="es16/index.html">Pythonで作るなんちゃってCインタプリタ</a> <li> <a href="nand17/index.html">Pythonで作るなんちゃってNANDゲートシミュレータ</a> <li> <a href="tete17/index.html">テテリス2017夏</a> <li> <a href="pac/index.html">パックマンもどき2017秋</a> <li> <a href="bktool/index.html">バックアップツール</a> <li> <a href="http://kondoh2.html.xdomain.jp/rt/index.html">レイトレーシング 2018春</a> <li> <a href="py3.html">python3 対応のメモ</a> <li> <a href="ezyaml/index.html">簡易なYAMLパーサ 2018夏</a> <li> <a href="ezhtml/index.html">簡易なHTMLパーサ 2018秋</a></ul> <p><video src="http://kondoh2.html.xdomain.jp/rt/out_v44/fix_1.mp4" controls playsinline></video></p> <p><video src="http://kondoh2.html.xdomain.jp/rt/out_v62/cut.mp4" controls playsinline></video></p> <p><hr></p></body></html>
liタグの改行がアダとなって、逆に視認性が落ちてるような気がしなくもない...?
一応この top2.html をサイトのホームディレクトリにアップロードしてみました。
内容的には大丈夫そうですね。
TODO
それがしの トップページ でHTMLからYAMLの変換を試してみると
<ul> <li><a href="bike-kon.html"> バイク </a> <li><a href=hist.html> 更新履歴 </a> <li><a href=me.html> 自己紹介 </a> : <li><a href="ezhtml/index.html"> 簡易なHTMLパーサ 2018秋 </a> </ul>
な箇所が
- ul: - li: / - a href="bike-kon.html": バイク - li: / - a href=hist.html: 更新履歴 - li: / - a href=me.html: 自己紹介 : - li: / - a href="ezhtml/index.html": 簡易なHTMLパーサ 2018秋
てな具合に改行が入って、さらにこのYAMLをHTMLに変換しなおすと
<ul><li> <a href="bike-kon.html">バイク</a> <li> <a href=hist.html>更新履歴</a> <li> <a href=me.html>自己紹介</a> : <li> <a href="ezhtml/index.html">簡易なHTMLパーサ 2018秋</a></ul>
ブラウザで表示される内容は同じとは言え、 何とか改行を入れないようにできないでしょうか?
通常のタグは
<tag>foo</tag>
な形式で、'/'で始まる終了タグがついてます。
変換するYAML形式では
tag: foo
の辞書にしてます。
HTMLの場合、この終了タグがないパターンがある訳で、 その場合のYAML形式は
tag: /
の辞書にしてます。
よく考えると終了タグがないパターンは2通りあります。
開始タグだけで意味が完結してる
<tag>
のパターン。
もう一つは
<tag>foo</tag>
で意味が完結するところだが、終了タグが省略されている
<tag>foo
のパターン。
前者はこれまでの対応がふさわしく。
さらに後者のパターンの対応を追加してみます。
これまでの方針
に加えて
先のulタグ、liタグの場合ならば
ul: - li: / - foo - li: / - bar
は
ul: - li /: foo - li /: bar
あるいは
ul: - li/: foo - li/: bar
も許す事にしてみます。
まずはダンプ側の対応から。こちら側の変更は簡単。
v6.patch
diff -urN v5/ezhtml.py v6/ezhtml.py
--- v5/ezhtml.py 2018-09-18 00:31:27.000000000 +0900
+++ v6/ezhtml.py 2018-09-18 21:51:22.000000000 +0900
@@ -15,6 +15,19 @@
s = s.replace(f, t)
return s
+def dump_tag(tag, v):
+ lst = bak = tag.split(' ')
+ if lst[-1] == '/':
+ lst = lst[:-1]
+ if lst[0][-1] == '/':
+ lst = [ lst[0][:-1] ] + lst[1:]
+ s = '<' + ' '.join(lst) + '>'
+ if v != '/':
+ s += html_dump(v)
+ if lst == bak:
+ s += '</' + lst[0] + '>'
+ return s
+
def html_dump(o):
if not o:
return ''
@@ -22,10 +35,7 @@
return '\n'.join( map(html_dump, o) )
if type(o) == dict:
(tag, v) = list( o.items() )[0]
- s = '<' + tag + '>'
- if v != '/':
- s += html_dump(v) + '</' + tag.split(' ')[0] + '>'
- return s
+ return dump_tag(tag, v)
return cv_amp(o)
def get_tag(s):
$ cat v6.patch diff -urN v5/ezhtml.py v6/ezhtml.py --- v5/ezhtml.py 2018-09-18 00:31:27.000000000 +0900 +++ v6/ezhtml.py 2018-09-18 21:51:22.000000000 +0900 @@ -15,6 +15,19 @@ s = s.replace(f, t) return s +def dump_tag(tag, v): + lst = bak = tag.split(' ') + if lst[-1] == '/': + lst = lst[:-1] + if lst[0][-1] == '/': + lst = [ lst[0][:-1] ] + lst[1:] + s = '<' + ' '.join(lst) + '>' + if v != '/': + s += html_dump(v) + if lst == bak: + s += '</' + lst[0] + '>' + return s + def html_dump(o): if not o: return '' @@ -22,10 +35,7 @@ return '\n'.join( map(html_dump, o) ) if type(o) == dict: (tag, v) = list( o.items() )[0] - s = '<' + tag + '>' - if v != '/': - s += html_dump(v) + '</' + tag.split(' ')[0] + '>' - return s + return dump_tag(tag, v) return cv_amp(o) def get_tag(s): $ cat v6.patch | patch -p1
ck3.yaml
html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |
fuga
guha
- p: gundam
- ul:
- li: /
- zaku
- li /: gufu
- li/: dom
- p:
hr: /
もう一丁変換すると...
$ cat ck3.yaml | ./ezhtml.py | ./ezhtml.py html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: |2 fuga guha - p: gundam - ul: - li: / - zaku - li: / - gufu - li: / - dom - p: hr: /
こちら方向の変換は未対応なので、この形式に戻ってしまいます。
では、ロード側。
パース処理の駆動原理は
終了タグの無い場合に、従来の { tag: / } 形式とするか、新設した { tag /: xxx } 形式とするか?
これはもうHTMLのタグの仕様の意味に依ります。
終了タグの省略が許されてる一覧を、データとして持たせる事にします。
すぐ思い当たるのはliタグですが、他には?
それがしの ワイヤーフレーム のページで、終了タグのないものを調べてみます。
$ wget -q -O- http://kondoh.html.xdomain.jp/wf.html | ./ezhtml.py | grep ': /' | sed 's/ *//' | sort | uniq - a: / - br: / - li: / - meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp": / hr: / img src="wf/img/g1.gif": / img src="wf/img/g10.gif": / : img src="wf/img/w9.png": /
aタグ?
$ wget -q -O- http://kondoh.html.xdomain.jp/wf.html | ./ezhtml.py | less : - a: / - a name="try_repeat_copy": h2: 繰り返しのパターンを試す :
対応箇所は
<a> <a name="try_repeat_copy"> <h2> 繰り返しのパターンを試す </h2> </a>
あぁ... 確かに、なんか間違ってる。orz
他は、br, li, meta, hr, img
後続の内容を意味的に含んでいて、終了タグが省略されてるパターンはli。
他のHTMLファイル、例えば
$ wget -q -O- http://kondoh.html.xdomain.jp/py3.html | ./ezhtml.py Traceback (most recent call last): File "./ezhtml.py", line 166, in <module> o = yaml.load(s) File "/usr/lib/python2.7/dist-packages/yaml/__init__.py", line 71, in load return loader.get_single_data() File "/usr/lib/python2.7/dist-packages/yaml/constructor.py", line 37, in get_single_data node = self.get_single_node() File "/usr/lib/python2.7/dist-packages/yaml/composer.py", line 36, in get_single_node document = self.compose_document() File "/usr/lib/python2.7/dist-packages/yaml/composer.py", line 58, in compose_document self.get_event() File "/usr/lib/python2.7/dist-packages/yaml/parser.py", line 118, in get_event self.current_event = self.state() File "/usr/lib/python2.7/dist-packages/yaml/parser.py", line 193, in parse_document_end token = self.peek_token() File "/usr/lib/python2.7/dist-packages/yaml/scanner.py", line 128, in peek_token self.fetch_more_tokens() File "/usr/lib/python2.7/dist-packages/yaml/scanner.py", line 220, in fetch_more_tokens return self.fetch_value() File "/usr/lib/python2.7/dist-packages/yaml/scanner.py", line 576, in fetch_value self.get_mark()) yaml.scanner.ScannerError: mapping values are not allowed here in "<unicode string>", line 5, column 24: <style> pre{ background: lightgray; } </style> ^
おおっと。
HTML食わせてるのにyaml.load()?
$ wget -q -O- http://kondoh.html.xdomain.jp/py3.html | file - /dev/stdin: Python script, ASCII text executable, with escape sequences
py3.htmlの内容をfileコマンドがHTMLと思ってくれてない (T_T)
とりあえず、このデータ形式の自動判定の問題は後回し...
$ wget -q -O- http://kondoh.html.xdomain.jp/midi.html | ./ezhtml.py Traceback (most recent call last): File "./ezhtml.py", line 158, in <module> html = nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip() File "/raid5/kondoh/hobby/ezhtml/nkf.py", line 15, in do_cmd proc.stdin.write(in_b) IOError: [Errno 32] Broken pipe $ wget -q -O- http://kondoh.html.xdomain.jp/midi.html | file - /dev/stdin: HTML document, ASCII text, with very long lines, with escape sequences
これはfileコマンドもHTMLと思っているけど
def do_cmd(cmd, in_b): cmd = enc(cmd) proc = subprocess.Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE) proc.stdin.write(in_b)
データ大き過ぎ?
$ wget -q -O- http://kondoh.html.xdomain.jp/midi.html | wc -l 29020
かも知れません。comunicateを使うべし? 一旦後回し...
とりあえず、終了タグ省略パターンは当面liだけ。 発見次第随時追加という事で。
v7.patch
diff -urN v6/ezhtml.py v7/ezhtml.py
--- v6/ezhtml.py 2018-09-18 21:51:22.000000000 +0900
+++ v7/ezhtml.py 2018-09-18 21:52:05.000000000 +0900
@@ -79,6 +79,39 @@
return { h + ' '.join(e): '/' }
return e
+def is_solo_tag_has_v(e):
+ lst = ['li']
+ if type(e) != dict:
+ return False
+ (tag, v) = e.items()[0]
+ return v == '/' and tag.split(' ')[0] in lst
+
+def solo_tag_has_v_idx(lst):
+ for i in range( len(lst) ):
+ if is_solo_tag_has_v( lst[i] ):
+ return i
+ return -1
+
+def strip_lst1(o):
+ while type(o) == list and len(o) == 1:
+ o = o[0]
+ return o
+
+def solo_tags_modify(lst):
+ def div_lst(lst):
+ i = solo_tag_has_v_idx(lst)
+ return ( lst[:i], lst[i:] ) if i >= 0 else ( lst, [] )
+ r = []
+ while lst:
+ (p, lst) = div_lst(lst)
+ r += p
+ if lst:
+ (e, lst) = ( lst[0], lst[1:] )
+ (tag, v) = e.items()[0] # v == '/'
+ (p, lst) = div_lst(lst)
+ r += [ { tag + ' /': strip_lst1(p) } ]
+ return r
+
def solo_tags(lst):
return list( map( solo_tag, lst ) )
@@ -95,7 +128,7 @@
lst = map(f, lst)
return '\n'.join(lst)
-def strip_lst(lst, pre=False):
+def strip_lst(lst, pre):
def f(e):
if type(e) == dict:
return e
@@ -107,10 +140,16 @@
return list( filter( lambda e: e != '', map(f, lst) ) )
+def close_solo_tag(lst, pre=False):
+ lst = solo_tags(lst)
+ lst = strip_lst(lst, pre)
+ lst = solo_tags_modify(lst)
+ return lst
+
def close_tag(lst):
- tag = lst[0]
- lst = solo_tags( lst[1:] )
- lst = strip_lst( lst, tag[0].lower() == 'pre' )
+ (tag, lst) = ( lst[0], lst[1:] )
+ lst = close_solo_tag( lst, tag[0].lower() == 'pre' )
+
v = lst
if len(lst) == 1:
v = lst[0]
@@ -135,10 +174,8 @@
else:
stk.append( solo_tag(tag) )
- o = strip_lst( solo_tags(stk) )
- while type(o) == list and len(o) == 1:
- o = o[0]
- return o
+ o = close_solo_tag(stk)
+ return strip_lst1(o)
def yaml_dump(o):
def represent_str(dumper, instance):
$ cat v7.patch | patch -p1
is_solo_tag_has_v()冒頭の lst = ['li'] が終了タグ省略パターンのデータです。
$ cat ck3.yaml html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: | fuga guha - p: gundam - ul: - li: / - zaku - li /: gufu - li/: dom - p: hr: / $ cat ck3.yaml | ./ezhtml.py | tee ck3.html <html><head><title>Title</title></head> <body><h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p>gundam</p> <ul><li> zaku <li>gufu <li>dom</ul> <p><hr></p></body></html> $ cat ck3.yaml | ./ezhtml.py | ./ezhtml.py html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: |2 fuga guha - p: gundam - ul: - li /: zaku - li /: gufu - li /: dom - p: hr: / $ cat ck3.yaml | ./ezhtml.py | ./ezhtml.py | diff ck3.yaml - 7c7 < - pre: | --- > - pre: |2 13,14c13 < - li: / < - zaku --- > - li /: zaku 16c15 < - li/: dom --- > - li /: dom $ cat ck3.yaml | ./ezhtml.py | ./ezhtml.py | ./ezhtml.py <html><head><title>Title</title></head> <body><h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p>gundam</p> <ul><li>zaku <li>gufu <li>dom</ul> <p><hr></p></body></html> $ cat ck3.yaml | ./ezhtml.py | ./ezhtml.py | ./ezhtml.py | diff ck3.html - 9,10c9 < <ul><li> < zaku --- > <ul><li>zaku
なんとも...徐々に、liタグまわりの形式や改行が統一されてきます。
では トップページ で確認
$ wget -q -O- http://kondoh.html.xdomain.jp/index.html | tee top.html | nkf -u <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp"> <title> kon </title> </head> <body> <h1> kon page </h1> <p><hr></p> <p><img src="beat.jpg"></p> <p><hr></p> <ul> <li><a href="bike-kon.html"> バイク </a> <li><a href=hist.html> 更新履歴 </a> <li><a href=me.html> 自己紹介 </a> <li><a href=java/index.html> Javaのテスト </a> <li><a href=color-sample.html> 色見本 </a> <li><a href=qP2240018.jpg> ライトネス Qちゃん 2002年頃 </a> <li><a href="murakami-sho-ji-090329/index.html"> 村上商事 2009 </a> <li><a href="copen-090419.jpg"> Copen 2009 湯っぷる </a> <li><a href="txtbl.html"> 簡単なテキストの表組みツール (C言語) </a> <li><a href="txtblcnt.html"> TXTBLCNT (簡単なテキストの表組みツールのためのさらなるツール) </a> <li><a href="midi.html"> SMFを読み込み音の波形データを作るプログラム (C言語) </a> <li><a href="cui14/index.html"> CUI14 </a> <li><a href="wf.html"> ワイヤーフレームのプログラム </a> <li><a href="es16/index.html"> Pythonで作るなんちゃってCインタプリタ </a> <li><a href="nand17/index.html"> Pythonで作るなんちゃってNANDゲートシミュレータ </a> <li><a href="tete17/index.html"> テテリス2017夏 </a> <li><a href="pac/index.html"> パックマンもどき2017秋 </a> <li><a href="bktool/index.html"> バックアップツール </a> <li><a href="http://kondoh2.html.xdomain.jp/rt/index.html"> レイトレーシング 2018春 </a> <li><a href="py3.html"> python3 対応のメモ </a> <li><a href="ezyaml/index.html"> 簡易なYAMLパーサ 2018夏 </a> <li><a href="ezhtml/index.html"> 簡易なHTMLパーサ 2018秋 </a> </ul> <p><video src="http://kondoh2.html.xdomain.jp/rt/out_v44/fix_1.mp4" controls playsinline></video></p> <p><video src="http://kondoh2.html.xdomain.jp/rt/out_v62/cut.mp4" controls playsinline></video></p> <p><hr></p> </body> </html> $ cat top.html | ./ezhtml.py | tee top.yaml | nkf -u html: - head: - meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp": / - title: kon - body: - h1: kon page - p: hr: / - p: img src="beat.jpg": / - p: hr: / - ul: - li /: a href="bike-kon.html": バイク - li /: a href=hist.html: 更新履歴 - li /: a href=me.html: 自己紹介 - li /: a href=java/index.html: Javaのテスト - li /: a href=color-sample.html: 色見本 - li /: a href=qP2240018.jpg: ライトネス Qちゃん 2002年頃 - li /: a href="murakami-sho-ji-090329/index.html": 村上商事 2009 - li /: a href="copen-090419.jpg": Copen 2009 湯っぷる - li /: a href="txtbl.html": 簡単なテキストの表組みツール (C言語) - li /: a href="txtblcnt.html": TXTBLCNT (簡単なテキストの表組みツールのためのさらなるツール) - li /: a href="midi.html": SMFを読み込み音の波形データを作るプログラム (C言語) - li /: a href="cui14/index.html": CUI14 - li /: a href="wf.html": ワイヤーフレームのプログラム - li /: a href="es16/index.html": Pythonで作るなんちゃってCインタプリタ - li /: a href="nand17/index.html": Pythonで作るなんちゃってNANDゲートシミュレータ - li /: a href="tete17/index.html": テテリス2017夏 - li /: a href="pac/index.html": パックマンもどき2017秋 - li /: a href="bktool/index.html": バックアップツール - li /: a href="http://kondoh2.html.xdomain.jp/rt/index.html": レイトレーシング 2018春 - li /: a href="py3.html": python3 対応のメモ - li /: a href="ezyaml/index.html": 簡易なYAMLパーサ 2018夏 - li /: a href="ezhtml/index.html": 簡易なHTMLパーサ 2018秋 - p: video src="http://kondoh2.html.xdomain.jp/rt/out_v44/fix_1.mp4" controls playsinline: '' - p: video src="http://kondoh2.html.xdomain.jp/rt/out_v62/cut.mp4" controls playsinline: '' - p: hr: /
あぁ、aタグが入る場合は結局改行するのか...
- ul: - li /: { a href="bike-kon.html": バイク } - li /: { a href=hist.html: 更新履歴 } :
などとフロースタイルと混ぜて手打ちすれば、改行なしにもできますが...
ここまですると、かえって見にくいように思えます。
liタグは一旦ここまで。
$ cat top.html | ./ezhtml.py | ./ezhtml.py | nkf -u <html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp"> <title>kon</title></head> <body><h1>kon page</h1> <p><hr></p> <p><img src="beat.jpg"></p> <p><hr></p> <ul><li><a href="bike-kon.html">バイク</a> <li><a href=hist.html>更新履歴</a> <li><a href=me.html>自己紹介</a> <li><a href=java/index.html>Javaのテスト</a> <li><a href=color-sample.html>色見本</a> <li><a href=qP2240018.jpg>ライトネス Qちゃん 2002年頃</a> <li><a href="murakami-sho-ji-090329/index.html">村上商事 2009</a> <li><a href="copen-090419.jpg">Copen 2009 湯っぷる</a> <li><a href="txtbl.html">簡単なテキストの表組みツール (C言語)</a> <li><a href="txtblcnt.html">TXTBLCNT (簡単なテキストの表組みツールのためのさらなるツール)</a> <li><a href="midi.html">SMFを読み込み音の波形データを作るプログラム (C言語)</a> <li><a href="cui14/index.html">CUI14</a> <li><a href="wf.html">ワイヤーフレームのプログラム</a> <li><a href="es16/index.html">Pythonで作るなんちゃってCインタプリタ</a> <li><a href="nand17/index.html">Pythonで作るなんちゃってNANDゲートシミュレータ</a> <li><a href="tete17/index.html">テテリス2017夏</a> <li><a href="pac/index.html">パックマンもどき2017秋</a> <li><a href="bktool/index.html">バックアップツール</a> <li><a href="http://kondoh2.html.xdomain.jp/rt/index.html">レイトレーシング 2018春</a> <li><a href="py3.html">python3 対応のメモ</a> <li><a href="ezyaml/index.html">簡易なYAMLパーサ 2018夏</a> <li><a href="ezhtml/index.html">簡易なHTMLパーサ 2018秋</a></ul> <p><video src="http://kondoh2.html.xdomain.jp/rt/out_v44/fix_1.mp4" controls playsinline></video></p> <p><video src="http://kondoh2.html.xdomain.jp/rt/out_v62/cut.mp4" controls playsinline></video></p> <p><hr></p></body></html>
もう一度変換してHTMLに戻すと、良い感じ。
TODO
python3 対応のメモ のHTMLデータをfileコマンドがHTMLと思ってくれない問題について
$ wget -q -O- http://kondoh.html.xdomain.jp/py3.html | file - /dev/stdin: Python script, ASCII text executable, with escape sequences
HTMLじゃなくてpythonのソースと思ってるもよう。
ちょっと試してみると、逆にYAMLデータでも簡単にHTMLと思ってしまうようです。
ck4.yaml
html:
- head:
title: Title
- body:
- h1: foo
- p: <html><head></head><body></body></html>
# EOF
コマンド引数オプションで、強制ありにします。
h の指定があると入力データをHTMLとして扱い、 y の指定があると入力データをYAMLとして扱うようにします。
v8.patch
diff -urN v7/ezhtml.py v8/ezhtml.py
--- v7/ezhtml.py 2018-09-18 21:52:05.000000000 +0900
+++ v8/ezhtml.py 2018-09-18 21:52:28.000000000 +0900
@@ -192,7 +192,10 @@
if __name__ == "__main__":
b = nkf.get_stdin()
opt = nkf.guess(b)
- html = nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip()
+
+ is_html = lambda : nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip()
+ html = True if 'h' in sys.argv else False if 'y' in sys.argv else is_html()
+
u8 = nkf.cvt(b, '-u')
s = nkf.dec(u8)
$ cat v8.patch diff -urN v7/ezhtml.py v8/ezhtml.py --- v7/ezhtml.py 2018-09-18 21:52:05.000000000 +0900 +++ v8/ezhtml.py 2018-09-18 21:52:28.000000000 +0900 @@ -192,7 +192,10 @@ if __name__ == "__main__": b = nkf.get_stdin() opt = nkf.guess(b) - html = nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip() + + is_html = lambda : nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip() + html = True if 'h' in sys.argv else False if 'y' in sys.argv else is_html() + u8 = nkf.cvt(b, '-u') s = nkf.dec(u8) $ cat v8.patch | patch -p1
ck4.yamlから
$ cat ck4.yaml | ./ezhtml.py - 'html: - head: title: Title - body: - h1: foo - p:' - html: - head: '' - body: ''
YAMLなのにfileコマンドがHTMLと判定してるので、意味不明の出力してますが...
y を指定すると
$ cat ck4.yaml | ./ezhtml.py y | tee ck4.html <html><head><title>Title</title></head> <body><h1>foo</h1> <p><html><head></head><body></body></html></p></body></html>
OK。
一応
ck4.html
<html><head><title>Title</title></head>
<body><h1>foo</h1>
<p><html><head></head><body></body></html></p></body></html>
py3.html では逆に
$ wget -q -O- http://kondoh.html.xdomain.jp/py3.html | ./ezhtml.py Traceback (most recent call last): File "./ezhtml.py", line 206, in <module> o = yaml.load(s) : yaml.scanner.ScannerError: mapping values are not allowed here in "<unicode string>", line 5, column 24: <style> pre{ background: lightgray; } </style> ^
HTMLをfileコマンドがHTML以外と判定してるので、エラー発生。
h を指定すると
$ wget -q -O- http://kondoh.html.xdomain.jp/py3.html | ./ezhtml.py h | nkf -u html: - head: - meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp": / - title: python3 - style: 'pre{ background: lightgray; }' - body: - h1: python3 対応のメモ - p: - a href="http://kondoh2.html.xdomain.jp/rt/index.html": レイトレーシング 2018春 - の : >>> print((1,2)) (1, 2) >>> print ((1,2)) (1, 2) - p: hr: /
OK。
TODO
のHTMLが巨大で顕在化した問題を対策しておきます。
$ wget -q -O- http://kondoh.html.xdomain.jp/midi.html | wc -l 29020 $ wget -q -O- http://kondoh.html.xdomain.jp/midi.html | ./ezhtml.py Traceback (most recent call last): File "./ezhtml.py", line 158, in <module> html = nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip() File "/raid5/kondoh/hobby/ezhtml/nkf.py", line 15, in do_cmd proc.stdin.write(in_b) IOError: [Errno 32] Broken pipe
nkf.py の do_cmd() でproc.communicate()を使うように変更してみました。
ついでに python3 で辞書のitems()がlistを返さないため、 うまく動いてなかったバグを、しれっと直しておきます。
v9.patch
diff -urN v8/ezhtml.py v9/ezhtml.py
--- v8/ezhtml.py 2018-09-18 21:52:28.000000000 +0900
+++ v9/ezhtml.py 2018-09-18 22:19:51.000000000 +0900
@@ -28,13 +28,16 @@
s += '</' + lst[0] + '>'
return s
+def get_tag_v(d):
+ return list( d.items() )[0]
+
def html_dump(o):
if not o:
return ''
if type(o) == list:
return '\n'.join( map(html_dump, o) )
if type(o) == dict:
- (tag, v) = list( o.items() )[0]
+ (tag, v) = get_tag_v(o)
return dump_tag(tag, v)
return cv_amp(o)
@@ -83,7 +86,7 @@
lst = ['li']
if type(e) != dict:
return False
- (tag, v) = e.items()[0]
+ (tag, v) = get_tag_v(e)
return v == '/' and tag.split(' ')[0] in lst
def solo_tag_has_v_idx(lst):
@@ -107,7 +110,7 @@
r += p
if lst:
(e, lst) = ( lst[0], lst[1:] )
- (tag, v) = e.items()[0] # v == '/'
+ (tag, v) = get_tag_v(e) # v == '/'
(p, lst) = div_lst(lst)
r += [ { tag + ' /': strip_lst1(p) } ]
return r
diff -urN v8/nkf.py v9/nkf.py
--- v8/nkf.py 2018-09-17 00:15:20.000000000 +0900
+++ v9/nkf.py 2018-09-18 22:20:22.000000000 +0900
@@ -12,11 +12,7 @@
def do_cmd(cmd, in_b):
cmd = enc(cmd)
proc = subprocess.Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE)
- proc.stdin.write(in_b)
- proc.stdin.close()
- r = proc.stdout.read()
- proc.wait()
- return r # out_b
+ return proc.communicate(in_b)[0]
def get_stdin():
fi = sys.stdin if six.PY2 else sys.stdin.buffer
$ cat v9.patch diff -urN v8/ezhtml.py v9/ezhtml.py --- v8/ezhtml.py 2018-09-18 21:52:28.000000000 +0900 +++ v9/ezhtml.py 2018-09-18 22:19:51.000000000 +0900 @@ -28,13 +28,16 @@ s += '</' + lst[0] + '>' return s +def get_tag_v(d): + return list( d.items() )[0] + def html_dump(o): if not o: return '' if type(o) == list: return '\n'.join( map(html_dump, o) ) if type(o) == dict: - (tag, v) = list( o.items() )[0] + (tag, v) = get_tag_v(o) return dump_tag(tag, v) return cv_amp(o) @@ -83,7 +86,7 @@ lst = ['li'] if type(e) != dict: return False - (tag, v) = e.items()[0] + (tag, v) = get_tag_v(e) return v == '/' and tag.split(' ')[0] in lst def solo_tag_has_v_idx(lst): @@ -107,7 +110,7 @@ r += p if lst: (e, lst) = ( lst[0], lst[1:] ) - (tag, v) = e.items()[0] # v == '/' + (tag, v) = get_tag_v(e) # v == '/' (p, lst) = div_lst(lst) r += [ { tag + ' /': strip_lst1(p) } ] return r diff -urN v8/nkf.py v9/nkf.py --- v8/nkf.py 2018-09-17 00:15:20.000000000 +0900 +++ v9/nkf.py 2018-09-18 22:20:22.000000000 +0900 @@ -12,11 +12,7 @@ def do_cmd(cmd, in_b): cmd = enc(cmd) proc = subprocess.Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE) - proc.stdin.write(in_b) - proc.stdin.close() - r = proc.stdout.read() - proc.wait() - return r # out_b + return proc.communicate(in_b)[0] def get_stdin(): fi = sys.stdin if six.PY2 else sys.stdin.buffer $ cat v9.patch | patch -p1
では確認
$ wget -q -O- http://kondoh.html.xdomain.jp/midi.html | ./ezhtml.py | tee midi.yaml | nkf -u html: - head: - meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp": / - title: midi - style: 'pre{ background: lightgray; }' - body: - h1: SMFを読み込み音の波形データを作るプログラム (C言語) - pre: - "\n\n | " - font color="#FFFFFF" style="background-color:#000000": '' - X : - p: hr: / - p: 工事中... - p: hr: / - <!-- memo $ env RAW_CH=1 ./midi.sh jrt2-sawari.raw jrt2-test --- jrt2.mp3 $ mpg123 -w b.wav jrt2.mp3 $ sox b.wav -t raw -c 1 - > jrt2-mono.raw -rw-rw-r-- 1 kondoh root 50379264 Jun 25 jrt2-mono.raw -rw-rw-r-- 1 kondoh root 100758572 Jun 25 b.wav --> $ wc -l midi.yaml 25140 midi.yaml
25,000行のYAMLファイルが生成できました。
HTMLに戻してみます。
$ cat midi.yaml | ./ezhtml.py | tee midi2.html | nkf -u <html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp"> <title>midi</title> <style>pre{ background: lightgray; }</style></head> <body><h1>SMFを読み込み音の波形データを作るプログラム (C言語)</h1> <pre> | <font color="#FFFFFF" style="background-color:#000000"></font> X : <p><hr></p> <p>工事中...</p> <p><hr></p> <!-- memo $ env RAW_CH=1 ./midi.sh jrt2-sawari.raw jrt2-test --- jrt2.mp3 $ mpg123 -w b.wav jrt2.mp3 $ sox b.wav -t raw -c 1 - > jrt2-mono.raw -rw-rw-r-- 1 kondoh root 50379264 Jun 25 jrt2-mono.raw -rw-rw-r-- 1 kondoh root 100758572 Jun 25 b.wav --></body></html> $ wc -l midi2.html 24633 midi2.html
24,000行のHTMLファイル生成。
midi2.html 置いてみました。
冒頭の鍵盤の表示が?
<pre> | <font color="#FFFFFF" style="background-color:#000000"> </font>X<font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"><u>X</u></font> <font color="#FFFFFF" style="background-color:#000000"> </font>X<font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> |
から
<pre> | <font color="#FFFFFF" style="background-color:#000000"></font> X <font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"><u>X</u></font> <font color="#FFFFFF" style="background-color:#000000"></font> X <font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> |
に。あー、preタグの中でfontタグが開いて閉じて、改行入ったか。
他はちゃんと表示されてるか...? 巨大過ぎますね。
最後のHTMLのコメントだった箇所が見えてる?
$ tail midi.yaml : - p: hr: / - p: 工事中... - p: hr: / - <!-- memo $ env RAW_CH=1 ./midi.sh jrt2-sawari.raw jrt2-test --- jrt2.mp3 $ mpg123 -w b.wav jrt2.mp3 $ sox b.wav -t raw -c 1 - > jrt2-mono.raw -rw-rw-r-- 1 kondoh root 50379264 Jun 25 jrt2-mono.raw -rw-rw-r-- 1 kondoh root 100758572 Jun 25 b.wav -->
なんかhtml_load()で文字列としてスタックに積まれてる?
いづれにせよ、HTMLのコメントはノーマークでした。
TODO
SMFを読み込み音の波形データを作るプログラム (C言語) をYAMLに変換して、HTMLに変換しなおしたものを、 midi2.html として置いてみたのですが、冒頭の鍵盤の表示が...?
preタグの中にさらにタグがあると、改行が入ってしまってる問題の対策です。
v10.patch
diff -urN v9/ezhtml.py v10/ezhtml.py
--- v9/ezhtml.py 2018-09-18 22:19:51.000000000 +0900
+++ v10/ezhtml.py 2018-09-20 03:53:08.000000000 +0900
@@ -15,7 +15,7 @@
s = s.replace(f, t)
return s
-def dump_tag(tag, v):
+def dump_tag(tag, v, pre):
lst = bak = tag.split(' ')
if lst[-1] == '/':
lst = lst[:-1]
@@ -23,7 +23,7 @@
lst = [ lst[0][:-1] ] + lst[1:]
s = '<' + ' '.join(lst) + '>'
if v != '/':
- s += html_dump(v)
+ s += html_dump( v, lst[0].lower() == 'pre' )
if lst == bak:
s += '</' + lst[0] + '>'
return s
@@ -31,14 +31,15 @@
def get_tag_v(d):
return list( d.items() )[0]
-def html_dump(o):
+def html_dump(o, pre=False):
if not o:
return ''
if type(o) == list:
- return '\n'.join( map(html_dump, o) )
+ delim = '' if pre else '\n'
+ return delim.join( map( lambda e: html_dump(e, pre), o ) )
if type(o) == dict:
(tag, v) = get_tag_v(o)
- return dump_tag(tag, v)
+ return dump_tag(tag, v, pre)
return cv_amp(o)
def get_tag(s):
$ cat v10.patch diff -urN v9/ezhtml.py v10/ezhtml.py --- v9/ezhtml.py 2018-09-18 22:19:51.000000000 +0900 +++ v10/ezhtml.py 2018-09-20 03:53:08.000000000 +0900 @@ -15,7 +15,7 @@ s = s.replace(f, t) return s -def dump_tag(tag, v): +def dump_tag(tag, v, pre): lst = bak = tag.split(' ') if lst[-1] == '/': lst = lst[:-1] @@ -23,7 +23,7 @@ lst = [ lst[0][:-1] ] + lst[1:] s = '<' + ' '.join(lst) + '>' if v != '/': - s += html_dump(v) + s += html_dump( v, lst[0].lower() == 'pre' ) if lst == bak: s += '</' + lst[0] + '>' return s @@ -31,14 +31,15 @@ def get_tag_v(d): return list( d.items() )[0] -def html_dump(o): +def html_dump(o, pre=False): if not o: return '' if type(o) == list: - return '\n'.join( map(html_dump, o) ) + delim = '' if pre else '\n' + return delim.join( map( lambda e: html_dump(e, pre), o ) ) if type(o) == dict: (tag, v) = get_tag_v(o) - return dump_tag(tag, v) + return dump_tag(tag, v, pre) return cv_amp(o) def get_tag(s): $ cat v10.patch | patch -p1
早速、巨大なHTML SMFを読み込み音の波形データを作るプログラム (C言語) で確認
$ wget -q -O- http://kondoh.html.xdomain.jp/midi.html | ./ezhtml.py | ./ezhtml.py | tee midi3.html | nkf - <html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp"> <title>midi</title> <style>pre{ background: lightgray; }</style></head> <body><h1>SMFを読み込み音の波形データを作るプログラム (C言語)</h1> <pre> | <font color="#FFFFFF" style="background-color:#000000"></font>X<font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"><u>X</u></font> <font color="#FFFFFF" style="background-color:#000000"></font>X<font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> | <u>| | | | | | | | | | | | | | |</u> </pre> <p><hr></p> :
改行は消えてる様子。
midi3.html 置いてみました。
それでも鍵盤の表示が...変です。
| <font color="#FFFFFF" style="background-color:#000000"> </font>X
に対して
| <font color="#FFFFFF" style="background-color:#000000"></font>
fontタグのスペース1つだけの文字列が消えてました。
preタグ中の他のタグの中身は、strip()したらダメか。
TODO
midi3.html で、それでも鍵盤の表示がおかしい問題。
preタグの中でスペースがstrip()で消えてるようです。
小さいデータで再現確認
$ echo '<html><body><pre>foo<u> </u>bar</pre></body></html>' | file - /dev/stdin: HTML document text $ echo '<html><body><pre>foo<u> </u>bar</pre></body></html>' | ./ezhtml.py | ./ezhtml.py <html><body><pre>foo<u></u>bar</pre></body></html>
確かに<u>と</u>の間のスペースが消えてます。
YAMLに変換した段階は?
$ echo '<html><body><pre>foo<u> </u>bar</pre></body></html>' | ./ezhtml.py html: body: pre: - foo - u: '' - bar
「- u: ''」になってます。
という事はdump側じゃなくてload側の問題。
def strip_lst(lst, pre): def f(e): if type(e) == dict: return e if pre: while ' \n' in e: e = e.replace(' \n', '\n') return untabify(e) return e.replace('\n', ' ').strip() return list( filter( lambda e: e != '', map(f, lst) ) )
ここでpreタグの場合はstrip()通らないはず?
ちょっとdebug out追加してみます
def strip_lst(lst, pre): def f(e): if type(e) == dict: return e if pre: while ' \n' in e: e = e.replace(' \n', '\n') return untabify(e) return e.replace('\n', ' ').strip() print('lst={} pre={}'.format(lst, pre)) # !!! debug return list( filter( lambda e: e != '', map(f, lst) ) )
$ echo '<html><body><pre>foo<u> </u>bar</pre></body></html>' | ./ezhtml.py lst=[' '] pre=False lst=['foo', {'u': ''}, 'bar'] pre=True lst=[{'pre': ['foo', {'u': ''}, 'bar']}] pre=False lst=[{'body': {'pre': ['foo', {'u': ''}, 'bar']}}] pre=False lst=[{'html': {'body': {'pre': ['foo', {'u': ''}, 'bar']}}}] pre=False html: body: pre: - foo - u: '' - bar
ふーむ。uタグを処理する段階ではpre == False。
preの終了タグを見つけた時に、preをTrueにしてスタックを遡りますが、 そのときは既にuタグは処理済...
なのでpreの開始タグでpreをTrueにせねばなりません。
v11.patch
diff -urN v10/ezhtml.py v11/ezhtml.py
--- v10/ezhtml.py 2018-09-20 03:53:08.000000000 +0900
+++ v11/ezhtml.py 2018-09-20 21:28:26.000000000 +0900
@@ -150,9 +150,9 @@
lst = solo_tags_modify(lst)
return lst
-def close_tag(lst):
+def close_tag(lst, pre):
(tag, lst) = ( lst[0], lst[1:] )
- lst = close_solo_tag( lst, tag[0].lower() == 'pre' )
+ lst = close_solo_tag(lst, pre)
v = lst
if len(lst) == 1:
@@ -163,6 +163,12 @@
def html_load(s):
stk = []
+ pre_cnt = 0
+
+ def add_cnt(tag):
+ pre = ( tag[1] if tag[0] == '/' else tag[0] ).lower() == 'pre'
+ return ( -1 if tag[0] == '/' else 1 ) if pre else 0
+
while True:
(p, tag, s) = get_tag(s)
if not tag:
@@ -171,14 +177,16 @@
stk.append( cv_amp(p, 'dec') )
if tag[0] != '/':
stk.append(tag)
+ pre_cnt += add_cnt(tag)
continue
i = start_idx( stk, tag[1] )
if i >= 0:
- stk = stk[:i] + [ close_tag( stk[i:] ) ]
+ stk = stk[:i] + [ close_tag( stk[i:], pre_cnt > 0 ) ]
+ pre_cnt += add_cnt(tag)
else:
stk.append( solo_tag(tag) )
- o = close_solo_tag(stk)
+ o = close_solo_tag( stk, pre_cnt > 0 )
return strip_lst1(o)
def yaml_dump(o):
debug out行は削除して元に戻して
$ cat v11.patch | patch -p1
もっかいdebug out行をつけ直して
def strip_lst(lst, pre): def f(e): if type(e) == dict: return e if pre: while ' \n' in e: e = e.replace(' \n', '\n') return untabify(e) return e.replace('\n', ' ').strip() print('lst={} pre={}'.format(lst, pre)) # !!! debug return list( filter( lambda e: e != '', map(f, lst) ) )
$ echo '<html><body><pre>foo<u> </u>bar</pre></body></html>' | ./ezhtml.py lst=[' '] pre=True lst=['foo', {'u': ' '}, 'bar'] pre=True lst=[{'pre': ['foo', {'u': ' '}, 'bar']}] pre=False lst=[{'body': {'pre': ['foo', {'u': ' '}, 'bar']}}] pre=False lst=[{'html': {'body': {'pre': ['foo', {'u': ' '}, 'bar']}}}] pre=False html: body: pre: - foo - u: ' ' - bar
OK。
またdebut out削除して...
$ cat midi.html | ./ezhtml.py | tee midi4.yaml | nkf -u html: - head: - meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp": / - title: midi - style: 'pre{ background: lightgray; }' - body: - h1: SMFを読み込み音の波形データを作るプログラム (C言語) - pre: - "\n\n | " - font color="#FFFFFF" style="background-color:#000000": ' ' - X - font color="#FFFFFF" style="background-color:#000000": ' ' - ' | ' - font color="#FFFFFF" style="background-color:#000000": u: X - ' ' - font color="#FFFFFF" style="background-color:#000000": ' ' - X - font color="#FFFFFF" style="background-color:#000000": ' ' - ' | ' - font color="#FFFFFF" style="background-color:#000000": ' ' - ' ' - font color="#FFFFFF" style="background-color:#000000": ' ' - ' | ' - font color="#FFFFFF" style="background-color:#000000": ' ' - ' ' - font color="#FFFFFF" style="background-color:#000000": ' ' - ' ' - font color="#FFFFFF" style="background-color:#000000": ' ' - " |\n " - u: '| | | | | | | | | | | | | | | ' - |2+ : $ cat midi4.yaml | ./ezhtml.py | tee midi4.html | nkf -u <html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp"> <title>midi</title> <style>pre{ background: lightgray; }</style></head> <body><h1>SMFを読み込み音の波形データを作るプログラム (C言語)</h1> <pre> | <font color="#FFFFFF" style="background-color:#000000"> </font>X<font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"><u>X</u></font> <font color="#FFFFFF" style="background-color:#000000"> </font>X<font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> | <u>| | | | | | | | | | | | | | | </u> </pre> :
OK。
$ diff midi3.html midi4.html | nkf -u | less 7,8c7,8 < | <font color="#FFFFFF" style="background-color:#000000"></font>X<font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"><u>X</u></font> <font color="#FFFFFF" style="background-color:#000000"></font>X<font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> | < <u>| | | | | | | | | | | | | | |</u> --- > | <font color="#FFFFFF" style="background-color:#000000"> </font>X<font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"><u>X</u></font> <font color="#FFFFFF" style="background-color:#000000"> </font>X<font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> | > <u>| | | | | | | | | | | | | | | </u> 2746c2746,2748 < <p><a href="midi_mp3_early/prog8_xaa.mp3">prog8_xaa.mp3</a> --- > <p> > > <a href="midi_mp3_early/prog8_xaa.mp3"> prog8_xaa.mp3 </a> 2748,2749c2750,2755 < <a href="midi_mp3_early/prog8_xab.mp3">prog8_xab.mp3</a> < <br></p> --- > > > <a href="midi_mp3_early/prog8_xab.mp3"> prog8_xab.mp3 </a> > <br> > > </p> 6260c6266 < | midi ch : <u>0</u>| | --- > | midi ch : <u>0 </u>| | : 15550c15556 < <a href="midi_mp3/ryd-7.mp3">ryd-7.mp3</a> --- > <a href="midi_mp3/ryd-7.mp3"> ryd-7.mp3 </a> $ diff midi3.html midi4.html | wc -l 828
結構違いが出てますが...
該当箇所を元のmidi.htmlであたると、確かにpreタグの中。
midi4.html 置いてみました。
鍵盤はOK。
他、簡単なデータでデグレないか見ておきます。
$ cat ck1.yaml - html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: | fuga guha - p: hr: / $ cat ck1.yaml | ./ezhtml.py | tee tmp1.html <html><head><title>Title</title></head> <body><h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p><hr></p></body></html> $ cat tmp1.html | ./ezhtml.py | tee tmp1.yaml html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: |2 fuga guha - p: hr: / $ cat tmp1.html | ./ezhtml.py | diff tmp1.yaml - $ $ cat tmp1.yaml | ./ezhtml.py | diff tmp1.html - $ $ cat jis.yaml | nkf -u - html: - head: title: タイトル - body: - h1: ふー - p: ばー ほげ - pre: |2 ふが ぐは - p: hr: / $ cat jis.yaml | ./ezhtml.py | tee tmp_jis.html | nkf -u <html><head><title>タイトル</title></head> <body><h1>ふー</h1> <p>ばー ほげ</p> <pre> ふが ぐは </pre> <p><hr></p></body></html> $ cat tmp_jis.html | ./ezhtml.py | tee tmp_jis.yaml | nkf -u html: - head: title: タイトル - body: - h1: ふー - p: ばー ほげ - pre: |2 ふが ぐは - p: hr: / $ cat tmp_jis.yaml | ./ezhtml.py | diff tmp_jis.html - $ $ cat tmp_jis.html | ./ezhtml.py | diff tmp_jis.yaml - $ $ cat utf8.yaml - html: - head: title: タイトル - body: - h1: ふー - p: ばー ほげ - pre: | ふが ぐは - p: hr: / $ cat utf8.yaml | ./ezhtml.py | tee tmp_utf8.html <html><head><title>タイトル</title></head> <body><h1>ふー</h1> <p>ばー ほげ</p> <pre> ふが ぐは </pre> <p><hr></p></body></html> $ cat tmp_utf8.html | ./ezhtml.py | tee tmp_utf8.yaml html: - head: title: タイトル - body: - h1: ふー - p: ばー ほげ - pre: |2 ふが ぐは - p: hr: / $ cat tmp_utf8.yaml | ./ezhtml.py | diff tmp_utf8.html - $ $ cat tmp_utf8.html | ./ezhtml.py | diff tmp_utf8.yaml - $ $ cat ck3.yaml html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: | fuga guha - p: gundam - ul: - li: / - zaku - li /: gufu - li/: dom - p: hr: / $ cat ck3.yaml | ./ezhtml.py <html><head><title>Title</title></head> <body><h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p>gundam</p> <ul><li> zaku <li>gufu <li>dom</ul> <p><hr></p></body></html> $ cat ck3.yaml | ./ezhtml.py | ./ezhtml.py html: - head: title: Title - body: - h1: foo - p: bar hoge - pre: |2 fuga guha - p: gundam - ul: - li /: zaku - li /: gufu - li /: dom - p: hr: / $ cat ck3.yaml | ./ezhtml.py | ./ezhtml.py | ./ezhtml.py <html><head><title>Title</title></head> <body><h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p>gundam</p> <ul><li>zaku <li>gufu <li>dom</ul> <p><hr></p></body></html> $ cat ck4.yaml | ./ezhtml.py - 'html: - head: title: Title - body: - h1: foo - p:' - html: - head: '' - body: '' $ cat ck4.yaml | ./ezhtml.py y <html><head><title>Title</title></head> <body><h1>foo</h1> <p><html><head></head><body></body></html></p></body></html> $ cat ck4.yaml | ./ezhtml.py y | diff ck4.html - $
OK。
TODO
HTMLが進化してきたバージョンと、 コメントの規定の変遷の歴史は「微妙で複雑」です。
ここでは「ごちゃごちゃはヌキ」。
簡単なHTMLで現状の動作を確認
comment.html
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>foo</h1>
<!-- comment 1 -->
<p>bar</p>
<!--comment2-->
<!--
<p>hoge</p>
fuga
-->
<pre>
guha
geha
</pre>
<!-- <comment3> -->
</body>
</html>
だめです。
コメントの中のつもりの「<p>hoge</p>」が生きてるし、 そもそも'<!-- ...' が文字列として解釈されてます。
'<!-- xxx -->'はタグと認識しないのだろうか?
def get_tag(s): (p, tag) = ('', []) while '<' in s: i = s.index('<') (t, s) = ( s[:i], s[i+1:] ) p += t tag.append('<') n = s[:1] if n == '/': tag.append('/') s = s[1:] n = s[:1] if n.isalpha(): if '>' not in s: err( "not found '>'", 'tag={}'.format(tag) ) i = s.index('>') tag = tag[1:] + s[:i].split(' ') s = s[i+1:] break p += ''.join(tag) tag = [] if not tag: (p, s) = (p+s, '') return (p, tag, s)
get_tag() の n.isalpha() の箇所。ここで「はねて」いました。
'<' に続く文字列がアルファベットで始まってなければ、 タグと認識しません。
しかしながらコメントを、 通常の'<'で始まり'>'で終るタグの一種として、簡単に扱ってしまうと
<!-- <p>hoge</p> -->
の場合に、'<p>'の'>'で閉じてしまいます。
終りはちゃんと '-->' で見てやらねばなりません。
あとコメントは、改行も何もかも保持したままでYAMLに変換。 YAMLからHTMLに戻すときに、 正しく元のコメントとして復帰させねばなりません。
オブジェクトの段階ではpreタグのような感じで、 タグ名にあたる辞書のキーはとりあえず '!--' で。
v12.patch
diff -urN v11/ezhtml.py v12/ezhtml.py
--- v11/ezhtml.py 2018-09-20 21:28:26.000000000 +0900
+++ v12/ezhtml.py 2018-09-20 21:28:51.000000000 +0900
@@ -16,6 +16,8 @@
return s
def dump_tag(tag, v, pre):
+ if tag == '!--':
+ return '<!--' + v + '-->'
lst = bak = tag.split(' ')
if lst[-1] == '/':
lst = lst[:-1]
@@ -49,6 +51,13 @@
i = s.index('<')
(t, s) = ( s[:i], s[i+1:] )
p += t
+ if s[:3] == '!--' and '-->' in s[3:]:
+ tag.append('!--')
+ s = s[3:]
+ i = s.index('-->')
+ tag.append( s[:i] )
+ s = s[i+3:]
+ break
tag.append('<')
n = s[:1]
if n == '/':
@@ -79,6 +88,8 @@
def solo_tag(e):
if type(e) == list:
+ if e[0] == '!--':
+ return { '!--': e[1] }
(h, e) = ( '/', e[1:] ) if e[0] == '/' else ('', e)
return { h + ' '.join(e): '/' }
return e
$ cat v12.patch diff -urN v11/ezhtml.py v12/ezhtml.py --- v11/ezhtml.py 2018-09-20 21:28:26.000000000 +0900 +++ v12/ezhtml.py 2018-09-20 21:28:51.000000000 +0900 @@ -16,6 +16,8 @@ return s def dump_tag(tag, v, pre): + if tag == '!--': + return '<!--' + v + '-->' lst = bak = tag.split(' ') if lst[-1] == '/': lst = lst[:-1] @@ -49,6 +51,13 @@ i = s.index('<') (t, s) = ( s[:i], s[i+1:] ) p += t + if s[:3] == '!--' and '-->' in s[3:]: + tag.append('!--') + s = s[3:] + i = s.index('-->') + tag.append( s[:i] ) + s = s[i+3:] + break tag.append('<') n = s[:1] if n == '/': @@ -79,6 +88,8 @@ def solo_tag(e): if type(e) == list: + if e[0] == '!--': + return { '!--': e[1] } (h, e) = ( '/', e[1:] ) if e[0] == '/' else ('', e) return { h + ' '.join(e): '/' } return e $ cat v12.patch | patch -p1
簡単なデータから
$ cat comment.html <html> <head> <title>Title</title> </head> <body> <h1>foo</h1> <!-- comment 1 --> <p>bar</p> <!--comment2--> <!-- <p>hoge</p> fuga --> <pre> guha geha </pre> <!-- <comment3> --> </body> </html> $ cat comment.html | ./ezhtml.py html: - head: title: Title - body: - h1: foo - '!--': ' comment 1 ' - p: bar - '!--': comment2 - '!--': |2 <p>hoge</p> fuga - pre: |2 guha geha - '!--': ' <comment3> '
わりと狙い通りなYAML。
$ cat comment.html | ./ezhtml.py | ./ezhtml.py <html><head><title>Title</title></head> <body><h1>foo</h1> <!-- comment 1 --> <p>bar</p> <!--comment2--> <!-- <p>hoge</p> fuga --> <pre> guha geha </pre> <!-- <comment3> --></body></html>
コメント中の改行も再現できてるようですね。
では、大きなデータで
$ cat midi.html | grep '!--' | head <!-- 04192200 --> <!-- 04202200 --> <!-- 04220000 --> <!-- 04220000 --> <!-- 04220100 --> <!-- 04232300 --> <!-- 04232330 --> <!-- 04240000 --> <!-- 04240100 --> <!-- 04242300 --> $ cat midi.html | grep '!--' | tail <!-- 150909000000 --> <!-- 150910000000 --> <!-- 150911000000 --> o<!-- 150925000000 --> <!-- 150926000000 --> <!-- 150927000000 --> <!-- 150930000000 --> <!-- 151001000000 --> <!-- 151015000000 --> <!-- $ cat midi.html | grep '!--' | wc -l 92
コメントたくさんありますが、末尾の以外は単純っぽいです。
$ cat midi.html | ./ezhtml.py | tee midi.yaml | nkf -u : - p: - cui_midi.c の差分です - a href="midi_src/cui_midi7.patch": cui_midi7.patch - '!--': ' 04192200 ' : - p: hr: / - p: 工事中... - p: hr: / - '!--': |2+ memo $ env RAW_CH=1 ./midi.sh jrt2-sawari.raw jrt2-test --- jrt2.mp3 $ mpg123 -w b.wav jrt2.mp3 $ sox b.wav -t raw -c 1 - > jrt2-mono.raw -rw-rw-r-- 1 kondoh root 50379264 Jun 25 jrt2-mono.raw -rw-rw-r-- 1 kondoh root 100758572 Jun 25 b.wav ...
HTMLに戻してみて
$ cat midi.yaml | ./ezhtml.py > midi5.htm $ tail -20 midi5.html | nkf -u <p><hr></p> <p>工事中...</p> <p><hr></p> <!-- memo $ env RAW_CH=1 ./midi.sh jrt2-sawari.raw jrt2-test --- jrt2.mp3 $ mpg123 -w b.wav jrt2.mp3 $ sox b.wav -t raw -c 1 - > jrt2-mono.raw -rw-rw-r-- 1 kondoh root 50379264 Jun 25 jrt2-mono.raw -rw-rw-r-- 1 kondoh root 100758572 Jun 25 b.wav --></body></html>
オリジナルのmidi.htmlは
$ tail -20 midi.html | nkf -u <!-- memo $ env RAW_CH=1 ./midi.sh jrt2-sawari.raw jrt2-test --- jrt2.mp3 $ mpg123 -w b.wav jrt2.mp3 $ sox b.wav -t raw -c 1 - > jrt2-mono.raw -rw-rw-r-- 1 kondoh root 50379264 Jun 25 jrt2-mono.raw -rw-rw-r-- 1 kondoh root 100758572 Jun 25 b.wav --> </body> </html>
コメント中の改行も問題なさそう。
midi5.html 置いてみました。
OK?
TODO
pythonのユーティリティ・プログラム 2020冬 でうかつにnkf.pyを更新してしまったために、ezhtml.pyでエラーが出る場合がありました。
$ cat ezmhtml.py : is_html = lambda : nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip() :
このnkf.do_cmd()がもう消えてしまってました。
ezhtml.pyもkon_utを使うように変更しておきます。
v13.patch
diff -ur v12/ezhtml.py v13/ezhtml.py
--- v12/ezhtml.py 2018-09-20 21:28:51.000000000 +0900
+++ v13/ezhtml.py 2020-02-01 01:15:52.000000000 +0900
@@ -4,6 +4,7 @@
import yaml
import six
import nkf
+import cmd_ut
def cv_amp(s, d='enc'):
lst = [ ('&','&'), ('<','<'), ('>','>') ]
@@ -216,7 +217,7 @@
b = nkf.get_stdin()
opt = nkf.guess(b)
- is_html = lambda : nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip()
+ is_html = lambda : nkf.dec( cmd_ut.call_comm('file - | grep -i html', b) ).strip()
html = True if 'h' in sys.argv else False if 'y' in sys.argv else is_html()
u8 = nkf.cvt(b, '-u')
$ cat v13.patch | patch -p1
前回の更新から1年以上経ってますが、久々に更新してみます。
簡易なおれおれマークダウン 2019秋 の方でも更新してて、それとのセットになります。
タグに独自のプロパティ'bare'を追加します。
YAML形式的にはタグのプロパティは、タグ名の部分に押し込められています。
YAML形式で、bare="True" のプロパティがついてると、 &", "<", ">" の3つの文字について、"&", "<", "> のエンコード処理をせずに素通ししてHTMLを生成します。
v14.patch
diff -ur v13/ezhtml.py v14/ezhtml.py
--- v13/ezhtml.py 2020-02-01 01:15:52.000000000 +0900
+++ v14/ezhtml.py 2021-02-23 16:59:50.000000000 +0900
@@ -24,9 +24,17 @@
lst = lst[:-1]
if lst[0][-1] == '/':
lst = [ lst[0][:-1] ] + lst[1:]
+
+ t = 'bare="True"'
+ bare = t in lst
+ if bare:
+ lst.remove(t)
+ if t in bak:
+ bak.remove(t)
+
s = '<' + ' '.join(lst) + '>'
if v != '/':
- s += html_dump( v, lst[0].lower() == 'pre' )
+ s += html_dump( v, lst[0].lower() == 'pre', bare=bare )
if lst == bak:
s += '</' + lst[0] + '>'
return s
@@ -34,7 +42,7 @@
def get_tag_v(d):
return list( d.items() )[0]
-def html_dump(o, pre=False):
+def html_dump(o, pre=False, bare=False):
if not o:
return ''
if type(o) == list:
@@ -43,7 +51,7 @@
if type(o) == dict:
(tag, v) = get_tag_v(o)
return dump_tag(tag, v, pre)
- return cv_amp(o)
+ return o if bare else cv_amp(o)
def get_tag(s):
(p, tag) = ('', [])
$ cat v14.patch | patch -p1
$ ./ezhtml.py <<EOF > - pre: | > abc > xyz <u> foo </u> > bar > - pre bare="True": | > abc > xyz <u> foo </u> > bar > EOF <pre>abc xyz <u> foo </u> bar </pre> <pre>abc xyz <u> foo </u> bar </pre> $