2

我正在将 mysql 数据库迁移到 postgres,并在一些基本的 xml 功能方面遇到了障碍。在 MySql 中,我有存储过程,它将替换 xml 文档中的节点,但在 postgres 中找不到任何方法。

这是我从mysql存储的过程:

CREATE DEFINER=`root`@`localhost` PROCEDURE `SP_UpdateExamFilesXmlNode`(examFileId int, xPathExpression varchar(128), xmlNode longtext)
BEGIN
    DECLARE xmlData longtext;
    DECLARE newXmlData longtext;
    DECLARE xmlNodeCount int;
    SET xmlData = NULL;
    SELECT xml_data INTO xmlData FROM sonixhub.exam_files WHERE id = examFileId;

    IF xmlData IS NOT NULL THEN
        -- check if the node already exists and if it does then simply update it
        SET xmlNodeCount = ExtractValue(xmlData, CONCAT('count(',xPathExpression,')'));
        IF xmlNodeCount > 0 THEN
            SET newXmlData = UpdateXML(xmlData, xPathExpression, xmlNode);
        -- if node doesn't exist then we have to add it manually
        ELSE
            SET newXmlData = REPLACE(xmlData, '</ImageXmlData>', CONCAT(xmlNode, '</ImageXmlData>'));
        END IF;
        UPDATE sonixhub.exam_files SET xml_data = newXmlData WHERE id = examFileId;
    ELSE
        -- there is no xml found so create xml from scratch and insert the node
        SET xmlData = CONCAT('<ImageXmlData>',xmlNode,'</ImageXmlData>');
        UPDATE sonixhub.exam_files SET xml_data = xmlData WHERE id = examFileId;
    END IF;
END

有没有办法在 postgres 函数中复制这个功能,而不是将逻辑移动到应用程序本身?

编辑 - 找到了我的问题的解决方案

我找到了一个混合使用 postgres xml 和字符串格式化函数的解决方案。

ExamFileId 用于查找要使用 xml 更新的行,使用您的表信息更改代码在我的情况下是硬编码的根节点,但您可以将其更改为您喜欢的任何内容。

以下是调用函数的方式:

-- this adds <DicomTags> node to your xml value in the table, if <DicomTags> already exists then it's replaced by the one passed in
select update_exam_files_xml_node(1, '/ImageXmlData/DicomTags', '<DicomTags><DicomTag>xxx</DicomTag></DicomTags>');

-- this adds <Settings> node to your xml value in the table, if <Settings> already exists then it's replaced by the one passed in
select update_exam_files_xml_node(1, '/ImageXmlData/Settings', '<Settings>asdf</Settings>');


CREATE OR REPLACE FUNCTION update_exam_files_xml_node(examFileId int, xPathExpression text, xmlNode text)
  RETURNS void AS
$BODY$
    DECLARE xmlData xml;
    DECLARE newXmlData xml;
    DECLARE xmlNodeCount int;
    DECLARE replaceTag text;
BEGIN
    SELECT xml_data INTO xmlData FROM exam_files WHERE id = examFileId;

    IF xml_is_well_formed(xmlNode) = false THEN
        PERFORM add_error_log('update_exam_files_xml_node', 'xmlNode is not well formed xml');
        RETURN;
    END IF;

    IF xmlData IS NOT NULL THEN
        -- check if the node already exists and if it does then simply update it
        IF xmlexists(xPathExpression PASSING BY REF xml(xmlData)) = true THEN
            -- get the node name
            replaceTag := regexp_replace(xPathExpression, '/.*/', '');

            -- replace the existing node with the newly passed in node
            newXmlData := xml(regexp_replace(xmlData::text, '<'||replaceTag||'>.*</'||replaceTag||'>', xmlNode));

        -- if node doesn't exist then we have to add it manually
        ELSE
            newXmlData := xml(REPLACE(xmlData::text, '</ImageXmlData>', xmlNode||'</ImageXmlData>'));
        END IF;
        UPDATE exam_files SET xml_data = newXmlData WHERE id = examFileId;
    ELSE
        -- there is no xml found so create xml from scratch and insert the node
        xmlData := '<ImageXmlData>'||xmlNode||'</ImageXmlData>';
        UPDATE exam_files SET xml_data = xmlData WHERE id = examFileId;
    END IF;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
4

1 回答 1

0

很高兴你有一个解决方案。老实说,由于与语言层次结构相关的问题,字符串格式化函数在 SGML 中很难可靠地使用。即,正则表达式对它们可以做什么有严格的限制。

一个更好的解决方案可能是走一个非常不同的方向,用 PL/PerlU 或 PL/Python 编写函数,并为这些语言使用现有的 XML 处理能力。这可能会为您提供更好、更强大的解决方案。

于 2013-12-06T02:29:05.270 回答