Emacs üzerinde güzel baskı XML dosyaları


84

Xml dosyalarımı (nxml modu) düzenlemek için emacs kullanıyorum ve dosyalar makine tarafından oluşturulmuş herhangi bir etiket biçimlendirmesine sahip değil.

Tüm dosyayı girintili olarak yazdırmak ve kaydetmek için aradım, ancak otomatik bir yol bulamadım.

Bir yolu var mı? Veya linux üzerinde bunu yapabilen bir düzenleyici en azından.

Yanıtlar:


25

XML veya HTML'yi biçimlendirmek ve girintilemek istediğimde düzenleme ve Tidy için nXML modunu kullanıyorum . Ayrıca Tidy'ye bir Emacs arayüzü de vardır .


2013'ün sonunda tidy.el Sürümü: 20111222.1756, Emacs 24'tewrong type argument: stringp, nil
keiw

@keiw Muhtemelen bunu dosya adı olmayan bir arabellekte yaptığınız içindir. Aynı hatayı aldım ve en azından benim tarafımda izledim.
Alf

110

Kendi işlevinizi yazmanıza bile gerek yok - sgml-mode (bir gnu emacs çekirdek modülü), bölge başlangıcı ve sonu argümanlarını alan (sgml-pretty-print ...) adında yerleşik bir güzel yazdırma işlevine sahiptir.

Eğer xml kesip yapıştırıyorsanız ve terminalinizin satırları rastgele yerlerde kestiğini fark ederseniz, önce kesik çizgileri düzelten bu güzel yazıcıyı kullanabilirsiniz .


1
(sgml-pretty-print (bölge-başlangıcı) (bölge-sonu))
ScootyPuff

