« Mac De PL/SQL RSS Reader #2 | トップページ | Mac De PL/SQL RSS Reader #4 »

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

Mac De PL/SQL RSS Reader #3

前回のつづきです。
さて、文字化けを回避する方法はないかと考えてみた。
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のスナップショットを示す。


Jdevok

Oracle10g R1で、なんとか日本語対応のRSS Readerを作ることもできそうな感触。。。。Oracle10g R2は、MacOSX版がリリースされていないの(本当にリリースされるのか??)で、それまではLinux版のOracel10g R2で試してみるか。。。

今聞いている曲:
Malene Mortensen - Date with a DreamMalene Mortensen - デイト・ウィズ・ア・ドリーム GENAI - HAEVEN OF EARTHジェナイ - ヘブン・オン・アース

| |

トラックバック


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

コメント

コメントを書く