XML数据到PostgreSQL数据库

kru*_*son 11 java xml database postgresql parsing

将XML数据(我从网页上获得)插入PostgreSQL数据库的最佳方法是什么?
我正在使用Java,需要一些帮助,找到一种将数据读入数据库的好方法.

Erw*_*ter 19

我有一个工作实现,我在PostgreSQL中做所有事情,没有额外的库.

辅助解析功能

CREATE OR REPLACE FUNCTION f_xml_extract_val(text, xml)
  RETURNS text AS
$func$
SELECT CASE
        WHEN $1 ~ '@[[:alnum:]_]+$' THEN
           (xpath($1, $2))[1]
        WHEN $1 ~* '/text()$' THEN
           (xpath($1, $2))[1]
        WHEN $1 LIKE '%/' THEN
           (xpath($1 || 'text()', $2))[1]
        ELSE
           (xpath($1 || '/text()', $2))[1]
       END;
$func$  LANGUAGE sql IMMUTABLE;
Run Code Online (Sandbox Code Playgroud)

处理多个

上述实现不会在一个xpath 处理多个属性.这是一个重载版本f_xml_extract_val().使用第3个参数,您可以选择one(第一个)alldist(不同)值.多个值聚合为逗号分隔的字符串.

CREATE OR REPLACE FUNCTION f_xml_extract_val(_path text, _node xml, _mode text)
  RETURNS text AS
$func$
DECLARE
   _xpath text := CASE
                   WHEN $1 ~~ '%/'              THEN $1 || 'text()'
                   WHEN lower($1) ~~ '%/text()' THEN $1
                   WHEN $1 ~ '@\w+$'            THEN $1
                   ELSE                              $1 || '/text()'
                  END;
BEGIN
   -- fetch one, all or distinct values
   CASE $3
       WHEN 'one'  THEN RETURN (xpath(_xpath, $2))[1]::text;
       WHEN 'all'  THEN RETURN array_to_string(xpath(_xpath, $2), ', ');
       WHEN 'dist' THEN RETURN array_to_string(ARRAY(
            SELECT DISTINCT unnest(xpath(_xpath, $2))::text ORDER BY 1), ', ');
       ELSE RAISE EXCEPTION
          'Invalid $3: >>%<<', $3;
   END CASE;
END
$func$  LANGUAGE plpgsql;

COMMENT ON FUNCTION f_xml_extract_val(text, xml, text) IS '
Extract element of an xpath from XML document
Overloaded function to f_xml_extract_val(..)
$3 .. mode is one of: one | all | dist'
Run Code Online (Sandbox Code Playgroud)

呼叫:

SELECT f_xml_extract_val('//city', x, 'dist');
Run Code Online (Sandbox Code Playgroud)

主要部分

目标表的名称:tbl; 拘谨.关键id:

CREATE OR REPLACE FUNCTION f_sync_from_xml()
  RETURNS boolean AS
$func$
DECLARE
   datafile text := 'path/to/my_file.xml';  -- only relative path in db dir
   myxml    xml  := pg_read_file(datafile, 0, 100000000); -- arbitrary 100 MB
BEGIN
   -- demonstrating 4 variants of how to fetch values for educational purposes
   CREATE TEMP TABLE tmp ON COMMIT DROP AS
   SELECT (xpath('//some_id/text()', x))[1]::text AS id   -- id is unique  
        , f_xml_extract_val('//col1', x)          AS col1 -- one value
        , f_xml_extract_val('//col2/', x, 'all')  AS col2 -- all values incl. dupes
        , f_xml_extract_val('//col3/', x, 'dist') AS col3 -- distinct values
   FROM   unnest(xpath('/xml/path/to/datum', myxml)) x;

   -- 1.) DELETE?

   -- 2.) UPDATE
   UPDATE tbl t
   SET   (  col_1,   col2,   col3) =
         (i.col_1, i.col2, i.col3)
   FROM   tmp i
   WHERE  t.id = i.id
   AND   (t.col_1, t.col2, t.col3) IS DISTINCT FROM
         (i.col_1, i.col2, i.col3);

   -- 3.) INSERT NEW
   INSERT INTO tbl
   SELECT i.*
   FROM   tmp i
   WHERE  NOT EXISTS (SELECT 1 FROM tbl WHERE id = i.id);
END
$func$  LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

重点:

  • 如果插入的行已经存在并且在这种情况下更新,则此实现检查主键.仅插入新行.

  • 我使用临时临时表来加快程序.

  • pg_read_file()有限制.我引用手册:

    这些功能的使用仅限于超级用户.

    和:

    只能访问数据库集群目录和log_directory中的文件.

因此,您必须将源文件放在那里 - 或者创建指向实际文件/目录的符号链接.

或者您可以在您的情况下通过Java提供文件(我在Postgres中完成了所有操作).

或者,您可以将数据导入临时表的1行的1列中,然后从那里获取.

或者,你可以使用log_directory像在此证明上dba.SE相关答案.

  • 经测试在Postgres 8.4,9.09.1.

  • XML必须格式良好.

这篇由Scott Bailey撰写的博客文章帮助了我.


Jan*_*net 9

Postgres(感谢Daniel Lyons指出)原生XML支持,您可以使用它来存储您的表.但是,如果您想手动粉碎XML数据,则可以在数据库中表示XML数据.第一个问题应该是,如果你想要一个非常通用的解决方案,它将能够存储任何XML文档或特定于你的域的文档(即只允许某种结构的XML文档).根据这一点,您将拥有一个非常灵活的通用表示,但是查询更难(所需的SQL将非常复杂).如果您有更具体的方法,查询将更简单,但每次要存储其他类型的文档或向现有文档添加字段时,您将需要创建新表或向现有的talbes添加新属性; 因此,更改架构将更加困难(这是XML的一个主要优势).本演示文稿应该为您提供一些不同的可能性.

此外,您可能会考虑切换到支持Xquery的某些DB,例如DB2.使用XQuery(一种用于处理XML的语言)进行本机查询的能力将大大简化事情.

更新:鉴于您的评论,您的XML数据(您链接到的)是完全相关的.它可以1:1映射到下表:

CREATE TABLE mynt (
    ID          SERIAL     ,
    myntnafn    CHAR(3)    ,
    myntheiti   Varchar(255) ,
    kaupgengi   Decimal(15,2) ,
    midgengi    Decimal(15,2) ,
    solugengi   Decimal(15,2) ,
    dagsetning  TimeStamp      
)
Run Code Online (Sandbox Code Playgroud)

因此,任何mynt标记都是表中的记录,相应的子标记属性.我从您的数据中收集的数据类型可能是错误的.主要的问题是,IMO,没有自然的主键,所以我添加了一个自动生成的键.

  • [PostgreSQL有本机XML支持](http://www.postgresql.org/docs/current/static/datatype-xml.html)[自8.2版本](http://www.postgresql.org/docs/8.2 /static/datatype-xml.html). (3认同)

Dan*_*ons 6

PostgreSQL有一个XML数据类型.您可以使用许多XML特定函数来查询和修改数据,例如使用xpath.

从Java方面来说,你可以假装你只是使用字符串,但是知道数据在出路时格式正确,它不会让你存储非格式良好的数据.