Я хотел бы применить функцию к каждому узлу объекта SimpleXML.
<api> <stuff>ABC</stuff> <things> <thing>DEF</thing> <thing>GHI</thing> <thing>JKL</thing> </things> </api>
// function reverseText ($ str) {};
<api> <stuff>CBA</stuff> <things> <thing>FED</thing> <thing>IHG</thing> <thing>LKJ</thing> </things> </api>
Как я применил бы reverseText () для каждого узла, чтобы получить второй фрагмент XML?
Здесь стандартная библиотека PHP может прийти на помощь.
Один из вариантов – использовать (малоизвестный) SimpleXMLIterator
. Это один из нескольких RecursiveIterator
доступных в PHP, и RecursiveIteratorIterator
из SPL можно использовать для перебора и изменения текста всех элементов.
$source = ' <api> <stuff>ABC</stuff> <things> <thing>DEF</thing> <thing>GHI</thing> <thing>JKL</thing> </things> </api> '; $xml = new SimpleXMLIterator($source); $iterator = new RecursiveIteratorIterator($xml); foreach ($iterator as $element) { // Use array-style syntax to write new text to the element $element[0] = strrev($element); } echo $xml->asXML();
Вышеприведенный пример выводит следующее:
<?xml version="1.0"?> <api> <stuff>CBA</stuff> <things> <thing>FED</thing> <thing>IHG</thing> <thing>LKJ</thing> </things> </api>
Вы можете создать массив всех узлов в документе с помощью SimpleXMLElement::xpath()
.
Затем вы можете использовать array_walk
в этом массиве. Однако вы не хотите изменять строку каждого узла, только те элементы, у которых нет дочерних элементов.
$source = ' <api> <stuff>ABC</stuff> <things> <thing>DEF</thing> <thing>GHI</thing> <thing>JKL</thing> </things> </api> '; $xml = new SimpleXMLElement($source); array_walk($xml->xpath('//*'), function(&$node) { if (count($node)) return; $node[0] = strrev($node); }); echo $xml->asXML();
Вышеприведенный пример выводит следующее:
<?xml version="1.0"?> <api> <stuff>CBA</stuff> <things> <thing>FED</thing> <thing>IHG</thing> <thing>LKJ</thing> </things> </api>
Запрос xpath позволяет больше контролировать, например, с пространствами имен.