我有一个传入的soap消息,其形式是TStream(Delphi7),发送这个soap的服务器处于开发模式,并在消息中添加一个html标头以进行调试。现在我需要从它中删除 html 标头部分,然后才能将其传递给肥皂转换器。它以“pre”标签开头,以“/pre”标签结束。我认为这应该很容易,但我以前在 Delphi7 中没有做过,所以有人可以帮助我吗?
4 回答
另一个解决方案,更符合 Lars 的建议,并且以某种方式更有效。
它更快,尤其是当 Stream 的大小超过 100 时,甚至在非常大的情况下更是如此。它避免了复制到中间字符串。
FilterBeginStream更简单,并遵循“规范”删除所有内容,直到标题结束。
FilterMiddleStream的作用与 DepreStream 相同,只保留标题之前和之后的内容。
警告:此代码适用于 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;
创建一个新的 TStream(使用 TMemoryStream)并使用 TStream.CopyFrom 或 TStream.ReadBuffer/WriteBuffer 方法将您想要保留的任何内容从一个流移动到另一个流。
我认为以下代码可以满足您的需求,假设您的文档中只有一个 <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 转换来删除不需要的标签,但我在转换的方式上做的不多,所以如果其他人想要那个火炬......
编辑:更正代码以使其正常工作。教我直接编码到 SO 而不是先编码到 IDE。
" " 的 XPath 表达式//pre[1][1]
将拖出 XML 消息中第一个 <pre> 标记的第一个节点:根据您的描述,它应该包含您想要的 SOAP 消息。
我上次使用它已经很多年了,但我认为 Dieter Koehler 的OpenXML 库支持 XPath。