Reputation: 191
I'm using XMLReader to parse a file which i don't control. The file is missing some elements, example below. Where book 2 is missing an info element, i still want to add this to the array. I realise i could use a combination of XMLReader and SimpleXML... but i'd like to see if this is possible?
<book>
<title>book 1</title>
<info>book 1 info</info>
</book>
<book>
<title>book 2</title>
</book>
<book>
<title>book 3</title>
<info>book 3 info</info>
</book>
I have the following XMLReader function:
<?php
function parseXML($args){
extract($args);
$xml = new XMLReader();
$xml->open($file) or die('Cannot open file');
while($xml->read()){
switch($xml->nodeType){
case(XMLREADER::ELEMENT):{
if(in_array($xml->localName, $nodes, true)){
$lName = $xml->localName;
$val = $xml->readString();
$xml->read();
$child[$lName] = trim($val);
if($lName == end($nodes)){
$arr[] = $child;
}
}
}
break;
}
}
$xml->close($file);
return $arr;
}
$settings = array(
'file' => 'books.xml',
'nodes' => array('name', 'info')
);
$books = parseXML($settings);
var_dump($books);
?>
which produces:
Array
(
[0] => Array
(
[name] => book 1
[info] => book 1 info
)
[1] => Array
(
[name] => book 3
[info] => book 3 info
)
)
Upvotes: 1
Views: 819
Reputation: 51950
You could rethink your logic a little. The snippet below builds up a $book
array for each <book>
element, starting each time with default values (an empty string) in case a <name>
or <info>
does not exist for the book.
As <name>
and <info>
elements are reached, their contents are added to the current $book
array.
When reaching a </book>
, the $book
array is added to the main array of $books
.
Building $books
function parseXML($args){
extract($args);
$xml = new XMLReader();
$xml->open($file) or die('Cannot open file');
$books = array();
while ($xml->read()) {
// <book> - start a new child array with default values
if ($xml->nodeType === XMLReader::ELEMENT
&& $xml->localName === 'book') {
$book = array_fill_keys($nodes, '');
// </book> - add the child array to main array
} elseif ($xml->nodeType === XMLReader::END_ELEMENT
&& $xml->localName === 'book') {
$books[] = $book;
// <info> or <title> - add to child array
} elseif ($xml->nodeType === XMLReader::ELEMENT
&& in_array($xml->localName, $nodes, TRUE)) {
$name = $xml->localName;
$val = $xml->readString();
$book[$name] = trim($val);
}
}
$xml->close();
return $books;
}
Resulting array
$books = array(
array('title' => 'book 1', 'info' => 'book 1 info'),
array('title' => 'book 2', 'info' => ''),
array('title' => 'book 3', 'info' => 'book 3 info'),
);
Upvotes: 2