2010-03-04 6 views
2

J'ai besoin d'aide sur les appels SimpleXML pour une fonction récursive qui liste le nom et les attributs des éléments. Faire un système de fichier de configuration XML, mais chaque script aura son propre fichier de configuration ainsi qu'une nouvelle convention de nommage. Donc ce dont j'ai besoin est un moyen facile de tracer tous les éléments qui ont des attributs, comme dans l'exemple 1 j'ai besoin d'un moyen simple d'appeler tous les processus mais je ne sais pas comment faire cela sans coder en dur le nom des éléments l'appel de fonction. Existe-t-il un moyen d'appeler récursivement une fonction pour qu'elle corresponde à un nom d'élément enfant? J'ai vu la fonctionnalité xpath mais je ne vois pas comment l'utiliser pour les attributs. Des idées?Fonction récursive PHP SimpleXML pour lister les enfants et les attributs

Le code XML des exemples est-il correct? puis-je structurer mon XML comme ça?

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

Exemple 2:

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

Pseudo-code:

// 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 
} 

EDIT:

je peux passer deux parms? sur la première méthode que vous avez suggéré @Gordon

Je viens de le recevoir, thnx, voir ci-dessous

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; 
} 

Répondre

5

Le XML me semble bon. La seule chose que je ne ferais pas est de faire nom un attribut dans processus, parce qu'il contient des espaces et devrait être un textnode alors (à mon avis). Mais puisque SimpleXml ne s'en plaint pas, je suppose que cela se résume à des préférences personnelles.

Je l'aborderais probablement avec une classe DataFinder, encapsulant des requêtes XPath, par ex.

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 ... 
} 

puis l'utiliser avec

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

Sortie:

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

tutoriel XPath:


Une alternative serait d'utiliser SimpleXmlIterator pour itérer sur les éléments. Iterators peut être decorated avec d'autres itérateurs, de sorte que vous pouvez faire:

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 
} 

Vous devez ajouter quelques méthodes pour avoir le travail de filtre pour les attributs, mais cela est une tâche triviale.

Introduction à SplIterators:

+0

Merci une tonne, la première solution semble grande mais j'ai une erreur: PHP Fatal error: Uncaught exception 'Exception' message « chaîne n'a pas pu être analysé comme XML '. Im passant le fichier comme ça. $ xml = "/path/to/file.xml"; est-ce correct? –

+0

@Phill Non, il attend la chaîne XML, pas le chemin de fichier. Si vous voulez passer un chemin de fichier, vous devez passer '$ data_is_url' comme troisième paramètre. Voir http://de3.php.net/manual/en/simplexmlelement.construct.php – Gordon

+0

@Phill ou remplacer l'appel par 'simplexml_load_file' – Gordon

Questions connexes