XML数据到PostgreSQL数据库

时间:2011-09-20 20:39:23

标签: java xml database parsing postgresql

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

3 个答案:

答案 0 :(得分: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;

处理多个

上述实现不能在一个xpath处理多个属性。这是f_xml_extract_val() one版本的all。使用第3个参数,您可以选择dist(第一个),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' SELECT f_xml_extract_val('//city', x, 'dist'); (不同)值。多个值聚合为逗号分隔的字符串。

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; ;拘谨。 key:pg_read_file()

log_directory

重要说明

  • 如果插入的行已经存在,则此实现会检查主键,在这种情况下,更新。只插入新行。

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

  • 使用Postgres 8.4 9.0 9.1 进行测试。

  • XML必须格式良好。

  • lo_import有限制。 overloaded

      

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

      

    只能访问数据库群集目录和{{1}}中的文件。

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

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

您可以将数据导入临时表的1行中的1列并从中获取。

您可以使用此The manual中演示的{{1}}。

此博客SQL to read XML from file into PostgreSQL database帮助了我。

答案 1 :(得分:9)

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

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

更新:鉴于您的评论,您的XML数据(you linked to)是完全相关的。它可以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      
)

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

答案 2 :(得分:6)

PostgreSQL有一个XML datatype。您可以使用许多XML specific functions来查询和修改数据,例如使用xpath。

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