【问题标题】:How to process large XML files with jQuery/Javascript/PHP faster如何使用 jQuery/Javascript/PHP 更快地处理大型 XML 文件
【发布时间】:2020-01-14 08:38:48
【问题描述】:

我正在制作一个商店概览页面,每页呈现 +- 20 个产品。我从压缩 (gzip) XML 文件 (*.xml.gz) 中获取数据。这是提要:http://www.endclothing.com/media/end_feeds/awin_affiliates_eu.xml.gz 每天一次,我使用 PHP 将文件下载到我的服务器并提取 XML 文件。

问题是,解压缩的 XML 文件是 +- 60MB 并且包含超过 50k 的产品。现在,当我尝试从 XML 文件中获取产品并显示它们时,进展非常缓慢。使用下面我使用的代码从本地 XML 显示产品信息大约需要 8 秒:

$.ajax({
    type: "GET",
    url: 'feeds/awin_affiliates_eu.xml',
    cache: true,
    dataType: "xml",

    error: function (response) {
        alert("An error occurred while processing XML file");
        console.log('XML reading Failed: ', e);
    },

    success: function (response) {
        var max = 20;
        $(response).find("product").each(function (i) {

            if (i < max) {

                var _pid = $(this).find('pid').text();
                var _mpn = $(this).find('mpn').text();
                var _colour = $(this).find('colour').text();
                var _name = $(this).find('name').text();
                var _purl = $(this).find('purl').text();
                var _instock = $(this).find('instock').text();
                var _brand = $(this).find('brand').text();
                var _suitable_for = $(this).find('suitable_for').text();
                var _ptype = $(this).find('ptype').text();
                var _category = $(this).find('category').text();
                var _condition = $(this).find('condition').text();
                var _desc = $(this).find('desc').text();
                var _currency = $(this).find('currency').text();
                var _custom1 = $(this).find('custom1').text();
                var _price = $(this).find('price').text();
                var _deltime = $(this).find('deltime').text();
                var _delcost = $(this).find('delcost').text();
                var _imgurl = $(this).find('imgurl').text();
                var _alternate_image = $(this).find('alternate_image').text();

                $("h2._name").eq(i).text(_name);
                $(".price").eq(i).text(_price);
                var background_url = "url(" + _imgurl + ")";
                $(".panel").eq(i).css("background", background_url);

            } else {

                return false;
            }
        });
        console.log('done reading file');
    }
});

有什么方法可以更快地读取 XML 文件,从而更有效地呈现我的产品?

【问题讨论】:

  • It takes about 8 seconds to display product information 下载 60MB 需要多少时间? (在 100mbit 的互联网连接上,没有其他任何事情发生,这至少需要 5 秒 - 所以,我猜 8 秒可能主要是下载时间 - 解决这个问题的唯一方法是更快的互联网连接)跨度>
  • @epascarello - return false 将停止 jquery each 循环
  • 您可以设置一个 cron 作业,每天下载一次,解析数据并将您需要的数据存储在数据库中。然后应用程序的其余部分将只需要从数据库中查询数据。
  • Once a day I download the file to my server with PHP and extract the XML file - 你应该只在提取的 XML 中包含前 20 个产品 - PHP 肯定有能力以这种方式操作 XML 吗?
  • @JaromandaX 根据我的 chrome 开发人员模式,60 MB 大约需要 800 毫秒。我现在也在当地工作。最大的停机时间是等待。

标签: javascript php jquery xml gzip


【解决方案1】:

PHP 具有用于大型 XML 文件的 XMLReader/XMLWriter。您生成的 XML 不大(取决于每页产品的限制)。因此,您可以使用 DOM 进行编写,并且只需要 XMLReader。

这是一个减少 XML 的示例:

$data = <<<'XML'
<merchant xmlns="http://www.w3.org/2005/Atom" xmlns:g="http://base.google.com/ns/1.0">
  <title>End | Globally Sourced Menswear</title>
  <product><name>Comme des Garcons Play Full Zip Hoody</name></product>
  <product><name>Pharrell: Places &amp; Spaces I've Been - Pink Cover</name></product>
  <product><name>The Rig Out Issue 6</name></product>
  <product><name>Baxter of California Beard Comb</name></product>
  <product><name>Baxter of California Comb</name></product>
</merchant>
XML;

$template = <<<'XML'
<merchant xmlns="http://www.w3.org/2005/Atom" xmlns:g="http://base.google.com/ns/1.0"/>
XML;

$reader = new XMLReader();
$reader->open('data://text/plain;base64,'.base64_encode($data));

// prepare the target document
$document = new DOMDocument();
$document->preserveWhiteSpace = FALSE;
$document->loadXML($template);

// iterate to the first product element
do {
  $found = $reader->read();
} while ($found && $reader->localName !== 'product');

$offset = 0;
$limit = 2;
$end = $offset + $limit;

$i = 0;
while ($found && $i < $end) {
  if ($offset <= $i) {
    // expand the current "product" and append it to the "merchant" node
    $document->documentElement->appendChild($reader->expand($document));
  }
  $i++;
  $found = $reader->next('product');
}

$document->formatOutput = TRUE;
echo $document->saveXML();

输出:

<?xml version="1.0"?>
<merchant xmlns="http://www.w3.org/2005/Atom" xmlns:g="http://base.google.com/ns/1.0">
  <product>
    <name>Comme des Garcons Play Full Zip Hoody</name>
  </product>
  <product>
    <name>Pharrell: Places &amp; Spaces I've Been - Pink Cover</name>
  </product>
</merchant>

将原始文件上的脚本用于多个偏移量(分页),持续时间会增加,因为 XMLReader 在达到偏移量之前仍然必须遍历产品节点。但是,您可以在下载提要的脚本中执行此操作并避免请求中的工作。这是我机器上 20 个产品限制的一些结果:

[Page] => Duration
[1] => 3ms
[51] => 14ms
[101] => 25ms
[151] => 35ms
[201] => 44ms
[251] => 55ms
[301] => 66ms
[351] => 91ms
[401] => 95ms
[451] => 110ms

您还应该考虑将文件(使用 XMLReader+DOM)解析为数据库(SQLite,...)或搜索索引(Elastic Search,...)。这将允许您生成过滤结果。

PS:btw 您的 XML 文件看起来已损坏。它将 Atom 定义为默认命名空间,我看不到任何使用 g 前缀定义 Google 命名空间的元素。我希望 merchantproduct 成为该命名空间的一部分。

【讨论】:

    猜你喜欢
    • 2014-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多