在Emacs上打印漂亮的XML文件

时间:2008-08-15 17:17:15

标签: xml emacs editor

我使用emacs编辑我的xml文件(nxml-mode),并且机器生成的文件没有任何漂亮的标签格式。

我已经搜索了使用缩进打印整个文件并保存它,但无法找到自动方式。

有办法吗?或者至少有一些Linux编辑可以做到这一点。

15 个答案:

答案 0 :(得分:99)

你甚至不需要编写自己的函数 - sgml-mode(一个gnu emacs核心模块)有一个内置的漂亮的打印函数叫做(sgml-pretty-print ...),它需要区域的开头和结尾参数。

如果您正在剪切和粘贴xml,并且发现终端正在任意位置切断线条,您可以使用此pretty printer来修复断线。

答案 1 :(得分:85)

如果你只需要非常缩进而不引入任何新的换行符,你可以使用这些击键将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"))
      (indent-region begin end))
    (message "Ah, much better!"))

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

答案 2 :(得分:34)

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

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

“C-u M- | xmllint --format - ”也会这样做,用输出替换区域

答案 3 :(得分:25)

当我想格式化和缩进XML或HTML时,我使用nXML mode进行编辑,使用Tidy。还有an Emacs interface to Tidy.

答案 4 :(得分:19)

感谢Tim Helmstedt,我做了这样的事情:

(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)))
快速而简单。非常感谢。

答案 5 :(得分:18)

用于引入换行符然后再打印

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

答案 6 :(得分:8)

这是我对Benjamin Ferrari的版本进行的一些调整:

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

仍有“不依赖外部整洁”等。但是,cl宏需要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 :(得分: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=

希望这有帮助。

答案 8 :(得分:2)

  1. Emacs nxml-mode可以使用呈现的格式,但您必须拆分行。
  2. 对于较长的文件,根本不值得。运行此样式表(理想情况下使用Saxon 对于较长的文件,恕我直言得到关于权利的行缩进 得到一个漂亮的漂亮印刷品。对于要保留空白区域的任何元素 将他们的名字与'programlisting'一起添加,如'programlisting yourElementName'
  3. HTH

             

                     

答案 9 :(得分:2)

我使用Jason Viers' version并添加了逻辑以将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!"))

答案 10 :(得分:1)

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

无论如何,这个问题唠叨了我一个星期,我没有正常搜索。发布后,我开始搜索并找到一个elisp function的网站,这非常好。作者还建议使用Tidy。

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

会很快在我的博客上发布。这是一个post about it(链接到Marcel的网站)。

答案 11 :(得分:1)

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

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

我还附加了我的代码来启动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))
)

答案 12 :(得分:1)

如果您使用spacemacs,只需使用命令&#39; spacemacs / indent-region-or-buffer&#39;。

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

答案 13 :(得分:0)

我恐怕我更喜欢Benjamin Ferrari版本。内部漂亮的打印始终将结束标记放在值之后的新行中,在标记值中插入不需要的CR。

答案 14 :(得分:0)

截至2017年,默认情况下,emacs已经提供此功能,但您必须将此小功能写入(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

然后只需致电{{1}}

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