2009-11-18 1 views
-2

J'ai un fichier XML dans une variable de chaîne ($data), et un hachage contenant tous les noms de balises et leur contenu (%field_list).Comment puis-je rechercher et remplacer du code XML en fonction des valeurs d'un hachage Perl?

Les noms de points doivent être vérifiés de sorte que, s'il s'agit de champs énumérés, leur contenu soit remplacé par des chaînes.

Est-ce que quelqu'un sait s'il est possible de le faire avec la recherche et le remplacement? Je n'ai pas beaucoup de chance en ce moment.

foreach my $field (sort keys %field_list) 
{ 
    my $value = $field_list{$field}; 
    # will return a non-empty string if field is enumerated and value is valid 
    my $enum_string = &convert_enumeration_to_string($field, $value); 
    if ($enum_string ne "") 
    { 
#syntax error 
$data =~ s/<($field)>($value)</($field)>/<($field)>($enum_string)</($field)>/g; 
    } 
} 

Est-ce que quelqu'un sait si je peux faire quelque chose ou ai-je besoin d'une approche complètement différente?

+7

Je ne réponds pas à votre question mais je vous conseille plutôt de le faire. Vous ne devriez vraiment pas utiliser les expressions rationnelles avec xml. Utilisez l'un des nombreux modules XML trouvés sur cpan. Commencer avec XML :: Simple – Nifle

+2

Je voulais juste ajouter du poids à cela parce que d'autres personnes semblent l'encourager passivement en vous donnant une solution - analyser XML avec regex est retardé: d'autres alternatives qui pourraient vous intéresser seraient XML :: Twig ou XML :: LibXML –

+0

S'il vous plaît aller voter pour http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 ;-)) –

Répondre

3

échapper à vos barres obliques:

$data =~ s/<($field)>($value)<\/($field)>/<($field)>($enum_string)<\/($field)>/g; 

Ou utiliser différents deliminators:

$data =~ s{<($field)>($value)</($field)>}{<($field)>($enum_string)</($field)>}g; 
+4

Je recommande de ne pas utiliser '|' comme délimiteur car vous ne pouvez pas utiliser '|' -alternation dans votre modèle. Mon délimiteur de choix est 's {} {}' qui n'interfère généralement avec rien. – friedo

+0

N'y avais pas vraiment pensé. Je vais l'échanger, merci. –

+1

Merci beaucoup. Il est donc possible de rechercher et de remplacer par variable - la seule chose que j'ai manqué est d'oublier d'insérer des barres obliques inverses en face des barres obliques. De plus, les parenthèses ne sont pas nécessaires car cela gâcherait la sortie. – Andy

0

La bonne façon de le faire est:

$data =~ s/<($field)>($value)<\/($field)>/<$field>$enum_string<\/$field>/g; 
+0

Pourquoi cela a-t-il été déprécié? pour être succint? –

+0

Juste deviner, mais l'analyse de XML avec les expressions rationnelles est presque jamais la bonne façon de le faire. – daotoad

+0

Pas besoin de reverser une réponse juste parce que la question était mauvaise. Cela répond à la question. L'autre réponse a été upvoted, et la première partie est identique à ceci (sauf avec cette parenthèse erreur/faute de frappe dans le remplacement). – Cascabel

1

Eh bien, nous allons sauter dans le train en marche XML : utilisez une bibliothèque XML comme XML::LibXML pour manipuler des documents XML.

use XML::LibXML; 
my $dom = XML::LibXML->load_xml(string => $data); 

foreach my $field (sort keys %field_list) { 
    my $value = $field_list{$field}; 
    if (my $enum_string = &convert_enumeration_to_string($field, $value)) { 
     foreach my $node ($dom->findnodes("//xml/${field}[. = '$value']") 
      ->get_nodelist) { 
      my $element = $dom->createElement($field); 
      $element->appendText($enum_string); 
      $node->replaceNode($element); 
     } 
    } 
} 

print $dom->toString;