【问题标题】:How to cut out a part from a stream in Delphi7Delphi7如何从流中截取一部分
【发布时间】:2008-11-03 16:22:07
【问题描述】:

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

【问题讨论】:

    标签: delphi stream


    【解决方案1】:

    另一个解决方案,更符合 Lars 的建议,并且以某种方式更有效。
    它更快,尤其是当 Stream 的大小超过 100 时,甚至在非常大的情况下更是如此。它避免复制到中间字符串。
    FilterBeginStream 更简单,并遵循“规范”删除所有内容直到标题结束。
    FilterMiddleStream 确实与 DepreStream 相同,保留 header 之前和之后的内容。

    警告:此代码适用于 D2007 之前的 Delphi,而不是 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;
    

    【讨论】:

      【解决方案2】:

      假设您的文档中只有一个

       块,我认为以下代码可以满足您的需求。
      
      
      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。

      【讨论】:

      • 看起来不错,但是从 Result.CopyFrom(oStrStm,oStStm.Size) 行出现错误(EReadError:流读取错误);有什么想法吗?
      • 教我直接输入 SO 而不是输入编译器。试试上面的片段,它应该做你想做的。
      【解决方案3】:

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

      【讨论】:

      • 谢谢,您的想法当然是正确的,但我正在寻找比您的更详细的答案。
      【解决方案4】:

      //pre[1][1]”的 XPath 表达式将拖出 XML 消息中第一个

       标记的第一个节点:根据您的描述,它应该包含您想要的 SOAP 消息。
      
      

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

      【讨论】:

      • 那时我想以最小的努力和尽可能快地删除不需要的部分,所以我真的不想将它转换为 xml doc,我也认为由于 xml 声明不是一开始的也可能造成麻烦。
      猜你喜欢
      • 2018-03-19
      • 2012-03-12
      • 2011-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-07
      相关资源
      最近更新 更多