Récupération et changement string [BASH] - Shell/Batch - Programmation
Marsh Posté le 07-07-2014 à 21:03:14
salut,
Code :
|
mais bon, si tu dois traiter souvent des fichiers xml, il vaut mieux investir ton temps dans l'apprentissage d'XSLT, xsltproc, ou xmlstarlet.
Marsh Posté le 07-07-2014 à 21:41:12
Sous unix (ça peut aussi marcher sous windows, mais en prenant certaines précautions dues aux interprétations des quotes par le shell):
perl -pe 's|(?<=\Q<Attribute name="CESTEST">\E)(.{0,18}+)(.*)(?=\Q</Attribute>\E)|$1|' monfichier.xml
A la base c'est un substitute s/// mais je remplace le / habituel par un |, d’où un s||| à cause de la présence d'un / dans la balise fermante.
On cherche un groupe de entre 0 et 18 caractères, de manière greedy, suivi éventuellement d'autres caractères (.{0,18}+)(.*), groupe qu'on va garder
Avec un contexte <Attribute name="CESTEST"> à gauche (?<=\Q<Attribute name="CESTEST">\E) (le \Q...\E sert a bloquer l'interprétation de caractères comme ayant un sens d'opérateur de la regexp)
et avec un contexte </Attribute> à droite (?=\Q</Attribute>\E)
La forme plus conventionnelle (et sans les \Q...\E en fait inutiles sauf pour la lisibilité ici) s/(?<=<Attribute name="CESTEST"> )(.{0,18}+)(.*)(?=<\/Attribute> )/$1/ marche aussi, bien sur, mais est nettement moins lisible.
A+,
Marsh Posté le 08-07-2014 à 09:49:47
Merci BEAUCOUP pour votre aide.
Ca fonctionne sur plein de fichiers SAUF (et je viens de découvrir le cas) sur des fichiers xml où les balises se suivent... On parle par exemple de fichier xml de 200ko où toutes les balises sont stockées sur... une seule ligne... Avec ta formule sur ce type de fichier, il va traiter la première balise et s'arrêter. J'aurai besoin que le script poursuive la recherche.
Je précise que je ne suis pas auteur de ces fichiers
Marsh Posté le 08-07-2014 à 09:59:07
Pour info, une version fonctionnelle
cat fichier.xml |\
awk '{
n=match($0,"\"CESTEST\"" )
if( n==0)
{
print $0
}
else
{
m=index(substr($0,n),">" )
o=index(substr($0,m+n),"<" )
if(o < 18 )
{
print $0
}
else
{
print substr($0,1,m+n+17) substr($0,m+n+o-1)
}
}
}'
Merci encore pour votre aide
Marsh Posté le 08-07-2014 à 11:19:56
LeBidule75 a écrit : |
Voila pourquoi il faut préciser les choses dans son post initial.
Si tu peux avoir plusieurs tags <Attribute...> sur une même ligne, alors il suffit de faire:
perl -pe 's|(?<=\Q<Attribute name="CESTEST">\E)([^<]{0,18}+)([^<]*)(?=\Q</Attribute>\E)|$1|g' monfichier.xml
le g final c'est pour faire une substitution incrémentale sur la ligne, et remplacer . par [^<] (tout caractère sauf < ) évitera d'être trop greedy et de faire la troncature entre le premier tag ouvrant <Attribute name="CESTEST"> et le dernier tag fermant </Attribute> de la ligne lorsqu'il y a plus d'un tag Attribute par ligne.
Et en dernier, après tests, si tout est ok et qu'on ne veut plus de fichier de backup ajouter l'option -i
perl -i -pe 's|(?<=\Q<Attribute name="CESTEST">\E)([^<]{0,18}+)([^<]*)(?=\Q</Attribute>\E)|$1|g' monfichier.xml
Le seul cas de figure restant ou ça pourrait ne pas marcher, c'est si tu as des tags coupés en deux par un retour de ligne, auquel cas il vaut mieux lire tout le fichier d'un coup et non en mode ligne a ligne
Il y a un trick standard pour cela: le flag -0777
Et pour un match multiline, utiliser l'option de regexp smg et non plus seulement g.
perl -0777 -pe 's|(?<=\Q<Attribute name="CESTEST">\E)([^<]{0,18}+)([^<]*)(?=\Q</Attribute>\E)|$1|smg' monfichier.xml
Mais je doute que tu aies ceci dans ton fichier source, sinon, cela mérite en fait un traitement plus complexe, au cas ou un saut de ligne intervient dans un tag, etc.
A+,
Marsh Posté le 08-07-2014 à 12:41:07
Citation : Ca fonctionne sur plein de fichiers SAUF (et je viens de découvrir le cas) sur des fichiers xml où les balises se suivent... |
une bonne raison supplémentaire pour privilégier XSLT pour le traitement de fichiers XML !
Marsh Posté le 07-07-2014 à 15:51:38
Bonjour à tous,
Je possède plusieurs fichiers XML. Dans chacun d'entre eux, j'ai quelque chose de ce type :
[...]
<Attribute name="V_volume">-1252141245e-015</Attribute>
<Attribute name="V_userZ">Default_User</Attribute>
<Attribute name="majorip">SD25SDSFGH12DSFGH45</Attribute>
<Attribute name="CESTEST">1215DSJFG5SJDF45REIUFTGOHK1558QSHGJKJLLLGE5R6TJ</Attribute>
</RootAttributes>
<Streams>
<Stream format="1" role="">
<Attribute name="majorid">D43DC61B00001BB4538EF3A300051112</Attribute>
<Attribute name="My_user">Default_User</Attribute>
<Attribute name="CESTEST">26XHCJ12SDH</Attribute>
[...]
Ce que j'ai besoin de faire est :
1/ Trouver toutes les lignes qui sont de type <Attribute name="CESTEST">**CONTENU**</Attribute>
2/ Tronquer la valeur **CONTENU** à 18 caractères
3/ Enregistrer l'output
Concrètement, je cherche à avoir l'output suivant :
<Attribute name="V_volume">-1252141245e-015</Attribute>
<Attribute name="V_userZ">Default_User</Attribute>
<Attribute name="majorip">SD25SDSFGH12DSFGH45</Attribute>
<Attribute name="CESTEST">1215DSJFG5SJDF45RE</Attribute>
</RootAttributes>
<Streams>
<Stream format="1" role="">
<Attribute name="majorid">D43DC61B00001BB4538EF3A300051112</Attribute>
<Attribute name="My_user">Default_User</Attribute>
<Attribute name="CESTEST">26XHCJ12SDH</Attribute>
J'ai testé avec sed et awk mais le résultat n'est pas probant car j'arrive à obtenir le 1215DSJFG5SJDF45RE mais les balises ont disparues avec
Merci pour votre aide