在Emacs上漂亮地打印XML文件

在Emacs上漂亮地打印XML文件

Pretty printing XML files on Emacs

我使用emacs编辑我的xml文件(nxml-mode),并且这些文件是由计算机生成的,没有任何漂亮的标记格式。

我一直在搜索漂亮的带有缩进的整个文件并保存,但是找不到自动方式。

有办法吗?或者至少在Linux上有一些可以做到的编辑器。


您甚至不需要编写自己的函数-sgml-mode(gnu emacs核心模块)具有一个称为(sgml-pretty-print ...)的内置漂亮打印功能,该功能可以开始和结束区域参数。

如果要剪切和粘贴xml,并且发现终端在任意位置剪切线,则可以使用此漂亮的打印机来首先修复折线。


如果只需要缩进而不引入任何新的换行符,则可以通过以下按键将indent-region命令应用于整个缓冲区:

1
2
C-x h
C-M-\\

如果还需要引入换行符,以使开始和结束标签位于单独的行上,则可以使用由Benjamin Ferrari编写的以下非常好的elisp函数。我在他的博客上找到了它,希望我可以在这里复制它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(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"\
"
) (setq end (1+ end)))
    (indent-region begin end))
  (message"Ah, much better!"))

这不依赖于Tidy之类的外部工具。


Emacs可以使用M- |运行任意命令。如果您已安装xmllint:

" M- | xmllint --format-"将格式化所选区域

" C-u M- | xmllint --format-"将执行相同操作,将区域替换为输出


当我要格式化和缩进XML或HTML时,我使用nXML模式进行编辑和整理。 Tidy还有一个Emacs界面。


用于引入换行符然后进行漂亮的打印

1
2
M-x sgml-mode
M-x sgml-pretty-print

感谢上面的Tim Helmstedt,我这样说过:

1
2
3
4
5
6
(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)))

快速简便。非常感谢。


以下是我对本杰明·法拉利(Benjamin Ferrari)版本的一些调整:

  • search-forward-regexp没有指定结束,因此它将对从区域开始到缓冲区结束(而不是区域结束)的内容进行操作
  • 如Cheeso所述,现在可以正确地增加end
  • 它将在<tag></tag>之间插入一个中断,从而修改其值。是的,从技术上讲,我们正在修改此处所有内容的值,但是空的开始/结束很可能很重要。现在使用两个单独的,更严格的搜索来避免这种情况。

仍然具有"不依赖外部整洁"等。但是,对于incf宏,它确实需要cl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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"\
"
) (incf end))
    ;; split <foo/></foo> and </foo></foo>
    (goto-char begin)
    (while (search-forward-regexp"<.*?/.*?>[ \\t]*<" end t)
      (backward-char) (insert"\
"
) (incf end))
    (indent-region begin end nil)
    (normal-mode))
  (message"All indented!"))

一种方法是
如果您使用以下格式的内容

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

在Emacs中,尝试

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

这会将上面的xml示例缩进到下面的

1
2
3
4
      </abc>
    </abc>
  </abc>
</abc>

在VIM中,您可以通过

1
2
3
4
:set ft=xml
:%s/>\\s*</>\
</g
ggVG=

希望这会有所帮助。


我采用了Jason Viers的版本,并添加了将xmlns声明放在自己的行上的逻辑。假设您有xmlns =和xmlns:且中间没有空格。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
(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"\
"
) (incf end))
    ;; split <foo/></foo> and </foo></foo>
    (goto-char begin)
    (while (search-forward-regexp"<.*?/.*?>[ \\t]*<" end t)
      (backward-char) (insert"\
"
) (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"
\
") (incf end))
    (indent-region begin end nil)
    (normal-mode))
  (message"
All indented!"))

  • Emacs nxml-mode可以使用呈现的格式,但是您必须分开行。
  • 对于更长的文件,这根本不值得。运行此样式表(理想情况下使用Saxon
    哪个恕我直言使行缩进正确)对更长的文件
    以获得漂亮的漂亮印刷品。对于要保留空白的任何元素
    在" programlisting"旁边添加其名称,例如" programlisting yourElementName"
  • HTH


    自2017年起,emacs默认已具有此功能,但是您必须将此小功能写入~/.emacs.d/init.el

    1
    2
    3
    4
    5
    6
    7
    (require 'sgml-mode)

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

    然后只需调用M-x reformat-xml

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


    如果使用spacemacs,只需使用命令'spacemacs / indent-region-or-buffer'。

    1
    M-x spacemacs/indent-region-or-buffer

    我使用xml-parse.el中的xml-reformat-tags。通常,在运行此命令时,您希望将点放在文件的开头。

    有趣的是,该文件已合并到Emacspeak中。当我每天使用Emacspeak时,我认为xml-reformat-tags是Emacs内置的。有一天,我迷失了它,不得不进行互联网搜索,因此进入了上面提到的Wiki页面。

    我还将附加我的代码以启动xml-parse。不确定这是否是Emacs代码的最佳片段,但似乎对我有用。

    1
    2
    3
    4
    5
    (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))
    )

    整理看起来很不错。必须看看它。如果我真的需要它提供的所有功能,将使用它。

    无论如何,这个问题困扰着我大约一个星期,而我的搜索不正确。发布后,我开始搜索并发现一个具有elisp功能的站点,它做得很好。作者还建议使用Tidy。

    感谢您回答Marcel (太可惜,我没有足够的积分来修饰您)

    将很快在我的博客上发布有关它的信息。这是关于它的信息(带有指向Marcel网站的链接)。


    恐怕我会更喜欢本杰明·法拉利(Benjamin Ferrari)版本。内部漂亮的打印件总是将结束标记放置在该值之后的新行中,从而在标记值中插入不需要的CR。


    推荐阅读