【问题标题】:Best Practices for AS3 XML ParsingAS3 XML 解析的最佳实践
【发布时间】:2010-09-06 06:49:14
【问题描述】:

我在解析 Flash 中的各种类型的 XML(特别是 FeedBurner RSS 文件和 YouTube 数据 API 响应)时遇到了一些问题。我正在使用URLLoader 加载一个XML 文件,并在Event.COMPLETE 创建一个新的XML 对象。 75% 的时间都可以正常工作,而且我时不时会遇到这种类型的异常:

TypeError: Error #1085: The element type "link" must be terminated by the matching end-tag "</link>".

我们认为问题在于 XML 很大,并且可能在实际从 URLLoader 下载 XML 之前触发了 Event.COMPLETE 事件。我们想出的唯一解决方案是在事件上设置一个计时器,并在开始解析数据之前基本上“等待几秒钟”。这肯定不是最好的方法。

有什么可靠的方法可以在 Flash 中解析 XML 吗?

2008 年 9 月 2 日更新 我们得出以下结论,此时代码中的 excption 被触发:

data = new XML(mainXMLLoader.data);

//  calculate the total number of entries.
for each (var i in data.channel.item){
    _totalEntries++;
}

我已经在这部分周围放置了一个 try/catch 语句,并且当它发生时当前正在屏幕上显示一条错误消息。我的问题是,如果bytesLoaded == bytesTotal,不完整的文件将如何到达这一点?


我已经用状态报告更新了原始问题;我想另一个问题可能是有没有办法在访问数据之前确定XML 对象是否被正确解析(以防错误是我的循环计数对象数量在 XML 实际解析之前开始对象)?


