2010-03-18 6 views
8

J'ai ce cas d'utilisation d'un fichier xml avec entrée commeCombiner plusieurs lignes en une seule ligne

Input: 
<abc a="1"> 
    <val>0.25</val> 
</abc> 
<abc a="2"> 
    <val>0.25</val> 
</abc> 
<abc a="3"> 
    <val>0.35</val> 
</abc> 
... 

Output: 
<abc a="1"><val>0.25</val></abc> 
<abc a="2"><val>0.25</val></abc> 
<abc a="3"><val>0.35</val></abc> 

J'ai autour de 200K lignes dans un fichier au format d'entrée, comment puis-je convertir rapidement cela en format de sortie .

Répondre

3

Dans vim, vous pouvez le faire avec

:g/<abc/ .,/<\/abc/ join! 

Normalement: join ajoute un espace à la fin de chaque ligne avant de rejoindre, mais le ! supprime cela.

En général, je recommande d'utiliser une bibliothèque d'analyse XML appropriée dans un langage tel que Python, Ruby ou Perl pour manipuler des fichiers XML (je recommande Python + ElementTree), mais dans ce cas, il est assez simple solution regex.

+0

Merci! C'est exactement ce dont j'avais besoin! –

+0

J'ai une solution similaire, seulement parce qu'il restera des espaces entre> et < ': g/val/norme kJxJx' mais si cela ne vous dérange pas avec cela, faites juste: ' g/val/norme kJJ' – SergioAraujo

0

perl doublure inélégante qui devrait faire l'affaire, mais pas particulièrement rapidement.

cat file | perl -e ' 
    $x=0; 
    while(<>){ 
     s/^\s*(\S*(?:\s+\S+)*)\s*$/$1/g; 
     print; 
     $x++; 
    if($x==3){ 
     print"\n"; 
     $x=0; 
    } 
}' > output 
+0

Au lieu de fichier' 'chat, il suffit d'utiliser' Arkku

+0

@Arkku - fonctionnerait aussi bien. C'est une vieille habitude à moi, et je suis plus à l'aise avec cat $ FILE | – zellio

+0

Il allume un «chat» inutile, cependant. Sur certains systèmes fortement restreints, le nombre de processus simultanés auxquels il compte est limité. En outre, cela peut être un ralentissement significatif si le processus lui-même est un lecteur rapide, par ex. essayez 'cat/dev/zero | dd bs = 1k compte = 1000' vs 'dd bs = 1k compte = 1000 Arkku

0

Vous pouvez le faire:

perl -e '$i=1; while(<>){chomp;$s.=$_;if($i%3==0){$s=~s{>\s+<}{><};print "$s\n";$s="";}$i++;}' file 
+0

chomp n'est pas bon parce qu'il laisse derrière lui trop d'espace, à moins que notre interlocuteur ne soit d'accord avec ça. – zellio

+0

@Mimisbrunnr: si vous regardez attentivement j'utilise une regex pour se débarrasser des espaces supplémentaires. – codaddict

+0

Je m'excuse, j'ai parlé avant de lire entièrement votre code. – zellio

1
$ awk ' 
    /<abc/ && NR > 1 {print ""} 
    {gsub(" +"," "); printf "%s",$0} 
' file 
<abc a="1"> <val>0.25</val></abc> 
<abc a="2"> <val>0.25</val></abc> 
<abc a="3"> <val>0.35</val></abc> 
+0

+1 Vous voudrez également: 'END {print" "}} pour vous assurer que le fichier se termine par un saut de ligne. –

0
sed '/<abc/,/<\/abc>/{:a;N;s/\n//g;s|<\/abc>|<\/abc>\n|g;H;ta}' file 
0
tr "\n" " "<myfile|sed 's|<\/abc>|<\/abc>\n|g;s/[ \t]*<abc/<abc/g;s/>[ \t]*</></g' 
1

Bash:

while read s; do echo -n $s; read s; echo -n $s; read s; echo $s; done < file.xml 
1

Vous pouvez enregistrer une macro. Fondamentalement ce que je ferais est de commencer avec mon curseur au début de la première ligne. Appuyez sur 'qa' (enregistre la macro dans le registre). La presse shift-V à être en mode visuel ligne par ligne. Ensuite, recherchez la balise de fin '// abc'. Ensuite, appuyez sur Maj + J pour joindre les lignes. Ensuite, vous devrez déplacer le curseur sur l'étiquette suivante, probablement avec 'j ^' et appuyez sur 'q' pour arrêter l'enregistrement. Vous pouvez ensuite relancer l'enregistrement avec '@a' ou spécifier 10000 @ a si vous le souhaitez. Si les tags sont différents ou pas les uns après les autres, vous avez juste besoin de changer la façon dont vous trouvez les balises d'ouverture et de fermeture pour les recherches ou quelque chose comme ça.

+0

C'est une solution basée sur vim ... –

4

En Vim:

  • position sur la première ligne
  • qq: commencer l'enregistrement macro
  • gJgJ: joint deux lignes sans ajouter des espaces
  • j: descendre
  • q: arrêt enregistrement
  • [email protected]: N = Nombre de lignes (en fait environ 1/3 de toutes les lignes qu'ils se condensent sur le pouce)
+0

Après 'gJgJ', n'est pas nécessaire pour' j'. – systemovich

0

Cela devrait fonctionner en mode ex:

:%s/\(^<abc.*>\)^M^\(.*\)^M^\(^<\/abc>\).*^M/\1\2\3^M/g

Je devrais avoir des espaces supplémentaires (ou un onglet entre la valeur), mais vous pouvez l'enlever en fonction de ce que c'est (\ t ou \ \ \ \).

Ce que vous cherchez/remplacement est ici est (motif1) [enter] (pattern2) [enter] (pattern3) [entrer] et le remplacer par (motif1) (pattern2) (pattern3) [enter]

Le

^m est fait avec ctrl + v CTRL + m

1
sed '/^<abc/{N;N;s/\n\| //g}' 

# remove \n or "space" 
# Result 

<abca="1"><val>0.25</val></abc> 
<abca="2"><val>0.25</val></abc> 
<abca="3"><val>0.35</val></abc> 
Questions connexes