1

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

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

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

有什么可靠的方法可以在 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

4

10 回答 10

1

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

URLLoader.bytesLoaded == URLLoader.bytesTotal

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

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

于 2008-08-20T13:36:43.027 回答
1

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

XML.ignoreWhitespace;

因为ignoreWhitespace是财产。你必须把它设置成true这样:

XML.ingoreWhitespace = true;
于 2008-08-22T07:27:47.190 回答
1

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

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

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

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

于 2008-08-20T16:54:12.570 回答
0

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

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

于 2008-08-22T07:32:57.800 回答
0

If you could post some more code we might be able to find the issue.

Another thing to test (besides tracing bytesTotal) is to trace the data property of the loader in the Event.COMPLETE handler, just to see if the XML data was actually loaded correctly, for example check that there is a </link> there.

于 2008-08-21T14:13:37.923 回答
0

@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我是否没有问题的代码——也就是说,这个错误很难重现,所以据我所知,我没有修复任何东西,而是添加了无用的代码。

于 2008-08-21T17:42:08.810 回答
0

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

于 2008-08-24T14:00:38.243 回答
0

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

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

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

于 2008-08-20T16:36:44.657 回答
0

您可以在 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 确实不完整,我们会强制它再次加载。

于 2008-09-25T08:27:43.600 回答
0

有时 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 中添加缓存破坏器?

只是一些建议...

于 2009-08-17T10:30:55.820 回答