如何在Delphi7中从流中剪切一部分

问题描述 投票:0回答:4

我有一条传入的soap消息,其形式为TStream(Delphi7),发送该soap的服务器处于开发模式,并向消息添加一个html标头以用于调试目的。现在我需要从中剪掉 html 标头部分,然后才能将其传递给soap 转换器。它从“pre”标签开始,以“/pre”标签结束。我想这应该很容易做到,但我以前没有在Delphi7中做过,有人可以帮助我吗?

delphi stream
4个回答
2
投票

另一个解决方案,更符合 Lars 的建议,并且不知何故更有效。
它更快,尤其是当 Stream 的大小超过 100 时,对于非常大的 Stream 来说更是如此。它避免复制到中间字符串。
FilterBeginStream 更简单,并且遵循“规范”删除所有内容直到标头末尾。
FilterMiddleStream 与 DepreStream 的作用相同,保留 header 之前和之后的内容。

警告:此代码适用于 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;

1
投票

我认为下面的代码可以满足您的要求,假设您的文档中只有一个

 块。

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 转换来删除不需要的标签,但我在转换方面没有做太多事情,所以如果其他人想要那个火炬......

编辑:更正代码以使其正常工作。 教我直接在 SO 中编码,而不是先在 IDE 中编码。

创建一个新的 TStream(使用 TMemoryStream),并使用 TStream.CopyFrom 或 TStream.ReadBuffer/WriteBuffer 方法将您想要保留的任何内容从一个流移动到另一个流。

//pre[1][1]
”的 XPath 表达式将拉出 XML 消息中第一个
 标记的第一个节点:根据您的描述,它应该包含您想要的 SOAP 消息。

自从我上次使用它以来已经很多年了,但我认为 Dieter Koehler 的 OpenXML 库 支持 XPath。


1
投票

创建一个新的 TStream(使用 TMemoryStream),并使用 TStream.CopyFrom 或 TStream.ReadBuffer/WriteBuffer 方法将您想要保留的任何内容从一个流移动到另一个流。


0
投票

//pre[1][1]
”的 XPath 表达式将拉出 XML 消息中第一个
 标记的第一个节点:根据您的描述,它应该包含您想要的 SOAP 消息。

自从我上次使用它以来已经很多年了,但我认为 Dieter Koehler 的 OpenXML 库 支持 XPath。

© www.soinside.com 2019 - 2024. All rights reserved.