2016-11-25 3 views
0

У меня есть xml-файл размером около 3,5 МБ. Я поддерживаю его и распространяю на другую базу данных, где мне нужно ее расшифровать. Я расшифровываю его в итерациях, так как он слишком велик, чтобы декодировать за один раз, однако в некоторых итерациях он не может декодироваться, я получаю некоторый giberish. Я считаю, что это потому, что некоторые символы могут быть 1 байт, а другие 2 байта, а иногда подстрока разрезает один символ из 2 байтов пополам и что итерация появится в виде. Я понял, что могу попытаться преобразовать каждую подстроку в clob, так как у нее есть предупреждения, когда она не может преобразовать символы, а если появляется предупреждение, увеличьте количество в подстроке на некоторое число, byt я еще не успел декодировать это путь. Есть ли обходной путь для этого?Декодирование больших base64 закодированных blobs

UPDATE

Преемник в расшифровке, с предупреждениями проверок. Все, что вам нужно сделать, это попытаться преобразовать подстроку в clob с dbms_lob.convertblobtoclob проверить на warning != 0, и если это уменьшит смещение на 1 и перейдите к следующей итерации, не приложив подстроку к вашему блобу. Однако это очень запоминающаяся дорогая проверка, потому что для этого требуется создать blob и трансформировать этот blob в clob. Есть ли более упрощенный обходной путь к этому, может быть, я пропущу что-то очень очевидное?

UPDATE

Я файл XML, который содержит платежное XML в кодировке base64, а также другие данные о том XML. F.E.

<envelope> 
    <file_name>a.xml</file_name> 
    <...><...> 
    <data>BASE64 ENCODED XML FILE</data> 
</envelope> 

Полный сценарий с несколькими примерами. Раньше я упомянул обходной путь с проверкой предупреждений, но в этом примере это, похоже, не работает, и когда я лучше думаю об этом, он не должен. Во всяком случае, вот скрипт:

declare 
    l_clob clob := empty_clob(); 

    function convert_clob_to_blob(
    p_clob in clob) return blob is 

    l_dest_offsset number := 1; 
    l_src_offsset number := 1; 
    l_lang_context number := dbms_lob.default_lang_ctx; 
    l_warning number; 

    l_result blob; 
    begin 
    dbms_lob.createtemporary(l_result, false); 
    dbms_lob.convertToBlob(
     dest_lob => l_result, 
     src_clob => p_clob, 
     amount => dbms_lob.lobmaxsize, 
     dest_offset => l_dest_offsset, 
     src_offset => l_src_offsset, 
     blob_csid => dbms_lob.default_csid, 
     lang_context => l_lang_context, 
     warning => l_warning); 

    if l_warning != 0 then 
     raise_application_error(-20001, 'sd' || '.convert_blob_to_clob ' || l_warning); 
    end if; 
    return l_result; 
    end; 

    function gen_rand_xml return clob is 

    l_xml xmltype := xmltype('<envelope><nullnode></nullnode></envelope>'); 
    begin 
    for i in 1..50 loop 
     SELECT 
      insertXMLafter(
      l_xml, 
      '/envelope/nullnode', 
      XMLType('<node>' || i || '</node>')) 
     INTO 
      l_xml 
     FROM dual; 
    end loop; 

    return l_xml.getClobVal(); 
    end; 

    function to_base64(
    p_clob in clob) return clob is 

    l_length integer; 
    l_offset integer := 1; 
    l_amt binary_integer := 600; 
    l_buffer varchar2(1800); 

    l_result clob := empty_clob(); 
    l_temp_blob blob; 
    begin 
    dbms_lob.createtemporary(l_temp_blob, false); 
    l_temp_blob := convert_clob_to_blob(p_clob); 

    l_length := dbms_lob.getlength(l_temp_blob); 
    while l_offset < l_length loop 
     l_result := l_result || utl_raw.cast_to_varchar2(utl_encode.base64_encode(dbms_lob.substr(l_temp_blob, l_amt, l_offset))); 
     l_offset := l_offset + l_amt; 
    end loop; 

    return l_result; 
    end; 

    function from_base64(
    p_clob in clob) return clob is 

    l_length integer := dbms_lob.getLength(p_clob); 
    l_offset integer := 1; 
    l_amt binary_integer := 800; 
    l_buffer varchar2(3200); 

    l_result clob := empty_clob(); 
    begin 

    while l_offset <= l_length loop 
     l_buffer := replace(replace(dbms_lob.substr(p_clob, l_amt, l_offset), chr(10), null), chr(13), null); 
     l_offset := l_offset + l_amt; 
     while l_offset <= l_length and mod(dbms_lob.getLength(l_buffer), 4) > 0 loop 
     l_buffer := l_buffer || replace(replace(dbms_lob.substr(p_clob, 1, l_offset), chr(10), null), chr(13), null); 
     l_offset := l_offset + 1; 
     end loop; 
     l_result := l_result || utl_raw.cast_to_varchar2(utl_encode.base64_decode(utl_raw.cast_to_raw(l_buffer))); 
    end loop; 

    return l_result; 
    end; 

    procedure print_clob(p_clob in clob) 
    as 
    l_offset number default 1; 
    begin 
    loop 
    exit when l_offset > dbms_lob.getlength(p_clob); 
    dbms_output.put_line(dbms_lob.substr(p_clob, 4000, l_offset)); 
    l_offset := l_offset + 4000; 
    end loop; 
    end; 
