Reformatação de um grande número de arquivos XML

11

Estou manipulando um grande número de arquivos XML espalhados por uma estrutura de diretório aninhada.

Eu tentei o seguinte:

$ find . -name "*.xml" -type f | xargs -- xmllint --format

O problema é que gera a saída XML formatada na tela, mas não altera o arquivo.

Como posso alterar este comando para que o conteúdo real do arquivo seja alterado?

atormentar
fonte

Respostas:

23

Isso pode ser feito finddiretamente usando -exec:

find . -name "*.xml" -type f -exec xmllint --output '{}' --format '{}' \;

O que foi passado -execserá chamado uma vez por arquivo encontrado com os parâmetros do modelo {}sendo substituídos pelo nome do arquivo atual. O \;no final do comando find apenas termina a linha.

O uso de xargsrealmente não é necessário nesse caso, porque precisamos chamar xmllintuma vez por arquivo, pois os nomes dos arquivos de entrada e de saída devem ser especificados na mesma chamada.

xargsseria necessário se o comando que está sendo canalizado a partir da localização estivesse trabalhando em vários arquivos por vez e essa lista fosse longa. Você não pode fazer isso neste caso, pois precisa passar o nome do arquivo único para a --outputopção de xmllint. Sem xargsvocê, você pode acabar com um erro "A lista de argumentos é muito longa" se estiver processando muitos arquivos. xargstambém suporta seqüências de substituição de arquivo com a -Iopção:

find . -name "*.xml" -type f | xargs -I'{}' xmllint --output '{}' --format '{}'

Faria o mesmo que o find -execcomando acima. Se alguma de suas pastas tiver caracteres ímpares em espaços iguais, você precisará usar as -0opções de finde xargs. Mas usar xargscom -Iimplica a opção -L 1que significa que apenas processar um arquivo de cada vez qualquer maneira, então você pode também usar diretamente findcom -exec.

didster
fonte
@manatwork graças para as edições - dedos pegajosos; o)
didster
Acabei de executar isso e parece funcionar um prazer! Muito obrigado pela resposta rápida e concisa!
Harry
2
“Isso falhará se a lista de arquivos for muito grande”: Não, não falhará (está processando um único arquivo de cada vez) e, de fato, find … -execé a maneira mais direta de fazer isso.
Gilles 'SO- stop being evil' em
@ Gilles Bom ponto! Atualizei minha resposta de acordo.
Didster 11/10/12
1
Isso funciona devido ao fato de xmllintprimeiro carregar o documento xml completo na memória e somente depois analisar / gravar. Isso permite o processamento no local do documento.
Gavenkoa # 28/18
6

Eu normalmente ataquei esses problemas com uma camada de indireção. Escreva um script de shell que faça o que quiser e chame isso. Eu sugeriria como começo

#! /bin/sh
for file
do
   xmllint --format $file > $file.tmp && mv $file.tmp $file
done

Experimente-o em um ou dois arquivos manualmente, e poderá substituí-lo nos xargs

find . -name "*.xml" -type f | xargs -- xmltidy.sh
Julian
fonte
Parece uma boa abordagem se eu precisar de uma manipulação mais complexa no futuro. Obrigado pela resposta.
Harry