7
sgml-modeZamanla nasıl değişmiş olabileceğinden emin değilim . Bugün, çağırdım C-x C-f foo.xml, M-x sgml-modesonra M-x sgml-pretty-printve xml dosyam oldukça basıldı. (Tamam, emacs tamamlamadan önce yirmi saniye veya daha fazla asıldı. Güzel baskıdan önce tek satırlık bir
dosyaydı

1
Aslında, C-x gtüm tamponu bir bölge olarak seçmek zorunda kaldım .
daveloyall

3
Sgml moduna geçmek zorunda bile değildim. NXML modunda bir Mx komutuydu!
nroose

1
Emacs 26.2'yi kullanarak nXML modunda kalabilirim, tüm arabelleği seçebilir C-x hve sonra M-x sgml-pretty-print. Xml şimdi oldukça biçimlendirilmiş olacak
03'te Swedgin

87

Yeni satır sonu eklemeden yalnızca oldukça girintileme yapmanız gerekiyorsa indent-region, şu tuş vuruşlarıyla komutu arabelleğin tamamına uygulayabilirsiniz :

C-x h
C-M-\

Açma ve kapama etiketlerinin ayrı satırlarda olması için satır sonlarını da tanıtmanız gerekiyorsa, Benjamin Ferrari tarafından yazılan aşağıdaki çok güzel elisp işlevini kullanabilirsiniz . Onu blogunda buldum ve burada yeniden üretmemin benim için sorun olmayacağını umuyorum:

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

Bu, Tidy gibi harici bir araca bağlı değildir.


1
İyi defun, teşekkürler. (Nxml-kipini) yukarıdaki güzel baskı defun'dan kaldırmak, onun emacs 22.2.1'de yerleşik olan sgml-kipinde çalışmasını sağlar. Ama tüm arabelleği (nokta-min) (nokta-maks) yapmak için değiştirdim çünkü bu benim ana işim. Ayrıca bir hata: Eklediğiniz her yeni satır için sonu artırmanız gerekecek.
Cheeso

Bu işlevi Emacs'ta nasıl kullanabilirim? Ben kopyalanıp fonksiyonu kodu yapıştırdıysanız karalama tampon ve onu değerlendirdik. Şimdi, bu işlevi nasıl çağırırım?
Alexandre Rademaker

1
Defun'u değerlendirdikten sonra, onu herhangi bir işlev gibi çağırabilirsiniz: Mx bf-pretty-print-xml-region. (Hepsini yazmak zorunda değilsiniz, elbette sekme tamamlamayı kullanın: Mx bf <tab> yeterli olmalıdır.) Muhtemelen her kullanmak istediğinizde işlevi tanımlamak istemezsiniz, bu yüzden bir yere koyun başlangıç ​​zamanında yüklendiği yer, örneğin ~ / .emacs.d / init.el
Christian Berg

1
Uzun öznitelik listelerini bozmaya ne dersiniz?
33'te yanıtlanıyor

Bu harika, çünkü tidy geçersiz karakter kodlamalarından şikayet ediyor ve dosyayı yeniden biçimlendirmeden önce onları temizlememi istiyor ! Bazen önemli olan, bozuk bir xml dosyasının yapısını görmektir ve düzenli, yardım etmeyi reddeder.
TauPan

35

Emacs, M- | ile rastgele komutlar çalıştırabilir. Eğer xmllint yüklüyse:

"M- | xmllint --format -" seçilen bölgeyi biçimlendirecek

"Cu M- | xmllint --format -" aynı şeyi yapacak ve bölgeyi çıktıyla değiştirecektir


Tüm arabellek içeriğini işlenecek bölge olarak işaretlemek için öndeki Mx mark-tüm-arabelleği kullanın.
Harald

19

Yukarıdaki Tim Helmstedt sayesinde bu şekilde st yaptım:

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

hızlı ve kolay. Çok teşekkürler.


2
Bu bana GNU Emacs 24'te bir hata verdi, bu yüzden son satırı şu şekilde değiştirdim:(indent-region 0 (count-lines (point-min) (point-max)))
John J. Camilleri

19

Satır sonlarını tanıtmak ve ardından güzel yazdırmak için

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

8

Benjamin Ferrari'nin versiyonunda yaptığım birkaç ince ayar:

  • search-forward-regexpo tampon sonuna kadar bölgenin baştan şeyler üzerinde faaliyet yüzden, bir son belirtmedi (yerine bölgenin sonu)
  • Şimdi artışlar endCheeso'nun da belirttiği gibi düzgün bir şekilde artıyor.
  • <tag></tag>değerini değiştiren bir ara eklerdi. Evet, teknik olarak burada her şeyin değerlerini değiştiriyoruz, ancak boş bir başlangıç ​​/ bitiş önemli olması çok daha olası. Artık bundan kaçınmak için iki ayrı, biraz daha katı arama kullanıyor.

Hala "harici düzenlemeye güvenmiyor" vb. Var. Ancak, makro cliçin gerekli 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!"))

5

Yapmanın bir yolu, aşağıdaki formatta bir şeyiniz varsa

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

Emacs'ta deneyin

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

Bu, xml örneğinin yukarısını aşağıya doğru girintiler

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

VIM'de bunu şu şekilde yapabilirsiniz:

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

Bu yardımcı olur umarım.


2
  1. Emacs nxml modu sunulan formatta çalışabilir, ancak satırları bölmeniz gerekir.
  2. Buna değmeyen daha uzun dosyalar için. Güzel ve hoş bir baskı elde etmek için bu stil sayfasını (ideal olarak IMHO'nun satır girintilerini doğru aldığı Saxon ile) daha uzun dosyalara karşı çalıştırın. Beyaz alanı korumak istediğiniz herhangi bir öğe için, adlarını, "ÖğenizinAdını programlamada" olduğu gibi "program listesi" nin yanına ekleyin.

HTH


2

Ben aldı Jason Viers' versiyonunu kendi hatlarında xmlns bildirimleri koymak ve katma mantığı. Bu, aradaki boşluk olmadan xmlns = ve xmlns: 'e sahip olduğunuzu varsayar.

(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

Tidy iyi bir moda benziyor. Bakmalıyım. Sunduğu tüm özelliklere gerçekten ihtiyacım olursa kullanacağım.

Her neyse, bu sorun beni yaklaşık bir haftadır rahatsız ediyordu ve düzgün bir şekilde aramıyordum. Gönderdikten sonra aramaya başladım ve oldukça iyi olan elisp işlevine sahip bir site buldum . Yazar ayrıca Tidy kullanmayı öneriyor.

Cevabınız için teşekkürler Marcel (çok kötü, seni modifiye etmek için yeterli puanım yok) .

Yakında blogumda yayınlayacağım. İşte bununla ilgili bir gönderi (Marcel'in sitesine bir bağlantı ile).


1

Kullandığım xml-reformat-tagsgelen xml-parse.el . Genellikle bu komutu çalıştırırken noktanın dosyanın başlangıcında olmasını istersiniz.

Dosyanın Emacspeak'e dahil edilmiş olması ilginç . Emacspeak'i günden güne kullandığımda xml-reformat-tags, bir Emacs yerleşik olduğunu düşündüm . Bir gün onu kaybettim ve bunun için internet araştırması yapmak zorunda kaldım ve böylece yukarıda bahsedilen wiki sayfasına girdim.

Xml ayrıştırmasını başlatmak için kodumu da ekliyorum. Bunun Emacs kodunun en iyi parçası olup olmadığından emin değilim, ama benim için çalışıyor gibi görünüyor.

(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

Eğer kullanırsanız spacemacs , sadece komut 'spacemacs / girinti-bölge-ya-tampon kullanabilirsiniz.

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

1

2017 itibariyle emacs zaten varsayılan olarak bu özellik ile birlikte gelir, ancak bu küçük işlevi aşağıdakilere yazmanız gerekir ~/.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))))

o zaman sadece ara M-x reformat-xml

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


0

Korkarım Benjamin Ferrari versiyonunu daha çok seviyorum. Dahili güzel baskı her zaman bitiş etiketini değerden sonra yeni bir satıra yerleştirir ve etiket değerlerine istenmeyen CR ekler.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.