Reformatear una gran cantidad de archivos XML


11

Estoy manipulando una gran cantidad de archivos XML dispersos en una estructura de directorio anidada.

Intenté lo siguiente:

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

El problema es que genera la salida XML formateada en la pantalla, pero no cambia el archivo.

¿Cómo puedo cambiar este comando para que se cambie el contenido real del archivo?

Respuestas:


23

Esto se puede hacer finddirectamente usando -exec:

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

Lo que se pasa -execse invocará una vez por cada archivo encontrado con los parámetros de plantilla {}reemplazados por el nombre del archivo actual. El \;final del comando find termina la línea.

El uso de xargsno es realmente necesario en este caso porque necesitamos invocar xmllintuna vez por archivo ya que los nombres de los archivos de entrada y salida deben especificarse dentro de la misma llamada.

xargssería necesario si el comando que se canaliza desde find funciona en varios archivos a la vez y esa lista es larga. No puede hacer eso en este caso, ya que necesita pasar el nombre de archivo único a la --outputopción de xmllint. Sin xargsusted, podría terminar con un error de "Lista de argumentos demasiado larga" si está procesando muchos archivos. xargstambién admite cadenas de reemplazo de archivos con la -Iopción:

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

Haría lo mismo que el find -execcomando anterior. Si alguna de sus carpetas tiene caracteres extraños en espacios similares, deberá usar las -0opciones de findy xargs. Pero usar xargscon -Iimplica la opción -L 1que significa procesar solo 1 archivo a la vez de todos modos, por lo que también puede usar directamente findcon -exec.


@manatwork gracias por las ediciones - dedos pegajosos; o)
didster

Acabo de ejecutar esto y parece funcionar una delicia! Muchas gracias por la pronta y concisa respuesta!
Harry

2
"Esto fallará si la lista de archivos es demasiado grande": No, no fallará (está procesando un solo archivo a la vez), y de hecho find … -execes la forma más directa de hacerlo.
Gilles 'SO- deja de ser malvado'

@Gilles ¡Buen punto! He actualizado mi respuesta en consecuencia.
didster

1
Esto funciona debido al hecho de que xmllintprimero carga el documento xml completo en la memoria y solo luego analiza / escribe. Esto permite el procesamiento de documentos en el lugar.
Gavenkoa

6

Normalmente ataco estos problemas con una capa de indirección. Escribe un script de shell que haga lo que quieras y llámalo. Sugeriría como comienzo

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

Pruébelo a mano en un archivo o dos, luego puede reemplazarlo en los xargs

find . -name "*.xml" -type f | xargs -- xmltidy.sh

Este parece un buen enfoque si tuviera que hacer una manipulación más compleja en el futuro. Gracias por la respuesta.
Harry
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.