ฉันใช้ emac เพื่อแก้ไขไฟล์ xml ของฉัน (โหมด nxml) และไฟล์ที่สร้างขึ้นโดยเครื่องไม่มีการจัดรูปแบบแท็กที่สวยงาม
ฉันค้นหาการพิมพ์สวย ๆ ทั้งไฟล์ด้วยการเยื้องและบันทึก แต่ไม่พบวิธีอัตโนมัติ
มีวิธีไหม? หรืออย่างน้อยตัวแก้ไขบน linux ซึ่งสามารถทำได้
ฉันใช้ emac เพื่อแก้ไขไฟล์ xml ของฉัน (โหมด nxml) และไฟล์ที่สร้างขึ้นโดยเครื่องไม่มีการจัดรูปแบบแท็กที่สวยงาม
ฉันค้นหาการพิมพ์สวย ๆ ทั้งไฟล์ด้วยการเยื้องและบันทึก แต่ไม่พบวิธีอัตโนมัติ
มีวิธีไหม? หรืออย่างน้อยตัวแก้ไขบน linux ซึ่งสามารถทำได้
คำตอบ:
ฉันใช้โหมด nXMLเพื่อแก้ไขและจัดระเบียบเมื่อฉันต้องการจัดรูปแบบและเยื้อง XML หรือ HTML นอกจากนี้ยังมีอินเทอร์เฟซ Emacs เพื่อ Tidy
คุณไม่จำเป็นต้องเขียนฟังก์ชันของคุณเองด้วยซ้ำ - โหมด sgml (โมดูลแกน gnu emacs) มีฟังก์ชันการพิมพ์ที่สวยงามในตัวที่เรียกว่า (sgml-pretty-print ... ) ซึ่งใช้อาร์กิวเมนต์เริ่มต้นและสิ้นสุดของภูมิภาค
หากคุณกำลังตัดและวาง xml และคุณพบว่าเทอร์มินัลของคุณกำลังตัดเส้นในสถานที่ใด ๆ คุณสามารถใช้เครื่องพิมพ์ที่สวยงามนี้ซึ่งจะแก้ไขเส้นที่ขาดก่อน
sgml-mode
จะมีการเปลี่ยนแปลงอย่างไรบ้างเมื่อเวลาผ่านไป วันนี้ผมเรียกC-x C-f foo.xml
, M-x sgml-mode
แล้วM-x sgml-pretty-print
และไฟล์ xml ของฉันได้พิมพ์สวย (อืมอีแมคถูกแขวนคอเป็นเวลายี่สิบวินาทีขึ้นไปก่อนจะเสร็จมันเป็นไฟล์หนึ่งบรรทัดก่อนพิมพ์สวยและ 720 บรรทัดหลังจากนั้น)
C-x g
เลือกบัฟเฟอร์ทั้งหมดเป็นภูมิภาคด้วย
C-x h
M-x sgml-pretty-print
xml จะมีรูปแบบที่สวยงามในขณะนี้
หากคุณต้องการเพียงแค่การเยื้องโดยไม่ต้องขึ้นบรรทัดใหม่คุณสามารถใช้indent-region
คำสั่งกับบัฟเฟอร์ทั้งหมดด้วยการกดแป้นเหล่านี้:
C-x h
C-M-\
หากคุณยังจำเป็นต้องแนะนำสายแบ่งเพื่อให้เปิดและปิดแท็กอยู่บนเส้นที่แยกจากกันคุณสามารถใช้ฟังก์ชั่น 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
Emac สามารถรันคำสั่งตามอำเภอใจด้วย M- | หากคุณติดตั้ง xmllint:
"M- | xmllint --format -" จะจัดรูปแบบภูมิภาคที่เลือก
"Cu M- | xmllint --format -" จะทำเช่นเดียวกันโดยแทนที่ภูมิภาคด้วยเอาต์พุต
ขอบคุณ 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)))
ง่ายและรวดเร็ว ขอบคุณมาก.
(indent-region 0 (count-lines (point-min) (point-max)))
สำหรับการแนะนำตัวแบ่งบรรทัดแล้วพิมพ์สวย ๆ
M-x sgml-mode
M-x sgml-pretty-print
นี่คือการปรับแต่งเล็กน้อยที่ฉันทำกับเวอร์ชันของ Benjamin Ferrari:
search-forward-regexp
ไม่ได้ระบุสิ้นจึงจะดำเนินการในสิ่งที่จากจุดเริ่มต้นของภูมิภาคที่จะสิ้นสุดของบัฟเฟอร์ (แทนของการสิ้นสุดของภูมิภาค)end
อย่างถูกต้องตามที่ Cheeso กล่าวไว้<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!"))
วิธีหนึ่งในการทำคือหากคุณมีบางอย่างในรูปแบบด้านล่าง
<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=
หวังว่านี่จะช่วยได้
HTH
ฉันใช้เวอร์ชันของ 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!"))
Tidy ดูเหมือนเป็นโหมดที่ดี ต้องดูเลย. จะใช้ถ้าฉันต้องการคุณสมบัติทั้งหมดที่มีให้จริงๆ
อย่างไรก็ตามปัญหานี้รบกวนฉันมาประมาณหนึ่งสัปดาห์แล้วและฉันก็ค้นหาไม่ถูกต้อง หลังจากโพสต์ฉันเริ่มค้นหาและพบไซต์หนึ่งที่มีฟังก์ชัน elispซึ่งทำได้ดีทีเดียว ผู้เขียนยังแนะนำให้ใช้ Tidy
ขอบคุณสำหรับคำตอบ Marcel (แย่จังฉันมีคะแนนไม่พอที่จะอัปโมดคุณ)คุณ)
จะโพสต์เกี่ยวกับเรื่องนี้ในบล็อกของฉันเร็ว ๆ นี้ นี่คือโพสต์เกี่ยวกับเรื่องนี้ (พร้อมลิงก์ไปยังเว็บไซต์ของ Marcel)
ผมใช้xml-reformat-tags
จากXML-parse.el โดยปกติคุณจะต้องมีจุดที่จุดเริ่มต้นของไฟล์เมื่อเรียกใช้คำสั่งนี้
มันเป็นเรื่องที่น่าสนใจที่ไฟล์จะถูกรวมอยู่ใน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))
)
หากคุณใช้spacemacsให้ใช้คำสั่ง 'spacemacs / indent-region-or-buffer'
M-x spacemacs/indent-region-or-buffer
ในปี 2017 emac มาพร้อมกับความสามารถนี้แล้วโดยค่าเริ่มต้น แต่คุณต้องเขียนฟังก์ชันเล็ก ๆ นี้ลงใน~/.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 ที่ไม่ต้องการในค่าแท็ก
wrong type argument: stringp, nil