我需要帮助我作为新员工接管的组件,其任务是向组件添加新方法。该组件使用idTCPClient而不是idHTTP。请参阅以下两个问题中的答案,了解原因。
Getting XML from response stream using Indy's IDTCPClient
Getting HTML from response stream using Indy's IDTCPClient
是的Remy&杰里,我已经开始重写组件以利用tidHTTP而不是idTCPClient,但我是在自己的空闲时间,而不是公司时间。所以,今晚我需要完成它。好的,回到这篇文章。
调用下面的get函数,我得到以下回复
HTTP/1.0 200 OK
Content-Length: 2069
Date: Wed, 20 Nov 2013 15:00:11 GMT
Content-Type: text/xml; charset=UTF-8
function TMyConnector.GET(aRawHeader: String): String;
begin
if Not Connected then Connected := True;
if Connected then
begin
FRawRequest := 'GET /'+ EncodeUrl(aRawHeader) + ' HTTP/'+HTTPVerText+#13#10+
'Host: '+FHost+#13#10+
'Cookie: UserHPos=IOGLO00003000090000C000BS; '+
'LOSID=qsBiy/wEDCq6tOXFzGbOlTD1lmo5AXdFnCkbzzPn6+qCeheYVyTcumRrjsqh+Hds4Fr2gZDazfDzGN1RA+nnHuQQeBy78ZUgctrZyyy9MnGl2qI/ulkV6EPxAfmmLg/lopRq99f5gAcG/dgtytAJjS+aD5DqtHGrAqjiqgtkwuA=; '+
'LoginHPos=IOGLO00003000090000C000BS; '+
'UIHPos=IOGLO00003000020000500003; '+
'LOSG=61939308-7C83-47ED-B909-2D2D10AD7026; '+
'fControllingBusiness=IOGLO000030000900001000050000200001'+#13#10+
'Connection: Close'+#13#10+
#13#10;
FSock.Socket.Write(FRawRequest);
FRawResponse := FSock.Socket.ReadLn(#13#10#13#10,nil);
Result := FRawResponse;
if ResponseStream = nil then ResponseStream := TMemoryStream.Create
else ResponseStream.SetSize(0);
FSock.Socket.ReadStream(ResponseStream,-1,True);
if Connected and (Not KeepAlive) then Connected := False;
end;
end;
我现在如何从responseStream获取XML字符串?
JSON已经存在一种当前的方法
Procedure TMyConnector.GenerateJSON;
begin
if ResponseStream <> nil then
Begin
ResponseJSON_V := TJSONObject.ParseJSONValue(StreamToArray(ResponseStream),0) as TJSONValue;
End;
end;
我想创建一个XML方法,我尝试了以下内容:
Procedure TMyConnector.GenerateXML;
var
S: String;
begin
if ResponseStream <> nil then
// code here to convert ResponseStream to XML
ResponseXML_v:= S;
end;
答案 0 :(得分:1)
我现在如何从responseStream获取XML字符串?
好吧,至少你必须从responseStream中读取一些数据。 但是你没有在GenerateXML代码中读到它。
Procedure TMyConnector.GenerateXML;
var
S: String; SS: TStringStream;
begin
if ResponseStream <> nil then begin
S := '';
SS := TStringStream.Create(S, TEncoding.UTF8, False);
try
SS.LoadFromStream(ResponseStream);
// original: ResponseXML_v := S; - so ResponseXML_v is jsut a string....
ResponseXML_v:= SS.DataString;
finally
SS.Destroy;
end;
end;
end;
但是在这里,UTF8绝对是猜测,如果ResponseStream是例如zip存档或base64编码的文本或其他东西,它将会失败。
获取字符串后,您必须解析它。但解析字符串并通过网络传输它是不同的问题。 您可以在此处获取XML解析器列表:What is the fastest XML Parser available for Delphi?
我还建议您尝试使用SuperObject库。我不确定它是否支持所有XML功能,但它具有JSON和XML的通用API,这应该是一件好事。
无论如何,您可以通过StackOverflow谷歌查看Delphi库存DB-Express JSON解析器有许多错误和限制。
https://code.google.com/p/superobject/source/browse/superxmlparser.pas
Procedure TMyConnector.GenerateXML;
begin
Response_v := nil;
if ResponseStream <> nil then begin
ResponseStream.Position := 0;
Response_v:= XMLParseStream(ResponseStream)
end;
end;
Procedure TMyConnector.GenerateJSON;
begin
Response_v := nil;
if ResponseStream <> nil then begin
ResponseStream.Position := 0;
Response_v:= TSuperObject.ParseStream(ResponseStream);
end;
end;
https://superobject.googlecode.com/git/readme.html
然而,在解析之前,charset检测和转换可能仍然是您的责任。
因此,“分离关注点”并使用“DRY原则”(“代码重用”部分)我们将功能统一为类似的东西:
{$ScopedEnums On}
type ResponseFormat = (XML, JSON)
function ParseResponse(const ResponseStream: TStream;
const Format: ResponseFormat): iSuperObject;
begin
Result := nil;
if ResponseStream = nil then exit;
if ResponseStream.Size <= 0 then exit;
ResponseStream.Position := 0;
case Format of
ResponseFormat.XML: Result := XMLParseStream(ResponseStream);
ResponseFormat.JSON: Result := TSuperObject.ParseStream(ResponseStream);
else raise Exception.CreateFmt(
'Unknown response format #%d, cannot parse it.', [ Ord(ResponseFormat) ] );
end;
end;
现在你的责任是在JSON或XML响应的统一事务中调用该函数,并始终为它提供正确的输入数据流。
总的来说,你面前有两个问题:
这些是不同的问题,你应该将你的情况和你的程序解构为这些部分。否则你会陷入无法理解(包括你)和调试的狂野混音。你应该去耦合和解缠结,而不是相反。
您告诉您向服务器发出相同的请求,但GenerateJSON函数获取流而GenerateXML没有?它应该是什么意思?只是代码中有一些重要的区别,你没有显示。这意味着你不要理解你的代码在做什么,何时以及为什么做什么。你应该“分而治之”。将程序分成几部分。一件将从服务器获取数据流 - 没有别的。另一部分将解析流 - 而不是其他任何东西。然后你应该单独调试它们(并提出单独的问题)。当你有nil流时,没有必要调试和重做解析。所以...单独关注。制作功能,支持流,并确保它能够正常工作。例如,将流保存到文本文件并使用Text + Hex编辑器检查其内容。完成第一个任务后 - 转到下一个任务,然后解析收到的流。但只有在你确定你总是得到了流之后。