begin 
    l_clob := gen_rand_xml; 
    print_clob(from_base64(to_base64(l_clob))); 
end; 
/
+1

Пожалуйста, покажите нам свой код. Почему вы пытаетесь преобразовать BLOB в CLOB? Для XML-файла должно быть хорошо работать все в 'CLOB' (если только XML не является UTF-8, но ваша база данных работает на« нижнем »наборе символов, например' WE8ISO8859P1', но тогда вы все равно можете использовать 'NCLOB') –

+1

Когда вы используете 'base64_encode', тогда количество данных должно быть целым кратным 3, т. Е.'l_amt binary_integer: = 1000;' не работает, используйте 'l_amt binary_integer: = 999;' например. –

+0

Изменено количество в скрипте. И для xml с 75 узлами он работал, однако, когда я увеличил количество узлов до 100, он снова не удался. –

ответ

1

Я до сих пор не понимаю вашу точку зрения, и большинство, я не понимаю, почему вы конвертировать из BLOB в CLOB.

В любом случае, у меня такая же ситуация в моем приложении, что и в XML-файле с кодировкой BASE64.

Для кодирования и декодирования я использую эти функции, возможно, это помогает в вашей ситуации.

CREATE OR REPLACE FUNCTION DecodeBASE64(InBase64Char IN OUT NOCOPY CLOB) RETURN CLOB IS 

    blob_loc BLOB; 
    clob_trim CLOB; 
    res CLOB; 

    lang_context INTEGER := DBMS_LOB.DEFAULT_LANG_CTX; 
    dest_offset INTEGER := 1; 
    src_offset INTEGER := 1; 
    read_offset INTEGER := 1; 
    warning INTEGER; 
    ClobLen INTEGER; 

    amount INTEGER := 1440; -- must be a whole multiple of 4 
    buffer RAW(1440); 
    stringBuffer VARCHAR2(1440); 

BEGIN 

    -- Remove all NEW_LINE from base64 string 
    ClobLen := DBMS_LOB.GETLENGTH(InBase64Char); 
    DBMS_LOB.CREATETEMPORARY(clob_trim, TRUE); 
    LOOP 
     EXIT WHEN read_offset > ClobLen; 
     stringBuffer := REPLACE(REPLACE(DBMS_LOB.SUBSTR(InBase64Char, amount, read_offset), CHR(13), NULL), CHR(10), NULL); 
     DBMS_LOB.WRITEAPPEND(clob_trim, LENGTH(stringBuffer), stringBuffer); 
     read_offset := read_offset + amount; 
    END LOOP; 

    read_offset := 1; 
    ClobLen := DBMS_LOB.GETLENGTH(clob_trim); 
    DBMS_LOB.CREATETEMPORARY(blob_loc, TRUE); 
    LOOP 
     EXIT WHEN read_offset > ClobLen; 
     buffer := UTL_ENCODE.BASE64_DECODE(UTL_RAW.CAST_TO_RAW(DBMS_LOB.SUBSTR(clob_trim, amount, read_offset))); 
     DBMS_LOB.WRITEAPPEND(blob_loc, DBMS_LOB.GETLENGTH(buffer), buffer); 
     read_offset := read_offset + amount; 
    END LOOP; 

    DBMS_LOB.CREATETEMPORARY(res, TRUE); 
    DBMS_LOB.CONVERTTOCLOB(res, blob_loc, DBMS_LOB.LOBMAXSIZE, dest_offset, src_offset, DBMS_LOB.DEFAULT_CSID, lang_context, warning); 

    DBMS_LOB.FREETEMPORARY(blob_loc); 
    DBMS_LOB.FREETEMPORARY(clob_trim); 
    RETURN res; 


END DecodeBASE64; 




