28 March 2013

MovableTypeの「改行を変換する」でコード記述部分まで変換されたのを自動修正する

MovableTypeで「改行を変換する」オプションを選択すると、 <pre> の間にある文章(ソースコード記述)まで“改行変換”されて表示がおかしくなる。

※ 「改行を変換する」オプションは標準設定値のため、特に明示しなければこのオプションで構築しているはず…

MovableTypeのデータベースファイルを直接開いて、一括して修正するスクリプトを作成した。(この修正後、MovableTypeの管理画面で“全て再構築”すれば、作業完了する)

■ MovableTypeでの記述例と表示サンプル

(1)改行だけの行が存在する場合

<div class="code"> #!/usr/bin/perl use warnings; use strict; use DBI; use HTML::Entities; my $dbh = undef; </div>

このソースコードをMovableTypeで「改行を変換する」をONにして変換(構築)すると

<div class="code"> <p>#!/usr/bin/perl</p> <p>use warnings;<br /> use strict;<br /> use DBI;<br /> use HTML::Entities;</p> <p>my $dbh = undef;<br />

20130328-mt-wospace.jpg
表示サンプル

(2)改行だけの行に1この空白文字を付加した場合

<div class="code"> #!/usr/bin/perl use warnings; use strict; use DBI; use HTML::Entities; my $dbh = undef; </div>

このソースコードをMovableTypeで「改行を変換する」をONにして変換(構築)すると

<div class="code"> #!/usr/bin/perl use warnings; use strict; use DBI; use HTML::Entities; my $dbh = undef;

20130328-mt-wspace.jpg
表示サンプル

■ MovableTypeの全エントリを一括修正するPerlスクリプト

MovableTypeのデータベースを直接開いて修正する。このサンプルスクリプトは、SQLite3のデータベースファイル mtdata.sqliteの存在するディレクトリで実行すると仮定している。

mt_fix_entry_code.plをダウンロードする(<div class="code"> 〜 </div> 版)

#!/usr/bin/perl use warnings; use strict; use DBI; use HTML::Entities; my $dbh = undef; my $sth = undef; my $strQuery = ""; my $strTmp = ""; my $strDsn = 'DBI:SQLite:dbname=./mtdata.sqlite'; # DSN my @arr_entry = (); # 修正すべきentry_id eval{ # DBに接続 $dbh = DBI->connect($strDsn, "", "", {PrintError => 1, AutoCommit => 0}); if(!$dbh) { die();} # データを読み込む $strQuery = "select entry_id,entry_text,entry_text_more from mt_entry where entry_text like '%\"code\"%' or entry_text_more like '%\"code\"%'"; $sth = $dbh->prepare($strQuery); if($sth){ $sth->execute();} my $counter = 0; while(my $arrData = $sth->fetchrow_arrayref()) { my ($id, $text, $text_more) = @$arrData; my @arr_textline = split(/\n/, $text."\n".$text_more); my $flag_incode = 0; foreach my $text_line (@arr_textline) { chomp $text_line; if($text_line =~ m/class\s*=\s*"code"/){ $flag_incode = 1; } if($flag_incode && $text_line =~ m/<\/div>/){ $flag_incode = 0; } if(length($text_line)<=0 && $flag_incode){ push(@arr_entry, $id); $counter++; last; } } } if($sth){ $sth->finish();} print "found ".$counter."topics\n"; foreach my $id (@arr_entry) { print $id." ..."; # 指定されたentry_idが複数ないか、データ件数を確認する $strQuery = "select count(*) from mt_entry where entry_id = ?"; $sth = $dbh->prepare($strQuery); $sth->bind_param(1, $id, DBI::SQL_INTEGER); if($sth){ $sth->execute();} my @arr = $sth->fetchrow_array(); if($sth){ $sth->finish();} if($arr[0] != 1){ print "count(entry_id=".$id.") = ".$arr[0]." , is not only one row\n"; last; } # 指定されたentry_idの内容を読み込む $strQuery = "select entry_id,entry_text,entry_text_more from mt_entry where entry_id = ?"; $sth = $dbh->prepare($strQuery); $sth->bind_param(1, $id); if($sth){$sth->execute();} my $arrData = $sth->fetchrow_arrayref(); if($sth){ $sth->finish();} my ($id, $text, $text_more) = @$arrData; # entry_textとentry_text_moreを修正する $text = fix_text($text); $text_more = fix_text($text_more); # 指定されたentry_idの内容を更新する $strQuery = "update mt_entry set entry_text = ?, entry_text_more = ? where entry_id = ?"; $sth = $dbh->prepare($strQuery); $sth->bind_param(1, $text, DBI::SQL_VARCHAR); $sth->bind_param(2, $text_more, DBI::SQL_VARCHAR); $sth->bind_param(3, $id, DBI::SQL_INTEGER); if($sth){$sth->execute();} if($sth){ $sth->finish();} print "\n"; } $dbh->commit(); # DBを閉じる $dbh->disconnect(); }; if($@){ # evalによるDBエラートラップ:エラー時の処理 $dbh->disconnect(); print("DBI error : ".$@."\n"); } exit(0); # # <div class="code"> 〜 </div> で囲まれた領域で改行のみの行に1文字分の空白を追加する # sub fix_text { my $text = shift; my @arr_textline = split(/\n/, $text); $text = ""; my $flag_incode = 0; foreach my $text_line (@arr_textline) { chomp $text_line; if($text_line =~ m/class\s*=\s*"code"/){ $flag_incode = 1; } if($flag_incode && $text_line =~ m/<\/div>/){ $flag_incode = 0; } if(length($text_line)<=0 && $flag_incode){ $text_line = " "; } $text .= ($text_line . "\n"); } return $text; }

