Как предположил @kfinity, это связано с обработкой CLOB, а также с тем, как работает dbms_output
. Вы читаете CLOB кусками по 32 КБ и записываете каждый из них с помощью put_line()
, который добавляет символ новой строки после каждого блока 32 КБ. Они не совпадают с какими-либо существующими разрывами строк в вашем XML-документе, поэтому вы получаете исходные разрывы, а затем дополнительные разрывы, которые выглядят несколько случайными и в середине текста, но на самом деле находятся в предсказуемых местах.
Очевидное решение состоит в том, чтобы переключиться с put_line()
на put()
, но это нарушит максимальный размер буфера и выдаст что-то вроде "ORU-10028: переполнение строки, ограничение 32767 байт на строку".
Вместо чтения в фиксированных кусках по 32 Кб, вы можете читать по одной строке за раз; CLOB на самом деле не понимает строки как таковые, но вы можете искать разрывы строк, например:
WHILE pos < v_clob_length LOOP
-- read to next newline if there is one, rest of CLOB if not
if dbms_lob.instr(v_clob, chr(10), pos) > 0 then
amount := dbms_lob.instr(v_clob, chr(10), pos) - pos;
dbms_lob.read(v_clob, amount, pos, buffer);
pos := pos + amount + 1; -- skip newline character
else
amount := 32767;
dbms_lob.read(v_clob, amount, pos, buffer);
pos := pos + amount;
end if;
dbms_output.put_line(buffer);
END LOOP;
if
ищет символ новой строки после текущей позиции. Если он находит один, то сумма вычисляется как количество символов от текущей позиции до этой новой строки (точнее, минус один - так как вы не хотите самой новой строки), он читает столько символов, а затем корректирует позицию на прочитанное количество плюс один (чтобы пропустить новую строку - что вам не нужно / не нужно, так как put_line()
добавляет еще одно).
Если он не находит его, он читает до 32 Кб - возможно, только один раз; если осталось больше символов, которые могут остаться без разрыва строки, тогда будет выполнено второе чтение, но все равно добавится эта мошенническая дополнительная новая строка и будет разбита эта строка. Однако с помощью dbms_output
вы ничего не можете сделать с этим, вам придется переключиться на utl_file
запись на сервер, а не на буферизацию на клиенте.