CREATE OR REPLACE FUNCTION EncodeBASE64(InClearChar IN OUT NOCOPY CLOB) RETURN CLOB IS 

    dest_lob BLOB; 
    lang_context INTEGER := DBMS_LOB.DEFAULT_LANG_CTX; 
    dest_offset INTEGER := 1; 
    src_offset INTEGER := 1; 
    read_offset INTEGER := 1; 
    warning INTEGER; 

    amount INTEGER := 1440; -- must be a whole multiple of 3 
    buffer RAW(1440); 
    res CLOB := EMPTY_CLOB(); 

BEGIN 

    IF DBMS_LOB.GETLENGTH(InClearChar) IS NULL THEN 
     RETURN NULL; 
    END IF; 

    DBMS_LOB.CREATETEMPORARY(dest_lob, TRUE); 
    DBMS_LOB.CONVERTTOBLOB(dest_lob, InClearChar, DBMS_LOB.LOBMAXSIZE, dest_offset, src_offset, DBMS_LOB.DEFAULT_CSID, lang_context, warning); 
    LOOP 
     EXIT WHEN read_offset >= dest_offset; 
     DBMS_LOB.READ(dest_lob, amount, read_offset, buffer); 
     res := res || UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(buffer));  
     read_offset := read_offset + amount; 
    END LOOP; 
    DBMS_LOB.FREETEMPORARY(dest_lob); 
    RETURN res; 


END EncodeBASE64; 

Вы можете использовать его как этот

DECLARE 
    str VARCHAR2(1000) := '<envelope><file_name>a.xml</file_name><data>some text</data></envelope>'; 
    base64 VARCHAR2(1000); 
BEGIN 
    base64 := EncodeBASE64(str); 
    DBMS_OUTPUT.PUT_LINE(base64); 

    str := DecodeBASE64(base64); 
    DBMS_OUTPUT.PUT_LINE(str); 

END; 

Выход:

PGVudmVsb3BlPjxmaWxlX25hbWU+YS54bWw8L2ZpbGVfbmFtZT48ZGF0YT5zb21l 
IHRleHQ8L2RhdGE+PC9lbnZlbG9wZT4= 
<envelope><file_name>a.xml</file_name><data>some text</data></envelope> 

Возможно, этот пример ближе к прецеденту:

DECLARE 
    payment CLOB := '<payment><amout>50 Cent</amout><recipient>Wernfried Domscheit</recipient></payment>'; 
    envelope XMLTYPE; 
    base64 CLOB; 

BEGIN 

    SELECT 
     XMLELEMENT("envelope", 
      XMLELEMENT("file_name", 'a.xml'), 
      XMLELEMENT("data", EncodeBASE64(payment)) 
     ) 
    INTO envelope 
    FROM dual; 
    DBMS_OUTPUT.PUT_LINE(envelope.getclobval() || CHR(13)); 

    SELECT RETURN_BASE64 
    INTO base64 
    FROM XMLTABLE('envelope/data' PASSING envelope COLUMNS 
     RETURN_BASE64 CLOB PATH '/');  
    DBMS_OUTPUT.PUT_LINE(base64 || CHR(13)); 

    payment := DecodeBASE64(base64); 
    DBMS_OUTPUT.PUT_LINE(payment); 

END; 

Выход:

<envelope><file_name>a.xml</file_name><data>PHBheW1lbnQ+PGFtb3V0PjUwIENlbnQ8L2Ftb3V0PjxyZWNpcGllbnQ+V2VybmZy 
aWVkIERvbXNjaGVpdDwvcmVjaXBpZW50PjwvcGF5bWVudD4=</data></envelope> 

PHBheW1lbnQ+PGFtb3V0PjUwIENlbnQ8L2Ftb3V0PjxyZWNpcGllbnQ+V2VybmZy 
aWVkIERvbXNjaGVpdDwvcmVjaXBpZW50PjwvcGF5bWVudD4= 

<payment><amout>50 Cent</amout><recipient>Wernfried Domscheit</recipient></payment> 

Чтобы не потерять память, вы всегда должны использовать пункт IN OUT NOCOPY при работе с LOB. При этом LOB не копируется для вызова процедуры, вы просто передаете указатель.

+0

Поскольку вы упомянули, что мне не нужно преобразовывать его в blob, а затем снова к clob, я исправил свои функции в соответствии с вашим примером. Я обновил сценарий. Добавлен случайный генератор xml для сценария, чтобы вы могли видеть, с чем я сталкиваюсь. Однако вопрос остается тем же. При декодировании с base64 части моего xml не могут декодироваться. –

Смежные вопросы