问题
I am trying to parse product feed that is provided to Google merchant. The thing is I want it to be more interactive so I was using a function that convert XML to array and then show percentage to the user that how much products are updated.
I have read that XMLReader
is much more efficient then other parsing techniques.
How can I make XMLReader
more effective. Can I get number of nodes using XMLReader. Or how Can I iterate over XML that it can be more responsive.
回答1:
Converting the XML to an array is the wrong idea. It will mean that you build the data structure in memory. But you already have a data structure, so converting it into an array will mean that you loose data and features. Always read the XML directly and use it.
Here are several ways to archive what you want. If the feed is small you can use DOM directly. That allows you to use XPaths count()
function.
The Google Product-Feed is bases on RSS 2.0 or Atom 1.0. Atom is the better format so let's use that.
// create a DOM document and load the XML
$dom = new DOMDocument();
$dom->loadXml($xml);
// Create a xpath object and register prefixes for the two namespaces
$xpath = new DOMXpath($dom);
$xpath->registerNamespace('atom', 'http://www.w3.org/2005/Atom');
$xpath->registerNamespace('gi', 'http://base.google.com/ns/1.0');
// Output the entry count
var_dump($xpath->evaluate('count(//atom:entry)'));
// iterate the entries
foreach ($xpath->evaluate('//atom:entry') as $entry) {
// output some data from them
var_dump(
[
'title' => $xpath->evaluate('string(atom:title)', $entry),
'summary' => $xpath->evaluate('string(atom:summary)', $entry),
'image-link' => $xpath->evaluate('string(gi:image_link)', $entry)
]
);
}
If the product feed is really large, loading it completely into memory might not be working. But to get the count you will have to load them into memory or iterate them twice. One possible approach around that would be the file size. It will not be the exact progress of course. But should be good enough.
$file = 'feed.xml';
$fileSize = filesize('feed.xml');
$readBytes = 0;
// get an xml reader for the file
$reader = new XMLReader;
$reader->open($file);
// get an xml document, xpath and register the namespaces
$dom = new DOMDocument();
$xpath = new DOMXpath($dom);
$xpath->registerNamespace('atom', 'http://www.w3.org/2005/Atom');
$xpath->registerNamespace('gi', 'http://base.google.com/ns/1.0');
// look for the first entry element
while ($reader->read() && $reader->localName !== 'entry') {
continue;
}
// while you have an entry element
while ($reader->localName === 'entry') {
// import the entry into the prepared document
$entry = $reader->expand($dom);
var_dump(
[
'title' => $xpath->evaluate('string(atom:title)', $entry),
'summary' => $xpath->evaluate('string(atom:summary)', $entry),
'image-link' => $xpath->evaluate('string(gi:image_link)', $entry)
]
);
$readBytes += strlen($reader->readOuterXml());
printf(
'Read %s of %s bytes, %d%%',
$readBytes,
$fileSize,
round($readBytes * 100 / $fileSize)
);
// move to the next entry sibling
$reader->next('entry');
}
Be aware that using XML Reader will be slower. Calculating the status will cost performance, too. It might be a better idea just to show how many entries have been read.
回答2:
Using DOM you can count no of nodes.
$dom = new DOMDocument;
$dom->loadXml($xml);
echo $dom->getElementsByTagName('OfferName')->length;
来源:https://stackoverflow.com/questions/23216522/get-xml-code-count-using-xmlreader