web-dev-qa-db-ja.com

PostgreSQLでxmlタグの値を抽出しています

以下は私のPostgresテーブルからの列の応答です。 Postgresデータベースのすべての行からステータスを抽出したいと思います。ステータスはSUCCESSのようにさまざまなサイズになる可能性があるため、部分文字列関数は使用しません。それを行う方法はありますか?

<?xml version="1.0" ?><response><status>ERROR_MISSING_DATA</status><responseType>COUNTRY_MISSING</responseType><country_info>USA</country_info><phone_country_code>1234</phone_country_code></response>

だから私のテーブル構造はこんな感じ

   Column    |            Type             |                        Modifiers                         

-------------+-----------------------------+----------------------------------------------------------

 id          | bigint                      | not null default nextval('events_id_seq'::regclass)
 hostname    | text                        | not null
 time        | timestamp without time zone | not null
 trn_type    | text                        | 
 db_ret_code | text                        | 
 request     | text                        | 
 response    | text                        | 
 wait_time   | text                        | 

そして、すべてのリクエストからステータスを抽出したいと思います。どうすればよいですか?

以下はサンプル行です。そして、テーブル名abc_eventsを想定します

id          | 1870667
hostname    | abcd.local
time        | 2013-04-16 00:00:23.861
trn_type    | A
request     | <?xml version="1.0" ?><response><status>ERROR_MISSING_DATA</status><responseType>COUNTRY_MISSING</responseType><country_info>USA</country_info><phone_country_code>1234</phone_country_code></response>
response    | <?xml version="1.0" ?><response><status>ERROR_MISSING_DATA</status><responseType>COUNTRY_MISSING</responseType><country_info>USA</country_info><phone_country_code>1234</phone_country_code></response>
11
ronak

xpath() 関数を使用します。

_WITH x(col) AS (SELECT '<?xml version="1.0" ?><response><status>ERROR_MISSING_DATA</status></response>'::xml)
SELECT xpath('./status/text()', col) AS status
FROM   x
_

/text()は、周囲の_<status>_タグを削除します。
この場合、単一の要素を持つxmlの配列を返します。

_status
xml[]
-------
{ERROR_MISSING_DATA}
_

あなたのテーブルに適用されます

質問の更新に応じて、これは単純に次のようになります。

_SELECT id, xpath('./status/text()', response::xml) AS status
FROM   tbl;
_

行ごとにステータスタグが1つしかないことが確実な場合は、配列から最初の項目を抽出するだけです。

_SELECT id, (xpath('./status/text()', response::xml))[1] AS status
FROM   tbl;
_

複数のステータス項目が存在する可能性がある場合:

_SELECT id, unnest(xpath('./status/text()', response::xml)) AS status
FROM   tbl;
_

idごとに1-n行を取得します。

xmlにキャスト

列をタイプtextxml の代わりに)に定義したので、あなたは明示的にxmlにキャストする必要があります。関数xpath()はタイプxml。型指定されていない文字列定数は自動的にxmlに強制されますが、text columnは強制されません。明示的にキャストします。

これは明示的なキャストなしで機能します。

_  SELECT xpath('./status/text()'
      ,'<?xml version="1.0" ?><response><status>SUCCESS</status></response>')
_

[〜#〜] cte [〜#〜]私の最初の例のようににはタイプが必要です 「共通テーブル式」のすべての列に対して。特定の型にキャストしていなかった場合、型unknownが使用されていたでしょう-これはnotと同じものではありません型なし文字列。明らかに、unknownxmlの間に直接変換は実装されていません。最初にtextにキャストする必要があります:_unknown_type_col::text::xml_。すぐに_::xml_にキャストすることをお勧めします。

これはPostgreSQL9.1で強化されています(私は思います)。古いバージョンはより寛容でした。

いずれにせよ、これらのメソッドのいずれかを使用する場合、文字列は有効なxmlである必要があります。そうでない場合、キャスト(暗黙的または明示的)によって例外が発生します。

16