Вместо того, чтобы использовать Simple XML для извлечения всех узлов в <UpdatedProducts>
, вы можете вложить один и тот же код, чтобы он читался внутри этого узла для `узлов. Это будет означать, что внутренний l oop будет получать по 1 узлу за раз ...
while ($xml->name == 'UpdatedProducts') {
while ($xml->read() && $xml->name !== 'ProductId');
while ($xml->name == 'ProductId') {
echo $xml->readOuterXml().PHP_EOL;
$xml->next('ProductId');
}
$xml->next('UpdatedProducts');
}
Для обоих типов я попытался уменьшить его до одного l oop. Это не идеально, но, кажется, работает ...
$xml = new \XMLReader();
$xml->open(__DIR__ . '/../../var/tmp/out.xml');
while ($xml->read() && $xml->name != 'UpdatedProducts');
$type = "update";
while ($xml->read() && $xml->name != 'ProductId');
while ($xml->name == 'ProductId') {
$id = $xml->readInnerXml();
if ( !empty($id) ) {
$this->saveToDb($xml->readInnerXml(), $type);
}
while ($xml->read() && $xml->name != 'ProductId'
&& $xml->name != 'RemovedProducts');
if ( $xml->name == 'RemovedProducts' ) {
$type = "remove";
while ($xml->read() && $xml->name != 'ProductId');
}
}
Есть альтернатива, использующая библиотеку, которую я написал, чтобы обернуть вокруг XMLReader (в https://github.com/NigelRel3/XMLReaderReg). Вам придется скачать его, так как версии composer пока нет. Но скопируйте скрипт XMLReaderReg. php в свой проект и
require_once "XMLReaderReg.php";
, тогда вы сможете использовать ...
$reader = new XMLReaderReg();
$reader->open(__DIR__ ."/../../var/tmp/out.xml");
$reader->process([
'.*/UpdatedProducts/ProductId' => function (SimpleXMLElement $data): void {
$this->saveToDb((string)$data, "update");
},
'.*/RemovedProducts/ProductId' => function (SimpleXMLElement $data): void {
$this->saveToDb((string)$data, "remove");
},
]);
$reader->close();