У меня есть входящее сообщение о мыле, которое представляет собой TStream (Delphi7), сервер, который отправляет это мыло, находится в режиме разработки и добавляет заголовок html в сообщение для целей отладки. Теперь мне нужно вырезать часть заголовка html, прежде чем я смогу передать его в мыльный конвертер. Он начинается с начала тегом pre и заканчивается тегом '/ pre'. Я думаю, что это должно быть довольно легко, но я не сделал этого раньше в Delphi7, так может кто-нибудь мне помочь?Как вырезать часть из потока в Delphi7
ответ
Я думаю, что следующий код будет делать то, что вы хотите, если у вас есть только один блок pre > в вашем документе.
function DepreStream(Stm : tStream):tStream;
var
sTemp : String;
oStrStm : tStringStream;
i : integer;
begin
oStrStm := tStringStream.create('');
try
Stm.Seek(0,soFromBeginning);
oStrStm.copyfrom(Stm,Stm.Size);
sTemp := oStrStm.DataString;
if (Pos('<pre>',sTemp) > 0) and (Pos('</pre>',sTemp) > 0) then
begin
delete(sTemp,Pos('<pre>',sTemp),(Pos('</pre>',sTemp)-Pos('<pre>',sTemp))+6);
oStrStm.free;
oStrStm := tStringStream.Create(sTemp);
end;
Result := tMemoryStream.create;
oStrStm.Seek(0,soFromBeginning);
Result.CopyFrom(oStrStm,oStrStm.Size);
Result.Seek(0,soFromBeginning);
finally
oStrStm.free;
end;
end;
Другой вариант я считаю, будет использовать XML-преобразования, чтобы удалить нежелательные теги, но я не делаю много на пути преобразований, так что если кто-то хочет, чтобы этот факел ...
EDIT: Исправленный код, чтобы он работал. Обучает меня кодированию непосредственно в SO, а не в IDE.
Создайте новый TStream (используйте TMemoryStream) и переместите все материалы, которые вы хотите сохранить из одного потока в другой, с помощью методов TStream.CopyFrom или TStream.ReadBuffer/WriteBuffer.
Спасибо, ваша идея, конечно, правильная, но я ищу более подробный ответ, чем ваш. – Tamm 2008-11-04 11:23:49
Выражение XPath «//pre[1][1]
» вытащит первый узел первого < тэга pre > в XML-сообщении: из вашего описания, которое должно содержать требуемое сообщение SOAP.
Прошло много лет с тех пор, как я в последний раз его использовал, но я думаю, что OpenXML library Дитера Келера поддерживает XPath.
Другое решение, более соответствующее предложению Ларса и как-то более выработанное.
Это быстрее, особенно если размер потока превышает 100 и даже больше на самом деле большие. Это позволяет избежать копирования в промежуточную строку.
FilterBeginStream проще и следует за «спецификациями» при удалении всего до конца заголовка.
FilterMiddleStream делает то же самое, что и DepreStream, оставляя перед и после заголовка.
Предупреждение: этот код предназначен для Delphi до D2007, а не D2009.
// returns position of a string token (its 1st char) into a Stream. 0 if not found
function StreamPos(Token: string; AStream: TStream): Int64;
var
TokenLength: Integer;
StringToMatch: string;
begin
Result := 0;
TokenLength := Length(Token);
if TokenLength > 0 then
begin
SetLength(StringToMatch, TokenLength);
while AStream.Read(StringToMatch[1], 1) > 0 do
begin
if (StringToMatch[1] = Token[1]) and
((TokenLength = 1) or
((AStream.Read(StringToMatch[2], Length(Token)-1) = Length(Token)-1) and
(Token = StringToMatch))) then
begin
Result := AStream.Seek(0, soCurrent) - (Length(Token) - 1); // i.e. AStream.Position - (Length(Token) - 1);
Break;
end;
end;
end;
end;
// Returns portion of a stream after the end of a tag delimited header. Works for 1st header.
// Everything preceding the header is removed too. Returns same stream if no valid header detected.
// Result is True if valid header found and stream has been filtered.
function FilterBeginStream(const AStartTag, AEndTag: string; const AStreamIn, AStreamOut: TStream): Boolean;
begin
AStreamIn.Seek(0, soBeginning); // i.e. AStreamIn.Position := 0;
Result := (StreamPos(AStartTag, TStream(AStreamIn)) > 0) and (StreamPos(AEndTag, AStreamIn) > 0);
if Result then
AStreamOut.CopyFrom(AStreamIn, AStreamIn.Size - AStreamIn.Position)
else
AStreamOut.CopyFrom(AStreamIn, 0);
end;
// Returns a stream after removal of a tag delimited portion. Works for 1st encountered tag.
// Returns same stream if no valid tag detected.
// Result is True if valid tag found and stream has been filtered.
function FilterMiddleStream(const AStartTag, AEndTag: string; const AStreamIn, AStreamOut: TStream): Boolean;
var
StartPos, EndPos: Int64;
begin
Result := False;
AStreamIn.Seek(0, soBeginning); // i.e. AStreamIn.Position := 0;
StartPos := StreamPos(AStartTag, TStream(AStreamIn));
if StartPos > 0 then
begin
EndPos := StreamPos(AEndTag, AStreamIn);
Result := EndPos > 0;
end;
if Result then
begin
if StartPos > 1 then
begin
AStreamIn.Seek(0, soBeginning); // i.e. AStreamIn.Position := 0;
AStreamOut.CopyFrom(AStreamIn, StartPos - 1);
AStreamIn.Seek(EndPos - StartPos + Length(AEndTag), soCurrent);
end;
AStreamOut.CopyFrom(AStreamIn, AStreamIn.Size - AStreamIn.Position);
end
else
AStreamOut.CopyFrom(AStreamIn, 0);
end;
Выглядит неплохо, но ошибка (EReadError: Ошибка чтения потока) поднимается из строки Result.CopyFrom (oStrStm, oStStm.Size); Любые идеи? – Tamm 2008-11-04 11:18:29
Научите меня печатать непосредственно в SO, а не в компилятор. Попробуйте описанный выше фрагмент, он должен делать то, что вы хотите. – skamradt 2008-11-04 18:04:45