7

政府の Web サイトから XML を取得しています。

http://www.bankofcanada.ca/stats/assets/rates_rss/noon/en_all.xml

私は次のかなり単純なコードを使用しています:

var
   szUrl: string;
   http: IXMLHTTPRequest;
begin
   szUrl := 'http://www.bankofcanada.ca/stats/assets/rates_rss/noon/en_all.xml';

   http := CoXMLHTTP60.Create;
   http.open('GET', szUrl, False, '', '');
   http.send(EmptyParam);

   Assert(http.Status = 200);

   Memo1.Lines.Add('HTTP/1.1 '+IntToStr(http.status)+' '+http.statusText);
   Memo1.Lines.Add(http.getAllResponseHeaders);
   Memo1.Lines.Add(http.responseText);

返される本文をすべて表示するわけではありませんが、有効な xml を返しますresponseText:

HTTP/1.1 200 OK
Cache-Control: max-age=5
Connection: keep-alive
Connection: Transfer-Encoding
Date: Fri, 30 Mar 2012 14:50:50 GMT
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
Expires: Fri, 30 Mar 2012 14:50:55 GMT
Server: Apache/2.2.16 (Unix) PHP/5.3.3 mod_ssl/2.2.16 OpenSSL/1.0.0d mod_perl/2.0.4 Perl/v5.12.0
X-Powered-By: PHP/5.3.3


<?xml version="1.0" encoding="ISO-8859-1"?>
<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns="http://purl.org/rss/1.0/"
    xmlns:cb="http://www.cbwiki.net/wiki/index.php/Specification_1.1"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:dcterms="http://purl.org/dc/terms/"
    xmlns:xsi="http://www.w3c.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.w3c.org/1999/02/22-rdf-syntax-ns#rdf.xsd">
    <channel rdf:about="http://www.bankofcanada.ca/stats/assets/rates_rss/noon/en_ALL.xml">
        <title xml:lang="en">Bank of Canada: Noon Foreign Exchange Rates</title>
        <link>http://www.bankofcanada.ca/rates/exchange/noon-rates-5-day/</link>

わかりました。そこには有効な xml があります。私はそれが有効であることを知っています...まあ、それを見てください。しかし、私はそれを解析することで有効であることも知っています:

var
   ...
   szXml: WideString;
   doc: DOMDocument60;
begin
   ...
   szXml := http.responseText;
  
   doc.loadXML(szXml);
   Assert(doc.parseError.errorCode = 0);

   Memo1.Lines.Add('============parsed xml');
   Memo1.Lines.Add(doc.xml);

オリジナルIXmlHttpRequestにはプロパティが含まれていresponseXmlます。MSDN から:

解析された応答エンティティ本体を表します。

応答エンティティ本体が有効な XML でない場合、このプロパティは、エラーにアクセスできるように解析された DOMDocument を返します。このプロパティは IXMLDOMParseError 自体を返しませんが、DOMDocument からアクセスできます。

私の場合、次のように responseXml プロパティが存在します。

Assert(http.responseXml <> nil);

また、responseText の解析エラーはありません。

doc := http.responseXml as DOMDocument60;
Assert(doc.parseError.errorCode = 0);

xmlが有効であるため、あるべきです。

http.responseXmlドキュメントオブジェクトを見ると、それは空です:

   Memo1.Lines.Add('============responseXml');
   Memo1.Lines.Add(doc.xml);

IXMLHttpRequest (および IXMLServerHttpRequest) は、次の場合に空の XML ドキュメントを返します。

  • xmlがあります
  • xml は有効です
  • 解析エラーはありません

長い形式で:

uses
    msxml2_tlb;

procedure TForm1.Button1Click(Sender: TObject);
var
    szUrl: string;
    http: IXMLHTTPRequest;
    doc: DOMDocument60;
begin
    szUrl := 'http://www.bankofcanada.ca/stats/assets/rates_rss/noon/en_all.xml';

    http := CoXMLHTTP60.Create; //or CoServerXmlHttpRequest.Create
    http.open('GET', szUrl, False, '', '');
    http.send(EmptyParam);

    Assert(http.Status = 200);

    doc := http.responseXml as DOMDocument60;
    Assert(doc.parseError.errorCode = 0);

    ShowMessage('"'+doc.xml+'"');
end;

文書化されているようにXmlHttpRequest(さらに重要なことに) 動作させるにはどうすればよいですか?ServerXMLHTTP60

4

4 に答える 4

4

は問題を見つけました

Fiddlerを使用して、http 応答をテキスト ファイルに保存しました。その後、応答ファイルを変更し、元の Web サイトに移動するのではなく、手作りの代替案を提供するようにフィドラーに指示できます。

ここに画像の説明を入力

3時間いじった後、元のhttp応答ヘッダーの問題を追跡することができました:

