2009-11-16 4 views
0

J'ai une structure XML simple imbriquée que je charge avec le langage simpleXML de PHP. Certains éléments de la structure contiennent des attributs "contextuels". Après le chargement, j'ai besoin de nettoyer la structure de tous les éléments qui n'appartiennent pas au contexte actuel.Filtrage d'une structure en XML par attribut

Je pourrais bien sûr traverser chaque élément mais peut-être que quelqu'un connaît un moyen rapide, SimpleXML - peut-être avec XPath - de filtrer la structure en conséquence?

Notez que le « contexte » est une liste de valeurs séparées par des virgules, mais je pourrais changer cela en une forme plus analysable:

context_new_item="yes" context_edit_item = "no" 

si nécessaire.

Je fouillant dans la documentation SimpleXML moi-même maintenant, il est tout simplement pas la partie la plus large de la documentation PHP ...

Mise à jour: Ce poste est à peine à 13 minutes vieux, et déjà 2 sur Google pour "filtrage simplexml". Merde, je suis impressionné.

Répondre

1

Si vous devez filtrer l'ensemble du document, XPath est le chemin à parcourir. Le problème est SimpleXML ne peut pas supprimer des noeuds arbitraires comme ceci, donc vous devez convert them to DOM puis utiliser parentNode-> removeChild()

Je maintiens une bibliothèque qui fait ce genre de choses, SimpleDOM. Voici comment je le ferais:

include 'SimpleDOM.php'; 

$tab = simpledom_load_string(
    '<tab context="new_item,edit_item"> 
     <input type="text" context="new_item" /> 
     <input type="readonly" context="edit_item" /> 
     <tab context="new_item"> 
     ... 
     </tab> 
    </tab>' 
); 

$context = 'new_item'; 

// will match ",new_item," to ",new_item,edit_item," 
$tab->deleteNodes('//*[contains(concat(",", @context, ","), ",' . $context . ',")]'); 

echo $tab->asXML(); 

Notez qu'il ne pas supprimer le nœud racine, car cela rendrait le document non valide. Si vous ne voulez pas dépendre d'une bibliothèque externe, n'hésitez pas à regarder le code source et à copier/coller ce dont vous avez besoin. Remarque sur l'expression XPath: si les valeurs sont séparées par des virgules, assurez-vous qu'il n'y a rien d'autre que des virgules (pas d'espaces) et que la valeur de l'attribut et la valeur à laquelle elle correspond sont séparées par des virgules.

+0

L'approche xpath seulement n'a pas fonctionné parce qu'il n'a pas préserver ma structure d'arbre. J'utilise maintenant simpledom, fonctionne très bien - merci. –

1

Si vous avez la valeur du « contexte » dans votre application PHP, vous pouvez sélectionner:

$context = "new_item"; 
$xpath = "//*[not(contains(concat(',', normalize-space(@context), ','), ',$context,'))]"; 

Maintenant que vous avez sélectionné tout ce qui est pas dans le contexte souhaité.

Maintenant, si vous aviez cette structure:

<tab context="new_item, edit_item"> 
    <context name="new_item" /> 
    <context name="edit_item" /> 
    <input type="text"> 
    <context name="new_item" /> 
    </input> 
    <input type="readonly"> 
    <context name="edit_item" /> 
    </input> 
    <tab> 
    <context name="new_item" /> 
    ... 
    </tab> 
</tab> 

Vous pouvez le faire plus simple et plus efficace:

$context = "new_item"; 
$xpath = "//*[not(context[@name='new_item'])]"; 

Vous pouvez également utiliser des attributs dédiés si le nombre de contextes possibles est limité.

$context = "new_item"; 
$xpath = "//*[not(context_$context = 'yes')]"; 
+1

Le contexte Wrt, qui utilise des enfants pour énumérer des contextes, facilite la mise en correspondance et réduit les risques de mise à jour. D'un autre côté, il est plus détaillé, donc vous préférerez peut-être utiliser des attributs namespaced, par ex.'' –

+0

Les deux bonnes réponses, merci et je vais maintenant regarder comment je les construis. –