如何在Postgres中将XML转换为JSONB

时间:2016-07-01 10:06:24

标签: xml postgresql jsonb

我有一个表Table1,其中包含XML data type列,ColumnA和另一个JSONB列ColumnB

如何将数据从ColumnA转换为ColumnB,大概使用SQL UPDATE语句。 Postgres中是否有内置函数来执行此操作?

1 个答案:

答案 0 :(得分:4)

据我所知,没有开箱即用的功能。

尝试:

create or replace function xml_to_json(p_xml xml) returns jsonb as $$
declare
  result json;
  root text;
  childs jsonb;
  attr jsonb;
  txt text;
begin
  -- Get root element name
  select (xpath('name(/*)', p_xml))[1]::text into root;

  -- Process child nodes
  select json_agg(xml_to_json(z))
  from unnest(xpath('/'||root||'/*', p_xml)) with ordinality as c(z,i)
  into childs;

  -- Read attributes
  select jsonb_agg(jsonb_build_object((xpath('name(/'||root||'/@*['||i||'])', p_xml))[1]::text, v))
  from unnest(xpath('/'||root||'/@*', p_xml)::text[]) with ordinality as a(v,i) 
  into attr;

  -- Read text
  select (xpath('/'||root||'/text()', p_xml))[1]::text into txt;

  -- Build object
  result := jsonb_build_object(root, jsonb_build_object('attr', attr, 'text', txt, 'childs', childs));
  return result;
end $$ language plpgsql immutable;

测试:

with t(x) as (values
('<root bar="foo" name="test" foo="bar">
  <aaa bbb="111">
    foo
    bar
  </aaa>
  <bbb>
    <ccc>222</ccc>
  </bbb>
</root>'::xml),
('<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book>
    <title lang="en">Harry Potter</title>
    <price>29.99</price>
  </book>
  <book>
    <title lang="en">Learning XML</title>
    <price>39.95</price>
  </book>
</bookstore>'))
select jsonb_pretty(xml_to_json(x)) from t;

输出:

                      jsonb_pretty                       
---------------------------------------------------------
 {                                                      +
     "root": {                                          +
         "attr": [                                      +
             {                                          +
                 "bar": "foo"                           +
             },                                         +
             {                                          +
                 "name": "test"                         +
             },                                         +
             {                                          +
                 "foo": "bar"                           +
             }                                          +
         ],                                             +
         "text": "\n  ",                                +
         "childs": [                                    +
             {                                          +
                 "aaa": {                               +
                     "attr": [                          +
                         {                              +
                             "bbb": "111"               +
                         }                              +
                     ],                                 +
                     "text": "\n    foo\n    bar\n  ",  +
                     "childs": null                     +
                 }                                      +
             },                                         +
             {                                          +
                 "bbb": {                               +
                     "attr": null,                      +
                     "text": "\n    ",                  +
                     "childs": [                        +
                         {                              +
                             "ccc": {                   +
                                 "attr": null,          +
                                 "text": "222",         +
                                 "childs": null         +
                             }                          +
                         }                              +
                     ]                                  +
                 }                                      +
             }                                          +
         ]                                              +
     }                                                  +
 }
 {                                                      +
     "bookstore": {                                     +
         "attr": null,                                  +
         "text": "\n  ",                                +
         "childs": [                                    +
             {                                          +
                 "book": {                              +
                     "attr": null,                      +
                     "text": "\n    ",                  +
                     "childs": [                        +
                         {                              +
                             "title": {                 +
                                 "attr": [              +
                                     {                  +
                                         "lang": "en"   +
                                     }                  +
                                 ],                     +
                                 "text": "Harry Potter",+
                                 "childs": null         +
                             }                          +
                         },                             +
                         {                              +
                             "price": {                 +
                                 "attr": null,          +
                                 "text": "29.99",       +
                                 "childs": null         +
                             }                          +
                         }                              +
                     ]                                  +
                 }                                      +
             },                                         +
             {                                          +
                 "book": {                              +
                     "attr": null,                      +
                     "text": "\n    ",                  +
                     "childs": [                        +
                         {                              +
                             "title": {                 +
                                 "attr": [              +
                                     {                  +
                                         "lang": "en"   +
                                     }                  +
                                 ],                     +
                                 "text": "Learning XML",+
                                 "childs": null         +
                             }                          +
                         },                             +
                         {                              +
                             "price": {                 +
                                 "attr": null,          +
                                 "text": "39.95",       +
                                 "childs": null         +
                             }                          +
                         }                              +
                     ]                                  +
                 }                                      +
             }                                          +
         ]                                              +
     }                                                  +
 }
(2 rows)