Tệp XML in ấn đẹp trên Emacs


84

Tôi sử dụng emacs để chỉnh sửa các tệp xml của mình (chế độ nxml) và các tệp được tạo bằng máy không có bất kỳ định dạng thẻ đẹp nào.

Tôi đã tìm cách in toàn bộ tệp bằng cách thụt lề và lưu nó, nhưng không thể tìm thấy cách tự động.

Là có một cách? Hoặc ít nhất là một số trình soạn thảo trên linux có thể làm điều đó.

Câu trả lời:


25

Tôi sử dụng chế độ nXML để chỉnh sửa và Gọn gàng khi tôi muốn định dạng và thụt lề XML hoặc HTML. Ngoài ra còn có một giao diện Emacs cho Tidy.


Tính đến cuối năm 2013 tidy.el Version: 20111222,1756 không chạy trên Emacs 24 vớiwrong type argument: stringp, nil
keiw

@keiw Đó có thể là do bạn đang thực hiện trong bộ đệm không có tên tệp. Gặp lỗi tương tự và ít nhất đã tìm ra lỗi đó về phía tôi.
Alf

108

Bạn thậm chí không cần phải viết hàm của riêng mình - sgml-mode (một mô-đun lõi của gnu emacs) có một chức năng in ấn đẹp được tích hợp sẵn gọi là (sgml-pretty-print ...) lấy các đối số đầu và cuối vùng.

Nếu bạn đang cắt và dán xml và bạn thấy thiết bị đầu cuối của mình đang cắt các dòng ở những nơi tùy ý, bạn có thể sử dụng máy in đẹp này để sửa các dòng bị hỏng trước tiên.


1
(sgml-pretty-print (region-start) (region-end))
ScootyPuff

7
Tôi không chắc sgml-modecó thể đã thay đổi như thế nào theo thời gian. Hôm nay, tôi đã gọi C-x C-f foo.xml, M-x sgml-modesau đó M-x sgml-pretty-printvà tệp xml của tôi đã được in khá đẹp. (. Vâng, emacs treo cổ trong hai mươi giây hoặc lâu hơn trước khi hoàn tất Đó là một tập tin một dòng trước khi in khá và 720 dòng sau.)
daveloyall

1
Trên thực tế, tôi cũng phải làm C-x gđể chọn toàn bộ vùng đệm như một vùng.
daveloyall

3
Tôi thậm chí không phải chuyển sang chế độ sgml. Đó là một lệnh Mx trong chế độ nXML!
nroose

1
Sử dụng Emacs 26.2, tôi có thể ở chế độ nXML, chọn toàn bộ bộ đệm C-x hvà sau đó M-x sgml-pretty-print. Xml bây giờ sẽ được định dạng khá đẹp
Thụy Điển

87

Nếu bạn chỉ cần thụt lề khá tốt mà không cần giới thiệu bất kỳ dấu ngắt dòng mới nào, bạn có thể áp dụng indent-regionlệnh cho toàn bộ bộ đệm bằng các tổ hợp phím sau:

C-x h
C-M-\

Nếu bạn cũng cần giới thiệu dấu ngắt dòng để thẻ mở và thẻ đóng nằm trên các dòng riêng biệt, bạn có thể sử dụng hàm elisp rất hay sau đây, được viết bởi Benjamin Ferrari . Tôi đã tìm thấy nó trên blog của anh ấy và hy vọng tôi có thể sao chép nó ở đây:

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

Điều này không dựa vào một công cụ bên ngoài như Tidy.


1
Tốt defun, cảm ơn. Loại bỏ (chế độ nxml) khỏi chế độ làm mờ bản in đẹp ở trên cho phép nó hoạt động ở chế độ sgml được tích hợp sẵn trong emacs 22.2.1. Nhưng tôi đã sửa đổi nó để thực hiện toàn bộ bộ đệm (điểm-tối thiểu) thành (điểm-tối đa) vì đó là điều chính của tôi. Ngoài ra, một lỗi: đối với mỗi dòng mới bạn chèn, bạn sẽ cần phải tăng kết thúc.
Cheeso

Làm cách nào để sử dụng chức năng này trong Emacs? Tôi đã sao chép và dán mã chức năng trong bộ đệm đầu và đánh giá nó. Bây giờ, làm cách nào để gọi hàm này?
Alexandre Rademaker

1
Sau khi đánh giá defun, bạn có thể gọi nó giống như bất kỳ hàm nào khác: Mx bf-pretty-print-xml-region. (Tất nhiên, bạn không cần phải gõ tất cả, hãy sử dụng tab hoàn thành: Mx bf <tab> là đủ.) Bạn có thể không muốn xác định hàm mỗi khi bạn muốn sử dụng nó, vì vậy hãy đặt nó ở đâu đó nơi nó được tải tại thời điểm bắt đầu, ví dụ: trong ~ / .emacs.d / init.el
Christian Berg

1
Làm thế nào về việc phá vỡ danh sách thuộc tính dài?
thúc

Điều này thật tuyệt vời, bởi vì gọn gàng phàn nàn về các mã hóa ký tự không hợp lệ và muốn tôi xóa chúng trước khi định dạng lại tệp! Đôi khi vấn đề là bạn thấy cấu trúc của một tệp xml bị hỏng và ngăn nắp sẽ từ chối trợ giúp.
TauPan

35

