2016-11-25 102 views
0

我有一個大小約爲3.5mb的xml文件。我encuding它並傳播到另一個數據庫,我需要解碼它。我在迭代中對它進行解碼,因爲它太大而無法一次解碼,但是在某些迭代中它無法解碼,我得到了一些giberish。我相信這是因爲一些符號可以是1個字節,其他符號可以是2個字節,有時子字符串會將2個字節的一個符號切成兩半,並且這個迭代會出現在giberish中。我認爲我可以嘗試將每個子字符串轉換爲clob,因爲它在轉換失敗時出現警告,如果出現警告,通過某個數字增加子字符串中的數量,我還沒有成功解碼這個辦法。有沒有解決方法?解碼大的base64編碼斑點

UPDATE

成功地解碼,但有警告的檢查。所有你需要做的就是嘗試將substring轉換爲clob,使用dbms_lob.convertblobtoclob檢查warning != 0,如果是這樣,則將偏移減少1並轉到下一次迭代,而不將子串寫入blob。然而,這是非常複雜的檢查,因爲它需要創建blob並將該blob轉換爲clob。有沒有更簡單的解決方法,也許我錯過了非常明顯的東西?

UPDATE

我已經包含支付XML中base64編碼,以及有關XML其他數據的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

更改腳本中的金額。對於具有75個節點的xml,它可以工作,但是當我將節點數量增加到100時,它再次失敗。 –

回答

1

我仍然沒有得到你的觀點,大多數我不明白你爲什麼從BLOB轉換爲CLOB。

無論如何,我的應用程序中有類似的情況,在XML文件中使用BASE64編碼的XML。

對於編碼和解碼我使用這些功能,也許它有助於您的情況。

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> 

爲了不浪費內存,在使用LOB時應始終使用IN OUT NOCOPY子句。通過這個LOB不被複制過程調用,你只需傳遞一個指針。

+0

既然你提到我不需要將它轉換爲blob,然後再次clob,我已經根據你的例子糾正了我的功能。我已經更新了腳本。添加隨機的XML生成器腳本,所以你可以看到我面臨的。但是,問題依然如此。從base64解碼時,我的xml部分無法解碼。 –