« 昨日の友は今日の敵?・・・・狭いね、この業界も! #2 | トップページ | Mac De PL/SQL RSS Reader #2 »

2006年8月 6日 (日) / Author : Hiroshi Sekiguchi.

Mac De PL/SQL RSS Reader #1

Mac De Oracle、久々の投稿です。前回までの騒ぎはなんとか収束。(あとはベンダーさん次第。。)

ということで、以前から読んでいるこのブログの記事にあるPL/SQLでRSS Reader!
そのネタの一部?!を試してみようと思う。まず、手始めに一番気になっているエンコーディングの部分から始めることにする。

環境は、 いつもの Oracle10g R1 EE for MacOSX Serverを利用する。(インストール方法などは、こちらを参考にしてください。
尚、MacOS Xは、以下のように現在の最新版を利用している。なお、データベースキャラクタセットは、JA16SJISTILDEである。

Os

RSS Readerの実験に利用するBlogは、私の友人であるmegawattさんのサイトを利用させて頂いた。(自分のブログである、Mac De OracleのRSSを利用していないのだが、理由は後日!)
megawattさんRSSのバージョンは、RSS 0.91RSS 1.0を提供しているが、当面はRSS 0.91で遊ぶことにする。

megawattさん、いろいろと試していたので、アクセスログがタップリ吐かれていると思いますが、DOS攻撃ではないのでご安心を! (^^;;;;;

さて、本題。
結果を先に書いておくと、Oracle10g R1のDBMS_XMLPARSERパッケージのXMLパーサーでRSS FeedのURLを直指定しパースした場合、マルチバイト文字は文字化した。(Oracle10g R2ではどうなのかは後日確認する予定)。 なんとかエンコーディングを指定できないものかと調べてみたが、Oracle10g R1のDBMS_XMLPARSERでは、XMLパーサーに対してエンコーディングを指定することはできないようだ。(マニュアルをざっと読んでみたが、該当するプロシージャもファンクションも存在しない。)


以下は、Oracle10g R1 EE for MacOSX ServerのDBMS_XMLPARSERパッケージを利用してパース後、XMLDOMからRSSソースを取り出しリストした結果である。文字の化け方から想像すると、UTF-8をISO Latin 1としてエンコードしているのかもしれない。
尚、すべての操作はOracle SQL Developer 1.0を利用して行った。(便利なのだがMacOSXだと、debuggerの動作がかなり遅いかも。。実際にはdebuggerを起動しなくても試せるので問題は無かったのだが。。)


_1 _2

_3 _4



データベースOracle10g R1 glasscatfishに接続中です。
begin...
DBMS_XMLPARSERバージョン:10.1.0.2.0
DBMS_XMLDOMバージョン :1.0
=== パース済みDOMから取得したRSSソース ===
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE rss PUBLIC "-//Netscape Communications//DTD RSS 0.91//EN"
"http://my.netscape.com/publish/formats/rss-0.91.dtd">
<rss version="0.91">
<channel>
<title>a?!a?¬a??e≪?</title>
<link>http://megawatt.blogdns.net/blog</link>
<description>A Weblog Product for Zope</description>

<item>
<title>c??a??a??e?oao?a??a??a?≪e!?a?£a?|a??a??</title>
<link>http://megawatt.blogdns.net/blog/252</link>
</item>

<item>
<title>e??a?aa??a?¨a??a? ̄e??a?aa?? Part2</title>
<link>http://megawatt.blogdns.net/blog/251</link>
</item>

<item>
<title>e??a?aa??a?¨a??a? ̄e??a?aa??</title>
<link>http://megawatt.blogdns.net/blog/250</link>
</item>

<item>
<title>a??a??a??a??a??a??</title>
<link>http://megawatt.blogdns.net/blog/249</link>
</item>

<item>
<title>c?≪a?Ra??a??a?Ra??c??e¬?ao§i??2006a1´ao|a??a??a?≫i??</title>
<link>http://megawatt.blogdns.net/blog/248</link>
</item>

<item>
<title>a? ̄a??a?3100mla??80a?-a?-a?≪a?-a?aa??!!</title>
<link>http://megawatt.blogdns.net/blog/247</link>
</item>

<item>
<title>a? ̄a?£a?!a??a??a?§a? ̄a?aa??a? ̄a?£a?!a??a??</title>
<link>http://megawatt.blogdns.net/blog/246</link>
</item>


<item>
<title>a?!a??a?£a?¨a??eμ°a?£a?|a??</title>
<link>http://megawatt.blogdns.net/blog/245</link>
</item>

<item>
<title>a??a??a??a??a??a?,a??</title>
<link>http://megawatt.blogdns.net/blog/244</link>
</item>

<item>
<title>c?≪a??a??a?? ate??a??a≫2c?o</title>
<link>http://megawatt.blogdns.net/blog/243</link>
</item>

<item>
<title>c?≪a??a??a?£a??a?¥</title>
<link>http://megawatt.blogdns.net/blog/242</link>
</item>

<item>
<title>a??e£2c?ca?aa?≪a?≪a??a??a??a???</title>
<link>http://megawatt.blogdns.net/blog/241</link>
</item>

<item>
<title>e??a??a≫2c?oa?≫a・±a・?a,?a??a??</title>
<link>http://megawatt.blogdns.net/blog/240</link>
</item>

<item>
<title>a??a??a??a??a??a??a??a??</title>
<link>http://megawatt.blogdns.net/blog/239</link>
</item>

<item>
<title>c?-a-?c?±</title>
<link>http://megawatt.blogdns.net/blog/238</link>
</item>

<item>
<title>a??a??a??a??a??a??a?aa??a?§</title>
<link>http://megawatt.blogdns.net/blog/237</link>
</item>

</channel>
</rss>
====================
...End
プロセス終了。
データベースOracle10g R1 glasscatfishから切断中です。

以下は、AMIS Technology Blogのサンプルコードを参考にして作成したプロシージャのソースである。
URLで指定されたRSSソースをDBMS_XMLPARSERパッケージのXMLパーサーでパースし、生成されたXMLDOMオブジェクトからRSSソースをリストするしている。


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;

-- XMLDOM
v_rssDoc DBMS_XMLDOM.DomDocument;

-- for UTL_HTTP
v_req UTL_HTTP.REQ;
v_resp UTL_HTTP.RESP;
v_source VARCHAR2(1024);

-- RSSソース用CLOB(SYS.XMLTYPE型にしたほうがよかったかもしれないが、現時点ではCLOBで!)
v_tempClob CLOB;

--========== Internal PROCEDUREs/FUNCTIONs ===================================
--
--****************************************************************************
--* VARCHAR2の文字列を最大で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(
'println(VARCHAR2) internal procedure:'
|| sqlerrm()
);
RAISE;
END println;

--****************************************************************************
--* CLOBの文字列を最大で255文字または、改行コード毎にプリントする内部プロシージャ
--****************************************************************************
--
PROCEDURE println
(
i_text IN CLOB
)
IS
v_src CLOB;
v_tempStr CLOB;
BEGIN
v_src := i_text;
IF INSTR(v_src, UTL_TCP.CRLF) = 0 THEN
v_src := REPLACE(v_src, '><', '>'||UTL_TCP.CRLF||'<');
END IF;

v_tempStr := SUBSTR(v_src, 1, INSTR(v_src, UTL_TCP.CRLF)-1);
v_src := TRIM(LEADING UTL_TCP.CRLF FROM SUBSTR(v_src, INSTR(v_src, UTL_TCP.CRLF)));

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;
v_tempStr := SUBSTR(v_src, 1, INSTR(v_src, UTL_TCP.CRLF)-1);
v_src := TRIM(LEADING UTL_TCP.CRLF FROM SUBSTR(v_src, INSTR(v_src, UTL_TCP.CRLF)));
END LOOP;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(
'println(CLOB) internal procedure:'
|| sqlerrm()
);
RAISE;
END 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_myParser := DBMS_XMLPARSER.NEWPARSER();
DBMS_XMLPARSER.PARSE(v_myParser, v_url);
v_rssDoc := DBMS_XMLPARSER.GETDOCUMENT(v_myParser);
DBMS_LOB.CREATETEMPORARY(v_tempClob, FALSE);
DBMS_XMLDOM.WRITETOCLOB(v_rssDoc, v_tempClob);
println('DBMS_XMLPARSERバージョン:'||DBMS_XMLPARSER.GETRELEASEVERSION());
println('DBMS_XMLDOMバージョン :'||DBMS_XMLDOM.GETVERSION(v_rssDoc));
println(' ');
println('=== パース済みDOMから取得したRSSソース ===');
println(v_tempClob);
println('====================');
println(' ');
DBMS_LOB.FREETEMPORARY(v_tempClob);

DBMS_XMLPARSER.FREEPARSER(v_myParser);

println('...End');

EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(
'Main Procedure:'
|| sqlerrm()
);
RAISE;

END RSS_FEED_READER;


次回は、RSSをパースする際、RSS FEEDのURLを直指定したパースではなく、一旦、UTL_HTTPパッケージを利用してRSSを取得、CLOB変換する。そのCLOBをDBMS_XMLPARSERパッケージのパーサーでパースし、結果を確認してみることにする。
(ちなみに、WindowsのOracle10g R2 EEではXMLDOMが修正されたのか、DBMS_XMLPARSERパッケージかDBMS_XMLDOMパッケージが改良されたのか?。異なる結果をしてしている。それに関しては別記事にて書く予定)


今聞いている曲:
Dave Koz - Lucky Man Dave Koz - The Dance Richard Elliot - Metro Blue

| |

トラックバック


この記事へのトラックバック一覧です: Mac De PL/SQL RSS Reader #1:

コメント

コメントを書く