Bonita impresión de archivos XML en Emacs


Uso emacs para editar mis archivos xml (modo nxml) y los archivos generados por la máquina no tienen ningún formato bonito de las etiquetas.

He buscado bastante impresión de todo el archivo con sangría y guardarlo, pero no fue capaz de encontrar una forma automática.

¿Hay alguna manera? O al menos algún editor en Linux que pueda hacerlo.

Author: Community, 2008-08-15

15 answers

Utilizo modo nXMLpara editar y Ordenado cuando quiero formatear y sangrar XML o HTML. También existe una interfaz Emacs para Tidy.

 24
Author: Marcel Levy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-23 00:59:41

Ni siquiera necesita escribir su propia función - sgml-mode (un módulo gnu emacs core) tiene una función de impresión pretty incorporada llamada (sgml-pretty-print ...) que toma los argumentos region beginning y end.

Si está cortando y pegando xml y encuentra que su terminal está cortando las líneas en lugares arbitrarios, puede usar esta bonita impresora que corrige primero las líneas rotas.

 96
Author: Juan Garcia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-27 16:47:05

Si solo necesita sangrar bastante sin introducir nuevos saltos de línea, puede aplicar el comando indent-region a todo el búfer con estas pulsaciones de teclas:

C-x h
C-M-\

Si también necesita introducir saltos de línea, de modo que las etiquetas de apertura y cierre estén en líneas separadas, podría usar la siguiente función elisp muy agradable, escrita por Benjamin Ferrari. Lo encontré en su blog y espero que esté bien para mí reproducirlo aquí:

(defun bf-pretty-print-xml-region (begin end)
  "Pretty format XML markup in region. You need to have nxml-mode
http://www.emacswiki.org/cgi-bin/wiki/NxmlMode installed to do
this.  The function inserts linebreaks to separate tags that have
nothing but whitespace between them.  It then indents the markup
by using nxml's indentation rules."
  (interactive "r")
  (save-excursion
      (nxml-mode)
      (goto-char begin)
      (while (search-forward-regexp "\>[ \\t]*\<" nil t) 
        (backward-char) (insert "\n"))
      (indent-region begin end))
    (message "Ah, much better!"))

Esto no depende de una herramienta externa como Ordenado.

 85
Author: Christian Berg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-20 16:51:01

Emacs puede ejecutar comandos arbitrarios con M-|. Si tiene xmllint instalado:

"M - / xmllint format format -" formateará la región seleccionada

"C-u M - / xmllint format format -" hará lo mismo, reemplazando la región con la salida

 33
Author: Tim Helmstedt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-02 03:50:04

Gracias a Tim Helmstedt arriba hice st así:

(defun nxml-pretty-format ()
    (interactive)
    (save-excursion
        (shell-command-on-region (point-min) (point-max) "xmllint --format -" (buffer-name) t)
        (nxml-mode)
        (indent-region begin end)))

Rápido y fácil. Muchas gracias.

 18
Author: bubak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-02 16:44:53

Para introducir saltos de línea y luego impresión bonita

M-x sgml-mode
M-x sgml-pretty-print
 14
Author: Talespin_Kit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-31 07:52:00

Aquí hay algunos ajustes que hice a la versión de Benjamin Ferrari:

  • el search-forward-regexp no especificó un final, por lo que operaría en cosas desde el principio de la región hasta el final del búfer (en lugar del final de la región)
  • Ahora incrementa end correctamente, como Cheeso señaló.
  • insertaría una ruptura entre <tag></tag>, que modifica su valor. Sí, técnicamente estamos modificando los valores de todo aquí, pero un inicio/final vacío es mucho más probable que sea significativo. Ahora utiliza dos separados, búsquedas un poco más estrictas para evitar eso.

Todavía tiene el "no depende de externo ordenado", etc. Sin embargo, requiere cl para la macro incf.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; pretty print xml region
(defun pretty-print-xml-region (begin end)
  "Pretty format XML markup in region. You need to have nxml-mode
http://www.emacswiki.org/cgi-bin/wiki/NxmlMode installed to do
this.  The function inserts linebreaks to separate tags that have
nothing but whitespace between them.  It then indents the markup
by using nxml's indentation rules."
  (interactive "r")
  (save-excursion
    (nxml-mode)
    (goto-char begin)
    ;; split <foo><foo> or </foo><foo>, but not <foo></foo>
    (while (search-forward-regexp ">[ \t]*<[^/]" end t)
      (backward-char 2) (insert "\n") (incf end))
    ;; split <foo/></foo> and </foo></foo>
    (goto-char begin)
    (while (search-forward-regexp "<.*?/.*?>[ \t]*<" end t)
      (backward-char) (insert "\n") (incf end))
    (indent-region begin end nil)
    (normal-mode))
  (message "All indented!"))
 7
Author: Jason Viers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-08 17:13:11

Una forma de hacer es Si tiene algo en el siguiente formato

<abc>     <abc><abc>   <abc></abc> </abc></abc>       </abc>

