在Emacs上漂亮地打印XML文件


84

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

我已经搜索了漂亮的带有缩进的整个文件打印并保存了,但是找不到自动方式。

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

Answers:



108

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

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


1
(sgml-pretty-print(region-beginning)(region-end))
ScootyPuff 2011年

7
我不确定sgml-mode随着时间的流逝会有怎样的变化。今天,我调用了C-x C-f foo.xmlM-x sgml-mode然后M-x sgml-pretty-printxml文件被漂亮地打印了。(好吧,emacs在完成前挂了20秒或更长时间。这是漂亮打印之前的一行文件,之后是720行。)
daveloyall 2015年

1
实际上,我还必须C-x g选择整个缓冲区作为区域。
daveloyall

3
我什至不必切换到sgml-mode。这是nXML模式下的Mx命令!
凌晨

1
使用Emacs 26.2,我可以保持在nXML模式,选择整个缓冲区C-x h,然后选择M-x sgml-pretty-print。xml现在将进行漂亮的格式化
瑞典

87

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

C-x h
C-M-\

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

(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") (setq end (1+ end)))
    (indent-region begin end))
  (message "Ah, much better!"))

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


1
祝你好运,谢谢。从上面的漂亮打印defun中删除(nxml-mode)使其可以在emacs 22.2.1内置的sgml-mode下工作。但是我修改了它,以便将整个缓冲区(最小点)更改为(最大点),因为这是我的主要任务。另外,还有一个错误:对于您插入的每个换行符,您都需要增加end。
Cheeso

如何在Emacs中使用此功能?我已将功能代码复制并粘贴到暂存缓冲区中并对其进行了评估。现在,如何调用此功能?
亚历山大·拉德梅克

1
评估defun之后,您可以像调用其他任何函数一样调用它:Mx bf-pretty-print-xml-region。(当然,您不必键入所有内容,只需使用制表符补全:Mx bf <tab>就足够了。)您可能不想每次都定义函数,因此请将其放在某个位置在开始时加载的位置,例如〜/ .emacs.d / init.el
Christian Berg,

1
打破长属性列表怎么样?
ceving 2012年

这太棒了,因为整洁地抱怨无效的字符编码,并希望我将文件重新格式化之前将其清除!有时,关键是要查看损坏的xml文件的结构,而整洁的工具将拒绝帮助。
陶潘

35

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

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

“ Cu M- | xmllint --format-”将执行相同的操作,将区域替换为输出


在前面使用Mx mark-whole-buffer将整个缓冲区内容标记为要处理的区域。
哈拉尔德

19

感谢上面的蒂姆·赫尔姆施泰特,我这样写了:

(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)))

快速简便。非常感谢。


2
这给了我GNU Emacs 24错误,所以我将最后一行更改为:(indent-region 0 (count-lines (point-min) (point-max)))
John J. Camilleri 2014年

19

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

M-x sgml-mode
M-x sgml-pretty-print

8

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

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

仍然有“不依靠外部整洁”,等等。但是,它需要clincf宏。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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!"))

5

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

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

在Emacs中,尝试

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

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

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

在VIM中,您可以通过

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

希望这可以帮助。


2
  1. Emacs nxml-mode可以使用呈现的格式,但是您必须分开行。
  2. 对于更长的文件,这根本不值得。针对较长的文件运行此样式表(最好是使用Saxon,IMHO可以使行缩进正确),以获取漂亮的打印效果。对于要保留空格的任何元素,请在“ programlisting”旁边添加其名称,如“ programlisting yourElementName”

高温超导


2

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

(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!"))

1

整洁看起来像一个好模式。必须看看它。如果我真的需要它提供的所有功能,将使用它。

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

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

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


1

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

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

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

(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

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

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

1

截至2017年,emacs默认已经具有此功能,但是您必须将此小功能写入您的~/.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))))

然后打电话 M-x reformat-xml

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


0

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.