實戰演練:無名 blog 資料移轉
雖然無名的 blog 服務,一直都沒有做得很好,不過寶貝還是不願意撤離無名,直到這次參加 OSDC.tw,寶貝很興奮地寫了一大篇文章,結果發表時,無名卻把文章藏了一個晚上才出現,這才讓寶貝同意放棄無名。所以就用超快速度,申請了 domain name,架了個 wordpress 給寶貝用。Wordpress 可以在後台 import RSS,所以接下來的問題,就是如何把無名 blog 裡的資料,以 RSS 格式弄下來了。
之前 gslin 有弄一個無名備份的服務,不過可能也是因為鳥蛋 MySQL 的 utf-8 問題的緣故,提供服務的那個網站已經連不到了。還好,隱約中有印象,該程式已經進 OpenSVN 了,所以就去那邊找。不過卻被 OpenSVN 的首頁搞迷糊了,只有讓人申請的頁面,完全找不到 hosted projects 的列表,這個站到底可以幹嘛,實在讓我搞不清楚。
所以只好再請出 Google 大神,試了很多組關鍵字,總算以「opensvn backup trac wretch blog」這五個關鍵字,撈出了在 blogspot 的《無名小站相簿備份服務》這篇文章,這才找到 OpenSVN 上的 Backup project 的鍊結。這實在是太曲折了啊,OpenSVN 有必要這麼講不清楚,說不明白嗎?實在是令我無法理解。
總之,找到主網頁後就好辦了,但又發現個問題,從 Backup project 的站上,完全找不到 repository 的 URL 要怎麼寫。只好亂猜一通,還好最後還是又被我猜到了,用以下的指令,即可下載最新版的 Backup project 的程式碼。
SHELL> svn checkout https://opensvn.csie.org/backup gslin-backup
裡面的 blog/wretch 目錄下,就有可以用來備份無名的程式。除了介紹用的 index.html 外,另外有兩組程式,皆是由一個負責前端的 php 檔和一個負責後端實際工作的 perl 檔組成。主檔名為 rss20-wretchblog 的這組,是用來將 RSS 檔裡的文章,「發表」到無名 blog 上的,因此使用時,需要用到無名的帳號與密碼。主檔名為 wretchblog-rss20 的這組,則剛好相反,是用來把無名 blog 上的文章,「備份」下來成為一個 RSS 2.0 的檔案,由於只需要抓資料,所以這一組只需要無名的帳號即可。由於懶得弄前端,所以研究了一下,確認只要使用以下的指令,就可以將寶貝在無名的 blog,完整備份下來:
SHELL> wretchblog-rss20.pl afoofa > afoofa-wretch.xml
資料抓下來後,先檢視一下,結果發現 <pubdate> 裡都是空的。追了一下,原來是抓文章時間的 regex,可能是因為模版不同的關係,寫得並不對。按照以下修改,即可修正:
Index: wretchblog-rss20.pl
===================================================================
--- wretchblog-rss20.pl (revision 101)
+++ wretchblog-rss20.pl (working copy)
@@ -119,7 +119,7 @@
my $month = $1;
my $year = $3 % 100;
- if ($body =~ /<div\s+class="posted">.*(\d+):(\d+)\s*(\w+)\s*發表/is) {
+ if ($body =~ /<div\s+class="posted">.* at (\d+):(\d+)\s*(\w+)\s*/is) {
my $tmp = sprintf("%02d %.3s %02d %02d:%02d:00 CST", $day, $month, $year, $1 + ($3 eq 'PM' ? 12 : 0), $2);
my $unixtime = str2time($tmp);
修改之後,<pubdate> 就可以正確抓出來了。至此,我很高興地就把備份下來的資料,import 進寶貝的 wordpress 了。可惜,最後還是棋差一著,寶貝跟我說,有些表情符號爛掉了。>.< 的 < 不見了。檢查了一下程式碼,發現是由最後面的 xmlencode() 這個 subroutine 負責將欄位裡的 HTML entities 編碼,這個 subroutine 是這樣子寫得:
sub xmlencode($)
{
my $str = shift();
$str =~ s/</</g;
$str =~ s/&/&/g;
return $encoded;
}
唉呀呀,這真是偷懶的寫法啊。先別說整套 HTML entities 只處理了兩個,程式的邏輯也不對。碰到 < 會先被轉成 <,然後又接著會被轉成 &lt;,這根本就不對了,第二次轉換不應該發生。但因為很晚了,所以就懶得弄了,寶貝的新 blog 直接開張。
Index: wretchblog-rss20.pl
===================================================================
--- nbsp;wretchblog-rss20.pl (revision 101)
+++ wretchblog-rss20.pl (working copy)
@@ -136,9 +136,24 @@
sub xmlencode($)
{
my $str = shift();
+ my $encoded = '';
+ while ($str =~ m/[<>&]/o) {
+ $encoded .= $`;
+ if ($& eq '<') {
+ $encoded .= '<';
+ }
+ elsif ($& eq '>') {
+ $encoded .= '>';
+ }
+ elsif ($& eq '&') {
+ $encoded .= '&';
+ }
+ else {
+ $encoded .= $&;
+ }
+ $str = $';
+ }
- $str =~ s/</</g;
- $str =~ s/&/&/g;
+ return $encoded;
+}
- return $str;
-}
剛剛想,總該還是要處理一下才對,所以又做了一下上面列出的 patch,只掃過輸入值一次就好,並補上另一個較常見的 >,以避免 import 到 wordpress時,又被 wordpress 弄爛。在 wordpress 裡,是使用 wp-admin/import/rss.php 這個檔案,來處理 RSS 的 import,裡面的 class RSS_Import 的 unhtmlentities(),就是用來逆轉 HTML entities 以轉換回原來的字元用的。這個函式用的是 PHP 提供的 HTML_ENTITIES 表格,應該所有 HTML entities 都齊備了。理論上,修改 xmlencode() 時,我也應該要把整套 HTML entities 都補上,以對應 wordpress 的 import,但因為其實大部分都不常用到,所以最後我還是只轉了 <、> 和 & 這三個字元而已。
測試了一下,結果正如所願,因此回報 Backup project 寫了這個 ticket:Wrong regex order in xmlencode()[1]。
- 竟然是第一個 ticket。 ↩



One Comment
OpenSVN 本來就是單純的 repository provider ,就像是一台 pure (連 port 80 都沒開) 的 cvs server 。 OpenSVN 並沒有義務需要幫忙宣傳或是告知有什麼 project 在這裡 - 這些應該是該個 project 自己該做的事情,而不是 OpenSVN 。
2 Backlinks
恐怖遊戲又一彈實戰演練:無名 blog 資料移轉
or a character reference when it appears in the string “]]>” in content, when that string is not marking the end of a CDATA section. 不過當初沒有管到 ‘>’ 這個,再加上置換的順序錯了,於是就爛了:實戰演練:無名 blog 資料移轉。
Post a Comment