Рекурсивная функция PHP SimpleXML для перечисления дочерних элементов и атрибутов

Мне нужна помощь в вызовах SimpleXML для рекурсивной функции, в которой перечислены имена и атрибуты элементов. Создание файловой системы XML-конфигурации, но каждый скрипт будет иметь собственный конфигурационный файл, а также новое соглашение об именах. Так что мне нужен простой способ отобразить все элементы с атрибутами, так как в примере 1 мне нужен простой способ вызова всех процессов, но я не знаю, как это сделать без жесткого кодирования. вызов функции. Есть ли способ рекурсивно вызывать функцию для соответствия имени дочернего элемента? Я видел функциональность xpath, но я не вижу, как использовать это для атрибутов. Есть идеи?

Также выглядит ли XML в примерах правильно? Могу ли я структурировать свой XML следующим образом?

Пример 1:

<application> <processes> <process id="123" name="run batch A" /> <process id="122" name="run batch B" /> <process id="129" name="run batch C" /> </processes> <connections> <databases> <database usr="test" pss="test" hst="test" dbn="test" /> </databases> <shells> <ssh usr="test" pss="test" hst="test-2" /> <ssh usr="test" pss="test" hst="test-1" /> </shells> </connections> </application> 

Пример 2:

 <config> <queues> <queue id="1" name="test" /> <queue id="2" name="production" /> <queue id="3" name="error" /> </queues> </config> 

Псевдокод:

 // Would return matching process id getProcess($process_id) { return the process attributes as array that are in the XML } // Would return matching DBN (database name) getDatabase($database_name) { return the database attributes as array that are in the XML } // Would return matching SSH Host getSSHHost($ssh_host) { return the ssh attributes as array that are in the XML } // Would return matching SSH User getSSHUser($ssh_user) { return the ssh attributes as array that are in the XML } // Would return matching Queue getQueue($queue_id) { return the queue attributes as array that are in the XML } 

РЕДАКТИРОВАТЬ:

Могу ли я пройти два парм? по первому методу, который вы предложили @Gordon

Я просто получил это, thnx, см. Ниже

 public function findProcessById($id, $name) { $attr = false; $el = $this->xml->xpath("//process[@id='$id'][@name='$name']"); // How do I also filter by the name? if($el && count($el) === 1) { $attr = (array) $el[0]->attributes(); $attr = $attr['@attributes']; } return $attr; } 

XML выглядит хорошо для меня. Единственное, что я бы не делал, это сделать имя атрибутом в процессе , потому что оно содержит пробелы и должно быть текстовым (тогда, по моему мнению). Но поскольку SimpleXml не жалуется на это, я думаю, это сводится к личным предпочтениям.

Я бы, скорее всего, применил это к классу DataFinder, инкапсулируя запросы XPath, например

 class XmlFinder { protected $xml; public function __construct($xml) { $this->xml = new SimpleXMLElement($xml); } public function findProcessById($id) { $attr = false; $el = $this->xml->xpath("//process[@id='$id']"); if($el && count($el) === 1) { $attr = (array) $el[0]->attributes(); $attr = $attr['@attributes']; } return $attr; } // ... other methods ... } 

а затем использовать его с

 $finder = new XmlFinder($xml); print_r( $finder->findProcessById(122) ); 

Вывод:

 Array ( [id] => 122 [name] => run batch B ) 

Учебник XPath:


Альтернативой было бы использование SimpleXmlIterator для итерации по элементам. Итераторы могут быть украшены другими итераторами, поэтому вы можете сделать:

 class XmlFilterIterator extends FilterIterator { protected $filterElement; public function setFilterElement($name) { $this->filterElement = $name; } public function accept() { return ($this->current()->getName() === $this->filterElement); } } $sxi = new XmlFilterIterator( new RecursiveIteratorIterator( new SimpleXmlIterator($xml))); $sxi->setFilterElement('process'); foreach($sxi as $el) { var_dump( $el ); // will only give process elements } 

Вам нужно будет добавить еще несколько методов для работы фильтра для атрибутов, но это довольно тривиальная задача.

Введение в SplIterators: