XML数据到PostgreSQL数据库

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

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

此外,您可能会考虑切换到某些支持Xquery的数据库,例如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 ) 

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

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

辅助解析function

 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 STRICT; 

处理多个

上述实现不会在一个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 IMMUTABLE STRICT; 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 ; 拘谨。 key: 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 max. 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 VOLATILE; 

重点:

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

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

  • pg_read_file()对它有限制。 我引用手册 :

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

    和:

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

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

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

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

或者您可以使用lo_import就像在dba.SE上的相关答案中所示 。

  • 使用Postgres 8.4,9.09.1进行测试

  • XML必须格式良好。

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

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

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