HTTP/1.1 200 OK
Cache-Control: max-age=5
Connection: keep-alive
Connection: Transfer-Encoding
Date: Fri, 30 Mar 2012 14:50:50 GMT
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
Expires: Fri, 30 Mar 2012 14:50:55 GMT
Server: Apache/2.2.16 (Unix) PHP/5.3.3 mod_ssl/2.2.16 OpenSSL/1.0.0d mod_perl/2.0.4 Perl/v5.12.0
X-Powered-By: PHP/5.3.3

次のようにする必要があります。

HTTP/1.1 200 OK
Cache-Control: max-age=5
Connection: keep-alive
Connection: Transfer-Encoding
Date: Fri, 30 Mar 2012 14:50:50 GMT
Transfer-Encoding: chunked
Content-Type: text/xml; charset=UTF-8
Expires: Fri, 30 Mar 2012 14:50:55 GMT
Server: Apache/2.2.16 (Unix) PHP/5.3.3 mod_ssl/2.2.16 OpenSSL/1.0.0d mod_perl/2.0.4 Perl/v5.12.0
X-Powered-By: PHP/5.3.3

問題が見つかったら、動作を説明するドキュメントをさかのぼって見つけることができました。

MSXML 6.0 でサポートされている MIME タイプは次のとおりです。

  • "テキスト/xml "
  • アプリケーション/xml
  • または「 +xml 」で終わるもの、たとえば「application/rss+xml

私が取得している RSS フィードは、実際にはResource Definition Format (RDF) フィードであり、コンテンツ タイプは次のようになります。

application/rdf+xml

彼らの使用:

text/html

非常に多くのレベルで間違っています。

したがって、私が経験している動作は設計によるものです。イライラしますが -responseXmlが「有効」かどうかを簡単に知る方法がないためです。

  • responseXmlオブジェクトが割り当てられます
  • parseErrorオブジェクトが割り当てられます
  • parseError.ErrorCodeゼロです
  • responseXml.documentElement は nil になります
于 2012-03-30T19:20:04.040 に答える
3

私はサービスに関して同じ問題を抱えていましたYouTube

オブジェクトは、応答のresponseXmlコンテンツタイプ/MIMEに依存します。
応答を調べることができますContent-Type。例:がhttp.getResponseHeader('Content-Type')含まれている場合、text/xmlまたはその場合application/xml のみを参照できますhttp.responseXml。それ以外の場合は空になります(MSDN備考を参照)。responseXmlまた、セキュリティ上の理由から、パーサー検証機能は常にオフになっていることに注意してください。

ただし、応答に含まれるコンテンツタイプに関係なく、は常にテキストを含むため、http.responseText新しいインスタンスを使用してたとえば次の例を読み込むことができます。xmlDOMDocumentxml

...
http := CoXMLHTTP60.Create; // or CoServerXmlHttpRequest.Create 
http.open('GET', szUrl, False, '', '');
http.send(EmptyParam);
Assert(http.Status = 200);

doc := CreateOleObject('Msxml2.DOMDocument.6.0') as DOMDocument60; 
doc.async := False;
doc.loadXML(http.responseText); // <- load XmlHttpRequest.responseText into DOMDocument60 and use it
Assert(doc.parseError.errorCode = 0);

// do useful things with doc object...
于 2012-03-31T20:24:58.540 に答える
0

さて、これは Delphi XE と Delphi 7 で動作します。

procedure TForm1.Button1Click(Sender: TObject);
var
    szUrl: string;
    http: IXMLHTTPRequest;
    doc: {$ifndef UNICODE}WideString{$else}string{$endif};
begin
    szUrl := 'http://www.bankofcanada.ca/stats/assets/rates_rss/noon/en_all.xml';

    http := CoXMLHTTP60.Create; //or CoServerXmlHttpRequest.Create
    http.open('GET', szUrl, False, '', '');
    http.setRequestHeader('Content-Type', 'text/xml;charset=UTF-8');
    http.send(EmptyParam);

    Assert(http.Status = 200);

    doc := UTF8Encode(http.responseText);

    Memo1.Lines.text := doc;
//  ShowMessage('"'+doc.xml+'"');
end;

Delphi 5 でもうまくいくことを願っています。もちろん、Unicode 文字は ? に変わります。あなたに、非ユニコードのデルファイバージョンで。

于 2012-03-30T16:05:09.913 に答える
0

xmlオブジェクト自体から取得してDOMDocumentいますが、代わりにドキュメントのツリーの最初のノードから取得する必要があります。次に例を示します。

doc := http.responseXml as DOMDocument60; 
Assert(doc.parseError.errorCode = 0); 
ShowMessage('"' + doc.DocumentElement.childNodes.Item(0).xml + '"'); 

DOMDocumentおよびプロパティのドキュメントにある Microsoft 独自の例は、xmlまさにその種類のロジックを示しています。

于 2012-03-30T18:47:24.593 に答える