Generating array of strings with PHP

I sometimes work with XML documents and need to make XPath queries to find information in the document. While XPath is extremely powerful tool, it needs thorough instructions how and where to look for the desired data. In case an XML document has multiple elements with the same name, the result will contain a list of nodes to iterate. Take a look at the following XML.

<book> <chapter>Prolog</chapter> <chapter>Chapter 1</chapter> <chapter>Chapter 2</chapter> <chapter>Chapter 3</chapter> <chapter>Epilog</chapter> </book>

This imaginary document describes some contents of a book. Using the DOMDocument object in PHP I can easily convert this document to strings for further manipulation in the code. The DOMXPath class provides the XPath capabilities and the following code instantiates the object for this demonstration.

$doc = new DOMDocument(); $doc->loadXML('<book>...</book>'); $xpath = new DOMXPath($doc);

To access the chapter elements, I would simply query the document with given path.

$elements = $xpath->query('/book/chapter');

The $elements variable contains now DOMNodeList object, which in turn holds a list of chapter elements ready to walk through in a loop. XPath can also query some specific element with an index starting from 1. For example, "Chapter 2" is the third chapter element from the beginning of the document and the following query will return the precise element.

$element = $xpath->query('/book/chapter[3]');

I had a project where I needed this specific path to pick up some elements in exact position. To avoid repeating the path I could use a loop and construct the path using some index variable, like in the next code snippet.

for ($i = 1; $i <= 5; $i++) { $element = $xpath->query("/book/chapter[$i]"); }

The length attribute gives the number of elements for the loop counter.

$elements = $xpath->query('/book/chapter'); for ($i = 1; $i <= $elements->length; $i++) { $element = $xpath->query("/book/chapter[$i]"); }

My code is growing and doesn't look very neat anymore. The path is repeated twice and when it changes, I need to fix the code in two instances. I wanted to loop an array of paths like in the code below.

$paths = array( '/book/chapter[1]', '/book/chapter[2]', '/book/chapter[3]', '/book/chapter[4]', '/book/chapter[5]' ); foreach ($paths as $path) { $element = $xpath->query($path); }

Now the loop looks simple and efficient, but the array of paths still needs fixing. Element count varies and the array of paths must be dynamic. Generating an array of paths needs a PHP callback function as well as dynamically created function to generate the actual string as an array element. First I need an array with index numbers. The range() function makes such an array required.

$a = range(1, $elements->length);

The $a array variable holds five elements.

Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 )

The next step is to replace the index numbers with a string while preserving the index. This requires using a callback function, which walks through all the elements in the array. I use array_walk() function, which takes two arguments. The first argument is the array to walk through and the other argument is a reference to a separate function, which in turn uses the value of each array element and makes a string to replace the original numerical value. I don't want to introduce another function and this is why I use create_function() to create an anonymous (lambda-style) function ad hoc.

array_walk($a, create_function('&$value', '$value = "/book/chapter[$value]";'));

The argument passed to the callback function is the actual value in the array element. This value is replaced with a string in $path variable added within brackets. Finally, the concatenated string is returned back to the array as the argument was declared by reference. The $a array contains the paths to use with XPath query.

Array ( [0] => /book/chapter[1] [1] => /book/chapter[2] [2] => /book/chapter[3] [3] => /book/chapter[4] [4] => /book/chapter[5] )

Final words

Generating array of strings, which have an index, is relatively easy with PHP array functions. First the range() function creates the base array with desired amount of numbers starting from the lowest limit. Finally the array_walk() function loops all the elements in the array and changes the values accordingly.

Julkaistu maanantaina 30.1.2012 klo 21:35 avainsanalla ohjelmointi.