在PostgreSQL中提取xml标记的值

ron*_*nak 11 xml postgresql xpath casting xml-parsing

下面是我的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>
Run Code Online (Sandbox Code Playgroud)

所以我的表格结构是这样的

   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                        | 
Run Code Online (Sandbox Code Playgroud)

我想从每个请求中提取状态.我该怎么做呢?

下面是一个示例行.并假设表名为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>
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 15

使用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
Run Code Online (Sandbox Code Playgroud)

/text()去除周围的<status>标签.
返回一个数组xml- 在这种情况下使用单个元素:

status
xml[]
-------
{ERROR_MISSING_DATA}
Run Code Online (Sandbox Code Playgroud)

适用于你的桌子

在回答您的问题更新时,这可能只是:

SELECT id, xpath('./status/text()', response::xml) AS status
FROM   tbl;
Run Code Online (Sandbox Code Playgroud)

如果您确定每行只有一个状态标记,则只需从数组中提取第一个项目:

SELECT id, (xpath('./status/text()', response::xml))[1] AS status
FROM   tbl;
Run Code Online (Sandbox Code Playgroud)

如果可以有多个状态项:

SELECT id, unnest(xpath('./status/text()', response::xml)) AS status
FROM   tbl;
Run Code Online (Sandbox Code Playgroud)

获得每个1-n行id.

演员 xml

既然你定义你的列是类型的text(而不是xml,你需要投以xml明确该功能xpath()预计类型的第二个参数xml.无类型的字符串常量强制为xml自动,但text不是.你需要显式转换.

这没有明确的演员:

  SELECT xpath('./status/text()'
      ,'<?xml version="1.0" ?><response><status>SUCCESS</status></response>')
Run Code Online (Sandbox Code Playgroud)

CTE像在我的第一个例子需要在"公用表表达式"每一列类型.如果我没有投给一个特定的类型,类型unknown将被使用-这是一样的东西作为一个无类型的字符串.显然,在unknown和之间没有实现直接转换xml.你必须先铸造text:unknown_type_col::text::xml.最好立即施展::xml.

这已经与PostgreSQL 9.1(我认为)收紧了.旧版本更宽松.

无论哪种方式,使用任何这些方法,字符串必须是有效的xml,或者强制转换(隐式或显式)将引发异常.