Emac có thể chạy các lệnh tùy ý với M- |. Nếu bạn đã cài đặt xmllint:

"M- | xmllint --format -" sẽ định dạng vùng đã chọn

"Cu M- | xmllint --format -" se lam the, thay the o khu vuc dau ra


Sử dụng Mx mark-whole-buffer phía trước để đánh dấu toàn bộ nội dung bộ đệm là vùng cần xử lý.
Harald

19

Cảm ơn Tim Helmstedt ở trên, tôi đã viết một câu như thế này:

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

nhanh và dễ. Cảm ơn nhiều.


2
Điều này đã cho tôi một lỗi trên GNU Emacs 24, vì vậy tôi đã thay đổi dòng cuối cùng để:(indent-region 0 (count-lines (point-min) (point-max)))
John J. Camilleri

19

Để giới thiệu ngắt dòng và sau đó in ấn đẹp

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

8

đây là một vài chỉnh sửa tôi đã thực hiện cho phiên bản của Benjamin Ferrari:

  • các search-forward-regexpkhông xác định chấm dứt, vì vậy nó sẽ hoạt động trên công cụ từ bắt đầu của khu vực kết thúc của bộ đệm (thay vì cuối vùng)
  • Bây giờ tăng endđúng cách, như Cheeso đã lưu ý.
  • nó sẽ chèn một dấu ngắt giữa <tag></tag>, điều này sẽ sửa đổi giá trị của nó. Đúng, về mặt kỹ thuật, chúng tôi đang sửa đổi các giá trị của mọi thứ ở đây, nhưng phần đầu / phần cuối trống có nhiều khả năng là đáng kể. Bây giờ sử dụng hai tìm kiếm riêng biệt, nghiêm ngặt hơn một chút để tránh điều đó.

Vẫn có "không dựa vào ngăn nắp bên ngoài", v.v. Tuy nhiên, nó yêu cầu clđối với incfmacro.

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

Một cách để làm là Nếu bạn có một cái gì đó ở định dạng dưới đây

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

Trong Emacs, hãy thử

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

Thao tác này sẽ thụt lề trên ví dụ xml xuống dưới

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

Trong VIM, bạn có thể làm điều này bằng cách

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

Hi vọng điêu nay co ich.


2
  1. Emacs nxml-mode có thể hoạt động trên định dạng được trình bày, nhưng bạn sẽ phải chia nhỏ các dòng.
  2. Đối với các tệp dài hơn đơn giản là không có giá trị. Chạy biểu định kiểu này (lý tưởng nhất là với Saxon mà IMHO lấy thụt lề dòng về bên phải) đối với các tệp dài hơn để có được bản in đẹp. Đối với bất kỳ phần tử nào bạn muốn giữ lại khoảng trắng, hãy thêm tên của chúng cùng với 'danh sách chương trình' như trong 'danh sách chương trình của bạnElementName'

HTH


2

Tôi lấy phiên bản của Jason Viers và thêm logic để đặt các khai báo xmlns trên các dòng của riêng họ. Điều này giả định rằng bạn có xmlns = và xmlns: không có khoảng trắng xen vào.

(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

Ngăn nắp có vẻ là một chế độ tốt. Phải nhìn vào nó. Sẽ sử dụng nó nếu tôi thực sự cần tất cả các tính năng mà nó cung cấp.

Dù sao, vấn đề này đã làm phiền tôi trong khoảng một tuần và tôi đã không tìm kiếm đúng cách. Sau khi đăng bài, tôi bắt đầu tìm kiếm và tìm thấy một trang web có chức năng elisp hoạt động khá tốt. Tác giả cũng gợi ý sử dụng Tidy.

Cảm ơn câu trả lời của Marcel (quá tệ là tôi không có đủ điểm để upmod bạn) .

Sẽ đăng về nó sớm trên blog của tôi. Đây là một bài đăng về nó (với một liên kết đến trang web của Marcel).


1

Tôi sử dụng xml-reformat-tagstừ xml-parse.el . Thông thường bạn sẽ muốn có điểm ở đầu tệp khi chạy lệnh này.

Thật thú vị khi tệp được kết hợp vào Emacspeak . Khi tôi đang sử dụng Emacspeak hàng ngày, tôi nghĩ đó xml-reformat-tagslà một bản dựng sẵn của Emacs. Một ngày nọ, tôi đánh mất nó và phải tìm kiếm trên internet để tìm kiếm nó, và do đó đã vào được trang wiki nói trên.

Tôi cũng đang đính kèm mã của mình để bắt đầu phân tích cú pháp xml. Không chắc đây có phải là đoạn mã Emacs tốt nhất hay không, nhưng có vẻ hiệu quả với tôi.

(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

Nếu bạn sử dụng spacemac , chỉ cần sử dụng lệnh 'spacemacs / indent-region-or-buffer'.

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

1

kể từ năm 2017, emacs đã đi kèm với khả năng này theo mặc định, nhưng bạn phải viết hàm nhỏ này vào ~/.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))))

sau đó chỉ cần gọi M-x reformat-xml

nguồn: https://davidcapello.com/blog/emacs/reformat-xml-on-emacs/


0

Tôi e rằng tôi thích phiên bản Benjamin Ferrari hơn nhiều. Bản in đẹp nội bộ luôn đặt thẻ kết thúc ở một dòng mới sau giá trị, chèn CR không mong muốn vào các giá trị thẻ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.