ChatGPT解决这个技术问题 Extra ChatGPT

在 Emacs 上漂亮地打印 XML 文件

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

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

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


J
Juan Garcia

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

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


(sgml-pretty-print (region-beginning) (region-end))
我不确定 sgml-mode 随着时间的推移会发生怎样的变化。今天,我调用了 C-x C-f foo.xmlM-x sgml-mode,然后是 M-x sgml-pretty-print,我的 xml 文件打印得很漂亮。 (好吧,emacs 在完成之前挂了 20 秒或更长时间。在漂亮的打印之前它是一个单行文件,之后是 720 行。)
实际上,我还必须执行 C-x g 才能选择整个缓冲区作为一个区域。
我什至不必切换到 sgml 模式。这是 nXML 模式下的 Mx 命令!
使用 Emacs 26.2,我可以停留在 nXML 模式,选择整个缓冲区 C-x h,然后选择 M-x sgml-pretty-print。 xml 现在将非常格式化
K
Kind Stranger

如果您只需要漂亮的缩进而不引入任何新的换行符,您可以使用以下击键将 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 这样的外部工具。


很好,谢谢。从上面的漂亮打印 defun 中删除 (nxml-mode) 允许它在 emacs 22.2.1 内置的 sgml-mode 中工作。但我修改它以将整个缓冲区 (point-min) 改为 (point-max),因为这是我的主要工作。此外,一个错误:对于您插入的每个换行符,您都需要增加 end。
如何在 Emacs 中使用此功能?我已将功能代码复制并粘贴到暂存缓冲区中并对其进行了评估。现在,我该如何调用这个函数?
在评估 defun 之后,您可以像调用任何其他函数一样调用它:Mx bf-pretty-print-xml-region。 (你不必全部输入,当然,使用制表符补全: Mx bf 应该足够了。)你可能不想每次要使用它时都定义函数,所以把它放在某个地方它在开始时加载的位置,例如在 ~/.emacs.d/init.el
打破长属性列表怎么样?
这太棒了,因为 tidy 抱怨无效的字符编码,并希望我在重新格式化文件之前清理它们!有时重点是查看损坏的 xml 文件的结构,并且 tidy 会拒绝提供帮助。
T
Tim Helmstedt

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

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

"Cu M-| xmllint --format -" 将做同样的事情,用输出替换区域


使用前面的 Mx mark-whole-buffer 将整个缓冲区内容标记为要处理的区域。
J
Jeff Trull

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


到 2013 年底 tidy.el 版本:20111222.1756 无法在带有 wrong type argument: stringp, nil 的 Emacs 24 上运行
@keiw这可能是因为您在没有文件名的缓冲区中执行此操作。得到了同样的错误,至少在我这边。
T
Talespin_Kit

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

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

S
Sean Allred

感谢上面的 Tim Helmstedt,我做了这样的 st:

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

快速简单。非常感谢。


这在 GNU Emacs 24 上给了我一个错误,所以我将最后一行更改为:(indent-region 0 (count-lines (point-min) (point-max)))
C
Community

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

search-forward-regexp 没有指定结束,因此它将对从区域开始到缓冲区结束(而不是区域结束)的内容进行操作

正如 Cheeso 所指出的,现在增量正确结束。

它会在 之间插入一个中断,从而修改它的值。是的,从技术上讲,我们正在修改这里所有内容的值,但是空的开始/结束更可能是重要的。现在使用两个单独的、稍微更严格的搜索来避免这种情况。

仍然有“不依赖外部整洁”等。但是,它确实需要 incf 宏的 cl

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

r
rajashekar

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

<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=

希望这可以帮助。


D
DaveP

Emacs nxml-mode 可以处理呈现的格式,但您必须拆分行。对于根本不值得的较长文件。对较长的文件运行此样式表(最好使用 Saxon,恕我直言,行缩进正确)以获得漂亮的打印效果。对于要保留空格的任何元素,请在“programlisting”旁边添加它们的名称,如“programlisting yourElementName”

高温高压


C
Community

我采用 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!"))

c
cnu

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

无论如何,这个问题困扰了我大约一个星期,我没有正确搜索。发布后,我开始搜索,发现一个带有 elisp function 的网站做得很好。作者还建议使用 Tidy。

感谢马塞尔的回答(太糟糕了,我没有足够的积分来升级你)。

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


J
Jarekczek

我使用 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))
)

J
JohnnyZ

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

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

n
ninrod

自 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/


佚名

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