PerlでXHTMLのテキスト内容だけを置換する
2017/10/20まあ仕事でEPUBを作っていると恒常的にXHTMLに触ることにはなるのですが、検索で文章中の欧文の部分などを引っかけて修正する時にXHTMLのタグ部分も引っかかってしまって、これこのまま間違えてここも修正しちゃったらエラー直行だよなみたいなケースが時々あります。なのでテキスト部分だけを検索置換対象にできれば便利かなと思って作ってみました。
XML::LibXMLでXHTMLをパースしてテキストノードだけ選別して置換処理をループで回してるだけです。置換用ファイルは別ファイルにPerlの置換式書いたヤツを読み込む感じで。
Macのターミナルで
perl コードのファイル.pl 置換対象.xhtml 外部読み込み置換式.pl
のような感じで実行すれば置換対象のxhtmlを置換して上書きします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
#!/usr/bin/perl use utf8; use warnings; use XML::LibXML; use Encode qw/encode decode/; #変換するXHTMLファイルのパスを取得 my $convertXhtmlFilePath = $ARGV[0]; $convertXhtmlFilePath = decode('UTF-8', $convertXhtmlFilePath); #インポートする置換式入りファイルのパスを取得、内容をインポート $replaceFilePath = $ARGV[1]; $replaceFilePath = decode('UTF-8', $replaceFilePath); require $replaceFilePath; #最初にパース実行 my $parser = XML::LibXML->new(); $parser->no_network(1); my $dom = $parser->parse_file($convertXhtmlFilePath); #デフォルト名前空間の対応処置 my $xc = XML::LibXML::XPathContext->new($dom); $xc->registerNs('xhtml', 'http://www.w3.org/1999/xhtml'); $xc->registerNs('epub', 'http://www.idpf.org/2007/ops'); #####dom置換実行##### #タグのリスト定義/よくわかんないからhtml5のタグほぼ全部ぶっ込んだ my @tags = ( '//xhtml:body', '//xhtml:div', '//xhtml:section', '//xhtml:article', '//xhtml:aside', '//xhtml:blockquote', '//xhtml:p', '//xhtml:h1', '//xhtml:h2', '//xhtml:h3', '//xhtml:h4', '//xhtml:h5', '//xhtml:h6', '//xhtml:ruby', '//xhtml:rb', '//xhtml:rt', '//xhtml:rp', '//xhtml:li', '//xhtml:dt', '//xhtml:dd', '//xhtml:td', '//xhtml:th', '//xhtml:caption', '//xhtml:thead', '//xhtml:tfoot', '//xhtml:span', '//xhtml:strong', '//xhtml:em', '//xhtml:small', '//xhtml:cite', '//xhtml:q', '//xhtml:i', '//xhtml:b', '//xhtml:u', '//xhtml:sub', '//xhtml:sup', '//xhtml:pre', '//xhtml:code', '//xhtml:time', '//xhtml:label', '//xhtml:input', '//xhtml:select', '//xhtml:option', '//xhtml:textarea', '//xhtml:a', '//xhtml:address', '//xhtml:figcaption', '//xhtml:abbr', '//xhtml:ins', '//xhtml:del', '//xhtml:fieldset', '//xhtml:legend', '//xhtml:s', '//xhtml:dfn', '//xhtml:var', '//xhtml:samp', '//xhtml:kbd', '//xhtml:mark', '//xhtml:bdi', '//xhtml:bdo', '//xhtml:wbr', '//xhtml:track', '//xhtml:button', '//xhtml:datalist', '//xhtml:output', '//xhtml:detail', '//xhtml:summary', '//xhtml:command', '//xhtml:menu' ); #ループまわしてテキストノードのテキスト部分を置換 foreach $tagName(@tags){ foreach $tagNode($xc->findnodes($tagName)){ my @childnodes = $tagNode->childNodes(); foreach $eachnode(@childnodes){ #テキストノードかどうか判定して置換を実行 $type = $eachnode->nodeType; if ($type == 3){ my $originTextContentsData = $eachnode->data; #サブルーチンに飛ばして置換処理実行 my $replacedTextContentsData = & textReplace ($originTextContentsData); $eachnode->setData( $replacedTextContentsData ); } } } } #####シリアライズしてヘッダくっつける##### my $htmls = $xc->findnodes('//xhtml:html'); $serializedTxt = $$htmls[0]->serialize; my $mergedTxt = '<?xml version="1.0" encoding="UTF-8"?>' . "\x0A" . '<!DOCTYPE html>' . "\x0A" . $serializedTxt; #####出力##### $mergedTxt = encode('UTF-8', $mergedTxt); open(OUT,"> $convertXhtmlFilePath"); print OUT $mergedTxt; close (OUT); exit; |
外部置換用ファイルは以下のような感じ。
1 2 3 4 5 6 7 8 9 10 11 |
#! /usr/bin/perl use utf8; sub textReplace { #置換テキストの取得 $_ = $_[0]; ######################↓↓↓ここに置換内容を記述↓↓↓###################### s/サンプル/さんぷる/g; ######################↑↑↑ここに置換内容を記述↑↑↑###################### return $_; } 1; |
いやあ長年作りたかったんですよこういうの。こないだやっとパーサーモジュールでDOM飼い慣らせたんで作れましたよ。うれしい。
(2017.10.20)