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

时间:2012-02-02 14:43:45

标签: oracle utf-8 latin1

我在表中有一个字段,其中包含特殊字符的XML实体,因为该表位于latin-1中。 例如。 “Hallöle slovenčina”(“ö”在latin-1中,但“slovenčina”中的“č”必须由某些将值存储到数据库中的应用程序转换为实体)

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

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

非常感谢任何帮助。

编辑:我找到了DBMS_XMLGEN.convert函数,但它仅适用于<>&。不在&#NNN;: - (

3 个答案:

答案 0 :(得分:7)

您也可以使用国际化套餐:

  

UTL_I18N.unescape_reference('text')

非常适合将这些html实体更改为普通字符(例如将数据库从iso 8859P1移动到UTF-8后进行清理)

答案 1 :(得分:6)

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

http://theorem.ca/~mvcorks/cgi-bin/unicode.pl.cgi?start=0100&end=017F

Oracle有一个功能UNISTR,在这里很有用:

select unistr('sloven\010dina') from dual;

我在上面的示例中将269转换为其十六进制等效010d(在Unicode中为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&#269;ina &#266; &#250;');

INSERT INTO html_entities 
VALUES (2, 'I like the letter &#266;');

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

请注意,我已经在调用UTL_FILE函数时将NVARCHAR行(Oracle的扩展字符集)写入数据库服务器上的文件。 dbms_output虽然非常适合调试,但似乎不支持扩展字符,但如果您使用UTL_FILE写入文件,这应该不是问题。这是DBMS_OUTPUT:

Hallöle slovencina C ú
I like the letter C
Nothing to change here.

答案 2 :(得分:2)

这可能应该在我不知道的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)

此(已更新)版本正确替换第一次出现。您需要应用它直到所有这些都被替换。