1

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
    )
)

1 Answer 1

2

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'),
);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.