2008-11-03 5 views
1

У меня есть входящее сообщение о мыле, которое представляет собой TStream (Delphi7), сервер, который отправляет это мыло, находится в режиме разработки и добавляет заголовок html в сообщение для целей отладки. Теперь мне нужно вырезать часть заголовка html, прежде чем я смогу передать его в мыльный конвертер. Он начинается с начала тегом pre и заканчивается тегом '/ pre'. Я думаю, что это должно быть довольно легко, но я не сделал этого раньше в Delphi7, так может кто-нибудь мне помочь?Как вырезать часть из потока в Delphi7

ответ

1

Я думаю, что следующий код будет делать то, что вы хотите, если у вас есть только один блок 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.

+0

Выглядит неплохо, но ошибка (EReadError: Ошибка чтения потока) поднимается из строки Result.CopyFrom (oStrStm, oStStm.Size); Любые идеи? – Tamm 2008-11-04 11:18:29

+0

Научите меня печатать непосредственно в SO, а не в компилятор. Попробуйте описанный выше фрагмент, он должен делать то, что вы хотите. – skamradt 2008-11-04 18:04:45

1

Создайте новый TStream (используйте TMemoryStream) и переместите все материалы, которые вы хотите сохранить из одного потока в другой, с помощью методов TStream.CopyFrom или TStream.ReadBuffer/WriteBuffer.

+0

Спасибо, ваша идея, конечно, правильная, но я ищу более подробный ответ, чем ваш. – Tamm 2008-11-04 11:23:49

0

Выражение XPath «//pre[1][1]» вытащит первый узел первого < тэга pre > в XML-сообщении: из вашего описания, которое должно содержать требуемое сообщение SOAP.

Прошло много лет с тех пор, как я в последний раз его использовал, но я думаю, что OpenXML library Дитера Келера поддерживает XPath.

2

Другое решение, более соответствующее предложению Ларса и как-то более выработанное.
Это быстрее, особенно если размер потока превышает 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;