XML数据到PostgreSQL数据库[已关闭]

ee7vknir  于 2022-11-23  发布在  PostgreSQL
关注(0)|答案(3)|浏览(151)

已关闭。此问题需要更多focused。当前不接受答案。
**想要改进此问题吗?**更新问题,使其仅关注editing this post的一个问题。

两年前就关门了。
机构群体在6天前审核了是否重新讨论此问题,并将其关闭:
原始关闭原因未解决
Improve this question
将XML数据(从网页中获取)插入PostgreSQL数据库的最佳方法是什么?
我正在使用Java,需要一点帮助来找到一个好的方法来将这些数据读入数据库。

rbl8hiat

rbl8hiat1#

我有一个工作实现,我在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()overloaded版本。使用第三个参数,你可以选择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'

电话:

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;

重要说明

  • 如果插入的行已经存在,此实现将检查主键,并且在这种情况下更新。只插入新行。
  • 我使用了临时临时表来加快过程。
  • 使用Postgres8.49.09.1进行测试。
  • XML必须是格式良好的。
  • pg_read_file()对其有限制。手册:

这些功能仅限超级用户使用。
还有:
只能访问数据库集群目录和log_directory中的文件。
所以你必须把你的源文件放在那里--或者创建一个到你实际的文件/目录的符号链接。

或者在您的情况下,您可以通过Java提供文件(我在Postgres中完成了所有操作)。
或者您可以将数据导入临时表的1行1列中,然后从该表中提取数据。
或者您可以使用lo_import,如dba. SE上的相关答案中所示。

这个博客post by Scott Bailey帮助了我。

a14dhokn

a14dhokn2#

波斯特格雷斯(感谢丹尼尔指出)native XML support,您可以使用它来存储表。但是,如果您希望手动分解XML数据,则有不同的方法可以在数据库中表示XML数据。第一个问题应该是,如果您想要一个非常通用的解决方案,能够存储任何XML文档或特定于您域的文档(即只允许特定结构的XML文档)。基于此,您将拥有一个非常灵活、然而更难查询的通用表示(所需的SQL将相当复杂)。如果您有更具体的方法,查询将更简单,但每次要存储另一种类型的文档或向现有文件;因此更改模式将更加困难(这是XML的一个主要优点)。This presentation应该给予您了解不同的可能性。
此外,您可能会考虑改用支持XQuery的数据库,如DB2。使用XQuery(一种旨在处理XML的语言)进行本地查询的能力将大大简化事情。
UPDATE:给出注解后,XML数据(即you linked to)是完全相关的。它可以1:1Map到下表:

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,没有自然主键,所以我添加了一个自动生成的主键。

xfyts7mz

xfyts7mz3#

PostgreSQL有一个XML datatype。有很多XML specific functions你可以用来查询和修改数据,比如用xpath。
从Java的Angular 来看,您可以假装您只是在处理字符串,但要知道数据在输出时是格式良好的,它不会让您存储非格式良好的数据。

相关问题