4

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

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

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

任何帮助是极大的赞赏。

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

4

3 回答 3

7

您也可以只使用国际化包:

UTL_I18N.unescape_reference ('文本')

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

于 2013-03-11T00:19:29.063 回答
7

我相信 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.
于 2012-02-07T02:28:09.890 回答
2

This should probably be done in PL/SQL which I do not know, but I wanted to see how far I could get it with pure SQL. This only replaces the first occurence of the code, so you would have to somehow run it multiple times.

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)))

Or less readable but more usable:

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)

This (updated) version correctly replaces the first occurrence. You need to apply it until all of them are replaced.

于 2012-02-07T04:37:01.987 回答