■ コード記述のある記事のみを抜き出してHTML化するスクリプト

mt_export_entry_code.plをダウンロードする(<div class="code"> 〜 </div> 版)
mt_export_entry_pre.plをダウンロードする(<pre> 〜 </pre> 版)

#!/usr/bin/perl use warnings; use strict; # 変数の宣言を強制する use DBI; # DBI モジュールを利用する use HTML::Entities; my $dbh = undef; my $sth = undef; my $strQuery = ""; my $strTmp = ""; my $strDsn = 'DBI:SQLite:dbname=./mtdata.db'; # DSN print "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n". "<html>\n". "<head>\n". "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n". "<meta http-equiv=\"Content-Language\" content=\"ja\" />\n". "<style type=\"text/css\">\n". "<!--\n". "table, td, tr { border:solid 1px maroon;font-size:10px;border-collapse: collapse; }\n". "-->\n". "</style>\n". "<title></title>\n". "</head>\n". "<body>\n". "<table>\n"; eval{ # DBに接続 $dbh = DBI->connect($strDsn, "", "", {PrintError => 1, AutoCommit => 0}); if(!$dbh) { die();} # データを読み込む $strQuery = "select entry_id,entry_text,entry_text_more from mt_entry where entry_text like '%\"code\"%' or entry_text_more like '%\"code\"%'"; $sth = $dbh->prepare($strQuery); if($sth){ $sth->execute();} my $counter = 0; while(my $arrData = $sth->fetchrow_arrayref()) { $counter++; my ($id, $text, $text_more) = @$arrData; my @arr_textline = split(/\n/, $text."\n".$text_more); print "<tr><td>".$id."</td><td><pre>"; my $flag_incode = 0; foreach my $text_line (@arr_textline) { chomp $text_line; if($text_line =~ m/class\s*=\s*"code"/){ $flag_incode = 1; } if($flag_incode && $text_line =~ m/<\/div>/){ $flag_incode = 0; } if(length($text_line)<=0 && $flag_incode){ print "<span style=\"background-color:red;\"> </span>"; } if($flag_incode){ print "<span style=\"color:green;\">"; } print encode_entities($text_line, '&<>\\\"\''); if($flag_incode){ print "</span>"; } print "\n"; } print "</pre></td></tr>\n"; } if($sth){ $sth->finish();} # DBを閉じる $dbh->disconnect(); print "</table>\n". "<p>total count = ".$counter."</p>\n". "</body>\n". "</html>\n"; }; if($@){ # evalによるDBエラートラップ:エラー時の処理 $dbh->disconnect(); print("DBI error : ".$@."\n"); } exit(0);