Как правильно парсить большие XML используя консоль?

В общем, на прошлом проекте, где используется yii2 фреймворк, столкнулся с проблемой, что парсинг xml файла, который имел 15к+ элементов, запускался по ссылке, что приводило к 99% CPU, сжиранию памяти и т.д.
Пытался гуглить этот вопрос, но особо ничего не нашел.
Например, я напишу парсер в виде консольного приложения под yii2, который будет запускаться такой командой: php yii parse/xml, будет ли снижено потребление ресурсов сервера? И в чем вообще отличие запуска через yii\console\Application от yii\web\Application?
Находил информацию о php-fpm - это из этой области или нет?
Буду благодарен за обучающие ссылки по этой теме
  • Вопрос задан
  • 59 просмотров
Пригласить эксперта
Ответы на вопрос 2
@bacon
Абстрагируясь от языков, есть два основных метода - через создание DOM и через события (SAX-парсеры). Первый проще в использовании, но загружаеь всё в память, поэтому на больших файлах и возникают проблемы с нехваткой ресурсов. Работа вторых "напоминает" построковое чтение файла. Так что ищите SAX-парсеры для своего языка.
Ответ написан
@topalek
данный код используется для чтения выгрузок товаров типа HOTLINE или Yandex

/**
     * Parsing xml file according to $key_node
     *
     * @param      $key_node
     * @param null $filePath
     *
     * @return array|bool
     */
    public function parseXml($key_node, $filePath = null)
    {

        try {
            $output = [];
            $DOMDocument = new DOMDocument();
            $reader = new XMLReader();
            $reader->open($filePath);
            $line = 0;
            while (($read = $reader->read()) && $reader->name !== $key_node) {
                $line++;
            }
            if (!$read) {
                $text = "Не возможно прочитать xml файл - {$filePath}<br>";
                $text .= "Элемент - {$key_node}  отсутствует в файле<br>";
                $this->importErrorText = $text;
                return $output = [];
            }
            $i = 0;
            while ($reader->name === $key_node) {
                try {
                    $expanded = $reader->expand();
                } catch (Exception $e) {
                    $this->readImportFileErrors[] = $e->getMessage();
                    try {
                        $reader->next($key_node);
                    } catch (Exception $e) {
                        $this->readImportFileErrors[] = $e->getMessage();
                    }
                }
                if (isset($expanded) && $expanded) {
                    if ($expanded->attributes) {
                        $dom = simplexml_import_dom($DOMDocument->importNode($expanded, true));
                        foreach ($dom->attributes() as $k => $v) {
                            $fieldName = mb_convert_encoding(trim($k), 'utf-8');

                            $output[$i][$fieldName] = mb_convert_encoding(trim((string)$v),
                                'utf-8');
                            $output[$i]['title'] = mb_convert_encoding(trim((string)$expanded->nodeValue), 'utf-8');
                        };
                    }

                    foreach ($expanded->childNodes as $k => $item) {
                        if ($item->nodeType == 1) {
                            if ($item->attributes->length > 0) {
                                foreach ($item->attributes as $prop) {
                                    if ((string)$prop->nodeValue) {
                                        $fieldName = trim((string)$item->nodeName);

                                        $output[$i][$fieldName][trim((string)$prop->nodeValue)] = mb_convert_encoding(trim((string)$item->nodeValue),
                                            'utf-8');
                                    }
                                }
                            } else {
                                $nodeName = trim((string)$item->nodeName);

                                if (in_array($nodeName, ['picture', 'image'])) {
                                    $output[$i]['image'][] = mb_convert_encoding(trim((string)$item->nodeValue),
                                        'utf-8');
                                } else {
                                    $output[$i][$nodeName] = mb_convert_encoding(trim((string)$item->nodeValue),
                                        'utf-8');
                                }
                            }
                        }
                    }

                    if (!isset($output[$i]['code']) && !isset($output[$i]['vendorCode']) && !isset($output[$i]['barcode'])) {
                        $article = ArrayHelper::getValue($output[$i], 'param.Артикул');
                        if ($article) {
                            $output[$i]['article'] = $article;
                        }
                    }
                }
                try {
                    $reader->next($key_node);
                } catch (Exception $e) {
                    $this->readImportFileErrors[] = $e->getMessage();
                }
                $i++;

            }
            return $output;
        } catch (Exception $exception) {
            $this->importErrorText = 'Ошибка чтения  файла';
            return [];
        }
    }
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы