【问题标题】:Access Violation while parsing XML in Delphi XE2在 Delphi XE2 中解析 XML 时访问冲突
【发布时间】:2012-10-06 12:16:10
【问题描述】:

我正在尝试使用以下代码在 Delphi XE2 中解析 MusicBraninz XML 文件:

webquery := 'http://www.musicbrainz.org/ws/2/recording/?query='+escape(tracktitle)+'&artist:'+escape(ArtistTitle);

Log('WebQuery: ' + webquery, 0);

begin
  XMLDoc:= TXMLDocument.Create(nil);
  XMLDoc.FileName := webQuery;
  XMLDoc.Active := True;

  Log('Report: ' + XMLDoc.XML.Text, 0);


   StartItemNode := XMLDoc.DocumentElement.ChildNodes.First.ChildNodes.FindNode('release-list') ;

   ANode := StartItemNode;
   repeat
     Result.Album := ANode.ChildNodes['title'].Text;  <-- Access Violation
     Result.Status:= ANode.ChildNodes['status'].Text;

     ANode := ANode.NextSibling;
   until ANode = nil;

end;

正确获取 XML 文件,如下所示:

<metadata xmlns="http://musicbrainz.org/ns/mmd-2.0#" xmlns:ext="http://musicbrainz.org/ns/ext#-2.0">
<recording-list offset="0" count="1">
<recording ext:score="100" id="a399eec1-d45d-4505-b475-ead0da6cad17">
<title>Mestecăniș</title>
<length>359000</length>
<artist-credit>
<name-credit>
<artist id="8fb78a16-0cba-4175-8c92-d9645dfb007d">
<name>Bucovina</name>
<sort-name>Bucovina</sort-name>
</artist>
</name-credit>
</artist-credit>
<release-list>
<release id="22b00afc-86ea-445a-8805-b6bfa33da74e">
<title>Duh</title>
<status>Official</status>
<release-group type="EP" id="4e8fb87c-3760-48c1-a3d7-88e7a2c839fa">
<primary-type>EP</primary-type>
</release-group>
<date>2010</date>
<country>RO</country>
<medium-list>
<track-count>5</track-count>
<medium>
<position>1</position>
<format>CD</format>
<track-list offset="3" count="5">
<track>
<number>4</number>
<title>Mestecăniș</title>
<length>359000</length>
</track>
</track-list>
</medium>
</medium-list>
</release>
</release-list>
</recording>
</recording-list>
</metadata>

我的问题是:我在这里做错了吗?所有变量都声明并初始化OK。

谢谢,

【问题讨论】:

  • 您不能将 URL 传递给 TXMLDocument.FileName 属性。如果你需要解析一个远程的 XML 文件,你必须先通过其他方式下载到本地,比如 Indy 的TIdHTTP 组件。在这种情况下,我建议使用 TStream 而不是 HDD 上的文件下载和解析 XML。
  • 感谢雷米的观察。我被 About.com (delphi.about.com/od/internetintranet/ss/xml_rss_read_3.htm) 上的示例代码误导了阅读和操作 XML 文件,我没有多想。当然,这让我付出了很大的代价。
  • @Remy,你不需要。正如我在(现已删除)评论中所建议的那样,将 URL 传递给 LoadXMLDocument 函数就足够了,就像 RRUZ 在他的回答中所说的那样。
  • LoadXMLDocument() 仅创建一个TXMLDocument 并分配其FileName 属性。该属性不支持 URL,仅支持本地文件路径。
  • @TLama:您依赖于底层引擎的供应商特定扩展,在本例中为 Windows 上的 MSXML。

标签: xml delphi delphi-xe2 musicbrainz


【解决方案1】:

您有访问冲突,因为 FindNode 方法返回一个 nil 值,并且您试图访问无效的内存位置。要使用FindNode 方法,您必须检查要搜索的节点的层次结构(级别),然后检查结果是否不是nil

试试这个示例。

  XMLDoc:= LoadXMLDocument(webQuery);
   StartItemNode := XMLDoc.DocumentElement.ChildNodes.FindNode('recording-list');
   if not Assigned(StartItemNode) then exit;
   StartItemNode := StartItemNode.ChildNodes.FindNode('recording');
   if Assigned(StartItemNode) then
   begin
     StartItemNode := StartItemNode.ChildNodes.FindNode('release-list');
     if Assigned(StartItemNode) then
     begin
       StartItemNode := StartItemNode.ChildNodes.FindNode('release');
       if Assigned(StartItemNode) then
       begin
         ANode := StartItemNode;
         repeat
           Result.Album := ANode.ChildNodes['title'].Text;
           Result.Status:= ANode.ChildNodes['status'].Text;
           ANode := ANode.NextSibling;
         until ANode = nil;
       end;
     end;
   end;

【讨论】:

  • +1,你的速度更快...无论如何,我认为最好使用 DOM 和 XPath。或者一个看起来很疯狂的XMLDoc.DocumentElement.ChildNodes.First.ChildNodes.First.ChildNodes.FindNode('release-list') 节点选择。和TIdURI.URLDecode 用于 URL 编码。
  • 当然,我总是推荐使用 XPath 来完成这类任务。
  • 谢谢@RRUZ。到目前为止,我从未使用过 XML,这真的让我感到困惑。您的解决方案为我节省了几个小时。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多