En Emacs, intenta

M-x nxml-mode
M-x replace-regexp RET  > *< RET >C-q C-j< RET 
C-M-\ to indent

Esto sangrará por encima del ejemplo xml a por debajo de

<abc>
  <abc>
    <abc>
      <abc>
      </abc>
    </abc>
  </abc>
</abc>

En VIM puedes hacer esto por

:set ft=xml
:%s/>\s*</>\r</g
ggVG=

Espero que esto ayude.

 5
Author: user1028948,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-04 02:32:33
  1. Emacs nxml-mode puede funcionar en formato presentado, pero tendrá que dividir las líneas.
  2. Para archivos más largos que simplemente no vale la pena. Ejecute esta hoja de estilos (idealmente con Saxon qué IMHO obtiene las sangrías de línea sobre la derecha) contra archivos más largos para conseguir una bonita huella. Para cualquier elemento en el que desee retener espacio en blanco agregue sus nombres junto a 'programlisting' como en 'programlisting yourElementName'

HTH

 2
Author: DaveP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-12 08:14:40

Tomé La versión de Jason Viers y agregué lógica para poner las declaraciones xmlns en sus propias líneas. Esto supone que tiene xmlns= y xmlns: sin espacios en blanco intermedios.

(defun cheeso-pretty-print-xml-region (begin end)
  "Pretty format XML markup in region. You need to have nxml-mode
http://www.emacswiki.org/cgi-bin/wiki/NxmlMode installed to do
this.  The function inserts linebreaks to separate tags that have
nothing but whitespace between them.  It then indents the markup
by using nxml's indentation rules."
  (interactive "r")
  (save-excursion
    (nxml-mode)
    ;; split <foo><bar> or </foo><bar>, but not <foo></foo>
    (goto-char begin)
    (while (search-forward-regexp ">[ \t]*<[^/]" end t)
      (backward-char 2) (insert "\n") (incf end))
    ;; split <foo/></foo> and </foo></foo>
    (goto-char begin)
    (while (search-forward-regexp "<.*?/.*?>[ \t]*<" end t)
      (backward-char) (insert "\n") (incf end))
    ;; put xml namespace decls on newline
    (goto-char begin)
    (while (search-forward-regexp "\\(<\\([a-zA-Z][-:A-Za-z0-9]*\\)\\|['\"]\\) \\(xmlns[=:]\\)" end t)
      (goto-char (match-end 0))
      (backward-char 6) (insert "\n") (incf end))
    (indent-region begin end nil)
    (normal-mode))
  (message "All indented!"))
 2
Author: Cheeso,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:33:24

Tidy parece un buen modo. Debo mirarlo. Lo usaré si realmente necesito todas las características que ofrece.

De todos modos, este problema me estaba molestando durante aproximadamente una semana y no estaba buscando correctamente. Después de publicar, comencé a buscar y encontré un sitio con una función elisp que lo hace bastante bien. El autor también sugiere usar Tidy.

Gracias por responder Marcel (lástima que no tengo suficientes puntos para actualizarte).

Lo publicaremos pronto en mi blog. Aquí hay un post al respecto (con un enlace al sitio de Marcel).

 1
Author: cnu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-16 06:01:12

Uso xml-reformat-tags desde xml-parse.el. Por lo general, querrá tener el punto al principio del archivo cuando ejecute este comando.

Es interesante que el archivo esté incorporado en Emacspeak. Cuando estaba usando Emacspeak día a día, pensé que xml-reformat-tags es un Emacs incorporado. Un día lo perdí y tuve que hacer una búsqueda en Internet para eso, y así entré en la página wiki mencionada anteriormente.

Estoy adjuntando también mi código para iniciar xml-parse. No estoy seguro de si este es el mejor código de Emacs, pero parece funcionar para mí.

(if (file-exists-p "~/.emacs.d/packages/xml-parse.el")
  (let ((load-path load-path))
    (add-to-list 'load-path "~/.emacs.d/packages")
    (require 'xml-parse))
)
 1
Author: Jarekczek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-03 15:30:45

Si usa spacemacs, simplemente use el comando 'spacemacs/indent-region-or-buffer'.

M-x spacemacs/indent-region-or-buffer
 1
Author: JohnnyZ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-10 08:33:32

Me temo que me gusta mucho más la versión de Benjamin Ferrari. La impresión pretty interna siempre coloca la etiqueta final en una nueva línea después del valor, insertando CR no deseado en los valores de la etiqueta.

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-12 18:18:21

A partir de 2017 emacs ya viene con esta capacidad por defecto, pero tienes que escribir esta pequeña función en tu ~/.emacs.d/init.el:

(require 'sgml-mode)

(defun reformat-xml ()
  (interactive)
  (save-excursion
    (sgml-pretty-print (point-min) (point-max))
    (indent-region (point-min) (point-max))))

Entonces solo llama M-x reformat-xml

Fuente: https://davidcapello.com/blog/emacs/reformat-xml-on-emacs/

 0
Author: ninrod,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-07 03:30:12