@Theo:感谢 ignoreWhitespace 提示。此外,我们已经确定事件在它准备好之前被调用(我们做了一些测试跟踪mainXMLLoader.bytesLoaded + "/" + mainXMLLoader.bytesLoaded

【问题讨论】:

    标签: xml flash actionscript-3 rss fileparse


    【解决方案1】:

    您是否尝试过检查加载的字节数是否与总字节数相同?

    URLLoader.bytesLoaded == URLLoader.bytesTotal
    

    这应该告诉你文件是否已经完成加载,它不会帮助完成事件提前触发,但它应该告诉你它是否是读取 xml 的问题。

    我不确定它是否适用于域,因为我的 xml 总是在同一个站点上。

    【讨论】:

    • 旁注:在开始加载之前,bytesLoaded 与 bytesTotal 相同(它们都是 0),所以我会检查 onComplete 条件,其中: URLLoader.bytesLoaded == URLLoader.bytesTotal &&字节总数 > 0
    【解决方案2】:

    正如您在问题中提到的那样,问题很可能是您的程序在实际完全下载之前正在查看 XML,我不知道是否有“解析”XML 的可靠方法,因为解析您的部分代码很可能没问题,这只是它是否实际下载的问题。

    您可以尝试使用 ProgressEvent.PROGRESS 事件在下载 XML 时持续监控它,然后按照 Re0sless 的建议,检查 bytesLoaded 与 bytesTotal 并在两个数字相等时开始 XML 解析,而不是使用 Event .COMPLETE 事件。

    无论域如何,您都应该能够很好地获取 bytesLoaded 和 bytesTotal 数字,如果您可以访问该文件,则可以访问其字节信息。

    【讨论】:

      【解决方案3】:

      让我担心的是它可能在完成加载之前触发 Event.COMPLETE,这让我想知道加载是否超时。

      问题多久发生一次?您能否在同一时间获得成功,然后在下一刻以相同的提要失败?

      出于测试目的,请尝试跟踪 Event.COMPLETE 处理程序方法顶部的 URLLoader.bytesLoadedURLLoader.bytesTotal。如果它们不匹配,您就知道该事件过早触发。如果是这种情况,您可以监听 URLLoader 的进度事件。检查处理程序中的bytesLoadedbytesTotal 并仅在加载真正完成后才解析XML。当然,这很可能类似于 URLLoader 在触发 Event.COMPLETE 之前所做的事情,但如果它被破坏了,您可以尝试自己滚动。

      请告诉我们您的发现。如果可以,请粘贴一些源代码。我们也许能发现一些值得注意的东西。

      【讨论】:

        【解决方案4】:

        如果您可以发布更多代码,我们也许能够找到问题。

        要测试的另一件事(除了跟踪bytesTotal)是跟踪Event.COMPLETE处理程序中加载程序的data属性,只是为了查看XML数据是否实际加载正确,例如检查是否有&lt;/link&gt; 那里。

        【讨论】:

          【解决方案5】:

          @Brian Warshaw:这个问题只有大约 10-20% 的时间发生。有时它会打嗝,只需重新加载应用程序就可以正常工作,有时我会花半个小时一遍又一遍地重新加载应用程序无济于事。

          这是原始代码(当我问这个问题时):

          public class BlogReader extends MovieClip {
              public static const DOWNLOAD_ERROR:String = "Download_Error";
              public static const FEED_PARSED:String = "Feed_Parsed";
          
              private var mainXMLLoader:URLLoader = new URLLoader();
              public var data:XML;
              private var _totalEntries:Number = 0;
          
              public function BlogReader(url:String){
                  mainXMLLoader.addEventListener(Event.COMPLETE, LoadList);
                  mainXMLLoader.addEventListener(IOErrorEvent.IO_ERROR, errorCatch);
                  mainXMLLoader.load(new URLRequest(url));
                  XML.ignoreWhitespace;
              }
              private function errorCatch(e:IOErrorEvent){
                  trace("Oh noes! Yous gots no internets!");
                  dispatchEvent(new Event(DOWNLOAD_ERROR));
              }
              private function LoadList(e:Event):void {
                  data = new XML(e.target.data);
          
                  //  calculate the total number of entries.
                  for each (var i in data.channel.item){
                      _totalEntries++;
                  }
          
                  dispatchEvent(new Event(FEED_PARSED));
              }
          }
          

          这是我根据 Re0sless 的原始回复编写的代码(类似于提到的一些建议):

          public class BlogReader extends MovieClip {
              public static const DOWNLOAD_ERROR:String = "Download_Error";
              public static const FEED_PARSED:String = "Feed_Parsed";
          
              private var mainXMLLoader:URLLoader = new URLLoader();
              public var data:XML;
              protected var _totalEntries:Number = 0;
          
              public function BlogReader(url:String){
                  mainXMLLoader.addEventListener(Event.COMPLETE, LoadList);
                  mainXMLLoader.addEventListener(IOErrorEvent.IO_ERROR, errorCatch);
                  mainXMLLoader.load(new URLRequest(url));
                  XML.ignoreWhitespace;
              }
              private function errorCatch(e:IOErrorEvent){
                  trace("Oh noes! Yous gots no internets!");
                  dispatchEvent(e);
              }
              private function LoadList(e:Event):void {
                  isDownloadComplete();           
              }
              private function isDownloadComplete() {
                  trace (mainXMLLoader.bytesLoaded + "/" + mainXMLLoader.bytesLoaded);
                  if (mainXMLLoader.bytesLoaded == mainXMLLoader.bytesLoaded){
                      trace ("xml fully loaded");
          
                      data = new XML(mainXMLLoader.data);
          
                      //  calculate the total number of entries.
                      for each (var i in data.channel.item){
                          _totalEntries++;
                      }
          
                      dispatchEvent(new Event(FEED_PARSED));
                  } else {
                      trace ("xml not fully loaded, starting timer");
                      var t:Timer = new Timer(300, 1);
                      t.addEventListener(TimerEvent.TIMER_COMPLETE, loaded);
                      t.start();
                  }
              }
              private function loaded(e:TimerEvent){
                  trace ("timer finished, trying again");
                  e.target.removeEventListener(TimerEvent.TIMER_COMPLETE, loaded);
                  e.target.stop();
          
                  isDownloadComplete();
              }
          }
          

          我会指出,自从添加代码确定 mainXMLLoader.bytesLoaded == mainXMLLoader.bytesLoaded 之后我没有遇到问题 - 也就是说,这个错误很难重现,所以据我所知,我没有修复任何东西,而是添加了无用的代码。

          【讨论】:

            【解决方案6】:

            只是一个旁注,这个声明没有任何效果:

            XML.ignoreWhitespace;
            

            因为ignoreWhitespace 是一个属性。您必须像这样将其设置为true

            XML.ingoreWhitespace = true;
            

            【讨论】:

              【解决方案7】:

              Event.COMPLETE 处理程序真的不应该被调用,除非加载器完全加载,这是没有意义的。您是否确认它实际上没有完全加载(通过查看您跟踪的 bytesLoadedbytesTotal 值)?如果Event.COMPLETE 事件在bytesLoaded == bytesTotal 之前调度,那就是一个错误。

              很好,你已经让它与计时器一起工作,但你需要它很奇怪。

              【讨论】:

                【解决方案8】:

                我建议您在https://bugs.adobe.com/flashplayer/ 提交错误报告,因为在加载所有字节之前确实不应该触发该事件。与此同时,我想你必须忍受计时器。您也许可以通过监听进度事件来做同样的事情,这也许可以让您不必自己处理计时器。

                【讨论】:

                  【解决方案9】:

                  您可以在 XML 文档的最后设置一个唯一的元素命名空间,其中一个属性“value”等于“true”;

                  //The XML
                  //Flash ignores the line that specifies the XML version and encoding so I have here as well.
                  
                  <parent>
                      <child name="child1" />
                      <child name="child2" />
                      <child name="child3" />
                      <child name="child4" />
                      <documentEnd value="true" />
                  </parent>
                  
                  //Sorry about the spacing, but it is difficult to get XML to show.
                  
                  //Flash
                  var loader:URLLoader = new URLLoader();
                  var request:URLRequest = new URLRequest('pathToXML/xmlFileName.xml');
                  
                  var xml:XML;
                  
                  //Event Listener with weak reference set to true (5th parameter);
                  //The above comment does not define a required practice, this is to aid with garbage collection.
                  
                  loader.addEventListener(Event.COMPLETE, onXMLLoadComplete, false, 0, true);
                  loader.load(request);
                  function onXMLLoadComplete(e:Event):void
                  {
                     xml = new XML(e.target.data);
                  
                     //Now we check the last element (child) to see if it is documentEnd.
                     if(xml[xml.length()-1].documentEnd.@value == "true")
                     {
                        trace("Woot, it seems your xml made it!");
                     }
                     else
                     {
                        //Attempt the load again because it seems it failed when it was unable to find documentEnd in the XML Object.
                        loader.load(request);
                     }
                  }
                  

                  我希望这对您现在有所帮助,但真正的希望是有足够多的人让 adobe 知道这个问题。不能依靠事件是一件可悲的事情。不过我必须说,从我听说过的有关 XML 的情况来看,它在大规模上并不是非常理想的,并且相信这是你需要像 AMFPHP 这样的东西来序列化数据的时候。

                  希望这会有所帮助!请记住这里的想法是我们知道 XML 中的最后一个子/元素是什么,因为我们设置了它!我们没有理由不能访问最后一个子/元素,但如果不能,我们必须假设 XML 确实不完整,我们会强制它再次加载。

                  【讨论】:

                    【解决方案10】:

                    有时 RSS 服务器页面可能无法输出正确且有效的 XML 数据,尤其是在您不断点击它的情况下,因此这可能不是您的错。您是否尝试过在 Web 浏览器中点击页面(最好使用 xml 验证器插件)来检查服务器响应是否始终有效?

                    我在这里能看到的唯一其他东西是这条线:

                    xml = new XML(event.target.data);
                    
                    //the data should already be XML, so only casting is necessary
                    xml = XML(event.target.data);
                    

                    您是否也尝试过将 urlloader dataFormat 设置为 URLLoaderDataFormat.TEXT,并添加 prama-no-cache 的 url 标头和/或在他的 url 中添加缓存破坏器?

                    只是一些建议......

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-01-15
                      • 1970-01-01
                      • 2021-09-23
                      • 1970-01-01
                      • 2012-01-05
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多