Mac De PL/SQL RSS Reader #3 Tweet
前回のつづきです。
さて、文字化けを回避する方法はないかと考えてみた。
URL指定で、Oracle10g R1のDBMS_XMLPARSERパッケージのパーサーでパースする場合、裏で行われて言うHTTPで正しくエンコーディングされていないのが原因でだろうと考え、試しにUTL_HTTPパッケージを使いRSSソースを取得してみることにした。
尚、DBMS_XMLPARDERパッケージ、DBMS_XMLDOMパッケージ、UTL_HTTPパッケージ、UTL_TCPパッケージの詳細については、「PL/SQL パッケージ・プロシージャおよびタイプ・リファレンス」を参照のこと。
まずは、結果から。
以下のように、HTTPで取得したRSSを表示すると文字化けは発生しなかった。(思った通り!)
データベースOracle10g R1 glasscatfishに接続中です。<br>
begin...
====================
DBMS_XMLPARSERバージョン:10.1.0.2.0
DBMS_XMLDOMバージョン :
<rss version="0.91">
<channel>
<title>メガ放談</title>
<link>http://megawatt.blogdns.net/blog</link>
<description>A Weblog Product for Zope</description>
<item>
<title>亀田家親子夏休み日記</title>
<link>http://megawatt.blogdns.net/blog/253</link>
</item>
<item>
<title>社会保険事務所に行ってきた</title>
<link>http://megawatt.blogdns.net/blog/252</link>
</item>
<item>
<title>重なるときは重なる Part2</title>
<link>http://megawatt.blogdns.net/blog/251</link>
</item>
<item>
<title>重なるときは重なる</title>
<link>http://megawatt.blogdns.net/blog/250</link>
</item>
<item>
<title>うしろすがた</title>
<link>http://megawatt.blogdns.net/blog/249</link>
</item>
<item>
<title>猫のための写真講座/2006年度前期・4</title>
<link>http://megawatt.blogdns.net/blog/248</link>
</item>
<item>
<title>ワイン100mlが80キロカロリー!!</title>
<link>http://megawatt.blogdns.net/blog/247</link>
</item>
<item>
<title>はっちゃんではないはっちゃん</title>
<link>http://megawatt.blogdns.net/blog/246</link>
</item>
<item>
<title>ちょっと、走ってる</title>
<link>http://megawatt.blogdns.net/blog/245</link>
</item>
<item>
<title>命名、じみへん</title>
<link>http://megawatt.blogdns.net/blog/244</link>
</item>
<item>
<title>猫まんが at門前仲町</title>
<link>http://megawatt.blogdns.net/blog/243</link>
</item>
<item>
<title>猫を拾った日</title>
<link>http://megawatt.blogdns.net/blog/242</link>
</item>
<item>
<title>お飲物なににしますか?</title>
<link>http://megawatt.blogdns.net/blog/241</link>
</item>
<item>
<title>門前仲町・深川不動堂</title>
<link>http://megawatt.blogdns.net/blog/240</link>
</item>
<item>
<title>う〜ん、まずい。</title>
<link>http://megawatt.blogdns.net/blog/239</link>
</item>
<item>
<title>短歌熱</title>
<link>http://megawatt.blogdns.net/blog/238</link>
</item>
</channel>
</rss>
====================
...End
プロセス終了。<br>
データベースOracle10g R1 glasscatfishから切断中です。<br>
以下、変更後のプロシージャのソースを示す。
変更点は、
DBMS_XMLPARSERパッケージのパーサーで、URL直指定でパースするのではなく、HTTP経由でCLOBにRSSソースを取り込み、CLOBをパースするようにした。
XMLをプリントする内部プロシージャも変更し、println(CLOB)からxml_println(XMLTYPE)へ変更した。(XMLTYPEにしておいたほうがなにかと便利なので。尚、元ネタは、ここ)
CREATE OR REPLACE PROCEDURE RSS_FEED_READER
(
i_url IN VARCHAR2
)
AS
--============ TYPEs/VARIABLEs ===============================================
TYPE rss_type IS RECORD
(
title VARCHAR2(2000),
link VARCHAR2(200),
pubDate VARCHAR2(200),
category VARCHAR2(500),
description VARCHAR2(4000)
);
v_rss_item rss_type;
v_rss_empty_item rss_type; -- v_rss_item初期化用
v_url VARCHAR2(32767);
-- XML PARSER
v_myParser DBMS_XMLPARSER.Parser;
-- RSSまたは、ATOMフォーマットのDOM
v_rssDoc DBMS_XMLDOM.DomDocument;
-- for UTL_HTTP
v_req UTL_HTTP.REQ;
v_resp UTL_HTTP.RESP;
-- HTTP経由でRSS/ATOMソースを取り込むためのワーク
v_source VARCHAR2(1024);
v_tempSourceClob CLOB;
--========== Internal PROCEDUREs/FUNCTIONs ===================================
--
--****************************************************************************
--* VARCHAR2の文字列を最大で255文字または、改行コード毎にプリントする内部プロシージャ
--*
--* NOTE:
--* Oracle10g R2では、DBMS_OUTPUT.PUT_LINEプロシージャの255文字制限が緩和され32767文字まで出力できるようになるためがないため、
--* 255文字毎に分割出力する必要はなくなるなぁ。
--****************************************************************************
PROCEDURE println
(
i_text IN VARCHAR2
)
IS
v_src VARCHAR2(32767);
v_tempStr VARCHAR2(32767);
BEGIN
v_src := i_text;
IF INSTR(v_src, UTL_TCP.CRLF) <> 0 THEN
v_tempStr := SUBSTR(v_src, 1, INSTR(v_src, UTL_TCP.CRLF)-1);
v_src := SUBSTR(v_src, INSTR(v_src, UTL_TCP.CRLF)+LENGTH(UTL_TCP.CRLF));
ELSE
v_tempStr := v_src;
END IF;
WHILE v_tempStr IS NOT NULL LOOP
IF LENGTH(v_tempStr)> 255 THEN
FOR i IN 1..(TRUNC(LENGTH(v_tempStr)/255)+1) LOOP
DBMS_OUTPUT.PUT_LINE(SUBSTR(v_tempStr,1+ 255*(i-1),255));
END LOOP;
ELSE
DBMS_OUTPUT.PUT_LINE(v_tempStr);
END IF;
IF INSTR(v_src, UTL_TCP.CRLF) <> 0 THEN
v_tempStr := SUBSTR(v_src, 1, INSTR(v_src, UTL_TCP.CRLF)-1);
v_src := SUBSTR(v_src, INSTR(v_src, UTL_TCP.CRLF)+LENGTH(UTL_TCP.CRLF));
ELSE
EXIT;
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error Occured : println(VARCHAR2) internal procedure.');
DBMS_OUTPUT.PUT_LINE(sqlerrm());
RAISE;
END println;
--****************************************************************************
--* XMLTYPEに格納されたXMLソースをプリントする。
--* (Oracle10g R1だと、255文字毎の分割プリントは必要かも。。。未実装)
--*
--* NOTE:
--* Oracle10g R2では、DBMS_OUTPUT.PUT_LINEプロシージャの255文字制限がないため、
--*255文字毎に分割出力する必要はなくなる32767文字毎の分割出力でもOK.
--****************************************************************************
PROCEDURE xml_println
(
i_text IN XMLTYPE
)
IS
v_str LONG;
BEGIN
v_str := i_text.EXTRACT('/*').GETSTRINGVAL();
WHILE(v_str IS NOT NULL) LOOP
DBMS_OUTPUT.PUB_LINE(SUBSTR(v_str, 1, INSTR(v_str, CHR(10)) - 1));
v_str := SUBSTR(v_str, INSTR(v_str, CHR(10)) + 1);
END LOOP;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error Occured : xml_println(XMLTYPE) internal procedure.');
DBMS_OUTPUT.PUT_LINE(sqlerrm());
RAISE;
END xml_println;
--****************************************************************************
--* Main Procedure
--****************************************************************************
BEGIN
DBMS_OUTPUT.ENABLE(200000);
println('begin...');
v_url := i_url;
IF v_url IS NULL THEN
RAISE_APPLICATION_ERROR(-20000, 'URLを指定してください。');
END IF;
v_req := UTL_HTTP.BEGIN_REQUEST(v_url);
UTL_HTTP.SET_HEADER(v_req, 'User-Agent', 'Oracle UTL_HTTP/Oracle10g R1');
UTL_HTTP.SET_HEADER(v_req, 'Content-Type', 'text/xml;charset=UTF-8');
v_resp := UTL_HTTP.GET_RESPONSE(v_req);
-- RSSソースを一時CLOBへ書き出す
DBMS_LOB.CREATETEMPORARY(v_tempSourceClob, FALSE);
BEGIN
LOOP
UTL_HTTP.READ_LINE(v_resp, v_source, true);
-- 改行コード強制的に付加。
-- xml_println()でDBMS_OUTPUT.PUT_LINE()が、最大255文字までしか
-- 表示できないことへの一時的な対策。(試しているサイトについてはこれで
-- 回避できているので今のところはこのままで。)
v_source := v_source || UTL_TCP.CRLF;
DBMS_LOB.WRITEAPPEND(v_tempSourceClob, LENGTH(v_source), v_source);
END LOOP;
EXCEPTION
WHEN UTL_HTTP.END_OF_BODY THEN
UTL_HTTP.END_RESPONSE(v_resp);
END;
println('====================');
v_myParser := DBMS_XMLPARSER.NEWPARSER();
DBMS_XMLPARSER.PARSECLOB(v_myParser, v_tempSourceClob);
v_rssDoc := DBMS_XMLPARSER.GETDOCUMENT(v_myParser);
println('DBMS_XMLPARSERバージョン:'||DBMS_XMLPARSER.GETRELEASEVERSION());
println('DBMS_XMLDOMバージョン :'||DBMS_XMLDOM.GETVERSION(v_rssDoc));
println(' ');
xml_println(DBMS_XMLDOM.GETXMLTYPE(v_rssDoc));
println('====================');
println(' ');
DBMS_LOB.FREETEMPORARY(v_tempSourceClob);
DBMS_XMLPARSER.FREEPARSER(v_myParser);
println('...End');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error Occured : main procedure.');
DBMS_OUTPUT.PUT_LINE(sqlerrm());
RAISE;
END RSS_FEED_READER;
また、前述のようにした事で、Mac De Oracleなどで発生してたココログのATOM配信フォーマットのパースエラーも消えた!?(やはり文字化けが影響していたようだ。)
以下に、Mac De OracleのATOMを読み込んだOracle SQL Developer 1.0 for MacOSXのスナップショットを示す。
Oracle10g R1で、なんとか日本語対応のRSS Readerを作ることもできそうな感触。。。。Oracle10g R2は、MacOSX版がリリースされていないの(本当にリリースされるのか??)で、それまではLinux版のOracel10g R2で試してみるか。。。
今聞いている曲:
Malene Mortensen - Date with a Dream GENAI - HAEVEN OF EARTH
| 固定リンク | 0
コメント