Oracle:将varchar2字段中的xml实体转换为utf-8字符

Oracle:将varchar2字段中的xml实体转换为utf-8字符,oracle,utf-8,latin1,Oracle,Utf 8,Latin1,我在一个表中有一个字段,其中包含特殊字符的XML实体,因为该表是拉丁语-1。 例如Hallöle sloven&269;ina theö是拉丁语-1,但斯洛文尼亚的č必须由某个将值存储到数据库中的应用程序转换为实体 现在,我需要通过将XML实体转换为原始字符,将表导出到utf-8编码的文件中 Oracle中是否有一个函数可以为我处理这个问题,或者我真的需要为此创建一个巨大的键/值映射 非常感谢您的帮助 编辑:我找到了函数DBMS_XMLGEN.convert,但它只在和上起作用。不在&NNN;上

我在一个表中有一个字段,其中包含特殊字符的XML实体,因为该表是拉丁语-1。 例如Hallöle sloven&269;ina theö是拉丁语-1,但斯洛文尼亚的č必须由某个将值存储到数据库中的应用程序转换为实体

现在,我需要通过将XML实体转换为原始字符,将表导出到utf-8编码的文件中

Oracle中是否有一个函数可以为我处理这个问题,或者我真的需要为此创建一个巨大的键/值映射

非常感谢您的帮助


编辑:我找到了函数DBMS_XMLGEN.convert,但它只在和上起作用。不在&NNN;上:-

我认为dbms_xmlgen的问题在于,从技术上讲,只有五个XML实体。您的示例有一个数字HTML实体,它与Unicode对应:

Oracle有一个UNISTR函数,在这里很有用:

select unistr('sloven\010dina') from dual;
在上面的例子中,我用Unicode将269转换为十六进制的010d,它是U+010d。但是,您可以传递一个十进制数并进行如下转换:

select unistr('sloven\' || replace(to_char(269, 'xxx'), ' ', '0') || 'ina') from dual;
编辑:PL/SQL解决方案:

这是我为你准备的一个例子。这应该循环并替换您从表中选择的每一行的任何引用

create table html_entities (
    id NUMBER(3),
    text_row VARCHAR2(100)
);

INSERT INTO html_entities 
VALUES (1, 'Hallöle slovenčina Ċ ú');

INSERT INTO html_entities 
VALUES (2, 'I like the letter Ċ');

INSERT INTO html_entities 
VALUES (3, 'Nothing to change here.');

DECLARE
    v_replace_str NVARCHAR2(1000);
    v_fh UTL_FILE.FILE_TYPE;       
BEGIN
    --v_fh := utl_file.fopen_nchar(LOCATION IN VARCHAR2, FILENAME IN VARCHAR2, OPEN_MODE IN VARCHAR2, MAX_LINESIZE IN BINARY_INTEGER);

    FOR v_rec IN (select id, text_row from html_entities) LOOP
        v_replace_str := v_rec.text_row;
        WHILE (REGEXP_INSTR(v_replace_str, '&#[0-9]+;') <> 0) LOOP
            v_replace_str := REGEXP_REPLACE(
                v_replace_str, 
                '&#([0-9]+);',
                unistr('\' || replace(to_char(to_number(regexp_replace(v_replace_str, '.*?&#([0-9]+);.*$', '\1')), 'xxx'), ' ', '0')),
                1,
                1
            );
        END LOOP;

        -- utl_file.put_line_nchar(v_fh, v_replace_str);
        dbms_output.put_line(v_replace_str);

    END LOOP;
    --utl_file.fclose(v_fh);
END;
/

这可能应该在PL/SQL中完成,我不知道这一点,但我想看看用纯SQL可以实现多远。这只会替换第一次出现的代码,因此您必须以某种方式多次运行它

select regexp_replace(s, '&#([0-9]+);', u) from
(select s, unistr('\0' || REPLACE(TO_CHAR(TO_NUMBER(c), 'xxxx'), ' ', '')) u from
(select s, regexp_replace(s, '.*&#([0-9]+);.*', '\1') c from
(select 'Hallöle sloven&#269;ina' s from dual)))
或可读性较低但可用性较高:

SELECT 
REGEXP_REPLACE(s, '&#([0-9]+);', unistr('\0' || REPLACE(TO_CHAR(TO_NUMBER(regexp_replace(s, '.*?&#([0-9]+);.*$', '\1', 1, 1)), 'xxxx'), ' ', '')), 1, 1) 
FROM
(SELECT 'Hallöle sloven&#269;ina &#269; &#278;' s FROM DUAL)

此更新版本将正确替换第一次出现的版本。您需要应用它,直到全部替换为止

您也可以使用国际化软件包:

“文本”


将数据库从iso 8859P1移动到链接dbms_xmlgen.convert中的UTF-8

后,将这些html实体更改为普通字符非常有用,例如清除;。可能是因为它是一个xml表而不是varchar2?Sérgio,所以它肯定是一个varchar2字段:CREATE table mytable tid INTEGER NOT NULL,zitat varchar2 2000 NOT NULL;unistr看起来是一个有趣的函数,但因为我的表中有许多行,有许多不同字符的实体,所有这些都是&N;当N代表一个或多个十进制数字时,这种方法在我看来不可行。@mawimawi-我意识到这不是一个完整的解决方案,但这是一个好的开始。我看到MK用正则表达式扩展了我的解决方案。如果REGEXP_REPLACE没有全局替换函数,那么如果没有,那将是一个遗憾。您可以使用存储过程-通过游标循环,并在每一行上循环,直到您不再使用REGEXP_INSTR函数和REGEXP_REPLACE找到十进制实体为止。如果我有时间,而你仍然没有解决方案,我可以写一个代码示例。如果你有时间,那将是天赐之物。谢谢你的帮助!看起来棒极了!谢谢你!我卑微的名声刚刚有了一个大飞跃看起来很棒!但是,在一个字符串中多次执行重放的regexp_replace函数是否有一个标志?我确信perl、python和其他语言都支持这样一个标志。否则,我必须多次替换波兰语或斯洛伐克语中的短语:-是的,它可以替换全部,但问题是,您不是每次都用相同的字符串替换它们。您需要提取代码,将其转换为unicode,并用unicode字符替换该代码。用纯SQL或许可以做到这一点,但这肯定超出了我的SQL专业水平。用160替换269将返回11g中必须后跟四个十六进制字符的错误]。知道为什么以及如何解决吗?我的XML字符串包含许多这样的&160;,除其他外。谢谢
SELECT 
REGEXP_REPLACE(s, '&#([0-9]+);', unistr('\0' || REPLACE(TO_CHAR(TO_NUMBER(regexp_replace(s, '.*?&#([0-9]+);.*$', '\1', 1, 1)), 'xxxx'), ' ', '')), 1, 1) 
FROM
(SELECT 'Hallöle sloven&#269;ina &#269; &#278;' s FROM DUAL)