Używam emacsa do edycji moich plików xml (tryb nxml), a pliki wygenerowane przez maszynę nie mają ładnego formatowania tagów.
Szukałem ładnego drukowania całego pliku z wcięciem i zapisywania go, ale nie byłem w stanie znaleźć automatycznego sposobu.
Czy istnieje sposób? Lub przynajmniej jakiś edytor na Linuksie, który to potrafi.
wrong type argument: stringp, nil
Nie musisz nawet pisać własnej funkcji - sgml-mode (podstawowy moduł emacsa GNU) ma wbudowaną ładną funkcję drukującą o nazwie (sgml-pretty-print ...), która pobiera argumenty początku i końca regionu.
Jeśli wycinasz i wklejasz xml i zauważysz, że twój terminal obcina linie w dowolnych miejscach, możesz użyć tej ładnej drukarki, która najpierw naprawia przerywane linie.
źródło
sgml-mode
mogło się to zmienić w czasie. Dzisiaj wywołałemC-x C-f foo.xml
,M-x sgml-mode
i wtedyM-x sgml-pretty-print
mój plik xml został całkiem wydrukowany. (Cóż, emacs wisiał na dwadzieścia sekund lub dłużej przed ukończeniem. Był to plik z jedną linijką przed ładnym wydrukiem i 720 wierszami po.)C-x g
aby wybrać cały bufor jako region.C-x h
i wtedyM-x sgml-pretty-print
. XML będzie teraz dość sformatowanyJeśli potrzebujesz tylko ładnych wcięć bez wprowadzania nowych podziałów linii, możesz zastosować
indent-region
polecenie do całego bufora za pomocą tych naciśnięć klawiszy:C-x h C-M-\
Jeśli chcesz również wprowadzić podziały wierszy, aby znaczniki otwierające i zamykające znajdowały się w osobnych wierszach, możesz użyć następującej bardzo ładnej funkcji elisp, napisanej przez Benjamina Ferrariego . Znalazłem go na jego blogu i mam nadzieję, że mogę go tutaj odtworzyć:
(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!"))
Nie polega to na zewnętrznym narzędziu, takim jak Tidy.
źródło
Emacs może uruchamiać dowolne polecenia za pomocą M- |. Jeśli masz zainstalowany xmllint:
„M- | xmllint --format -” sformatuje wybrany region
"Cu M- | xmllint --format -" zrobi to samo, zastępując region wyjściem
źródło
Dzięki Timowi Helmstedtowi powyżej zrobiłem tak:
(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)))
szybko i łatwo. Wielkie dzięki.
źródło
(indent-region 0 (count-lines (point-min) (point-max)))
Do wprowadzania podziałów wiersza, a następnie ładnego drukowania
M-x sgml-mode M-x sgml-pretty-print
źródło
oto kilka poprawek, które wprowadziłem do wersji Benjamina Ferrariego:
search-forward-regexp
nie określił kres, tak by działać na rzeczy od początku do końca z regionu buforu (zamiast końca regionu)end
rośnie prawidłowo, jak zauważył Cheeso.<tag></tag>
, co modyfikuje jego wartość. Tak, technicznie rzecz biorąc, modyfikujemy tutaj wartości wszystkiego, ale pusty początek / koniec jest znacznie bardziej istotny. Teraz używa dwóch oddzielnych, nieco bardziej ścisłych wyszukiwań, aby tego uniknąć.Nadal ma „nie polega na zewnętrznym porządku” itp. Jednak wymaga
cl
tegoincf
makra.;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; 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ódło
Jednym ze sposobów jest, jeśli masz coś w poniższym formacie
<abc> <abc><abc> <abc></abc> </abc></abc> </abc>
W Emacsie spróbuj
M-x nxml-mode M-x replace-regexp RET > *< RET >C-q C-j< RET C-M-\ to indent
Spowoduje to wcięcie powyższego przykładu XML do poniższego
<abc> <abc> <abc> <abc> </abc> </abc> </abc> </abc>
W VIM możesz to zrobić przez
:set ft=xml :%s/>\s*</>\r</g ggVG=
Mam nadzieję że to pomoże.
źródło
HTH
źródło
Wziąłem wersję Jason Viers' i dodał logiki umieścić deklaracji xmlns na swoich liniach. Zakłada się, że masz xmlns = i xmlns: bez pośrednich spacji.
(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!"))
źródło
Tidy wygląda na dobry tryb. Muszę na to spojrzeć. Użyję go, jeśli naprawdę będę potrzebować wszystkich funkcji, które oferuje.
Zresztą ten problem dokuczał mi przez około tydzień i nie szukałem poprawnie. Po wysłaniu zacząłem szukać i znalazłem jedną witrynę z funkcją elisp, która robi to całkiem nieźle. Autor sugeruje również użycie Tidy.
Dzięki za odpowiedź Marcel
(szkoda, że nie mam wystarczającej liczby punktów, aby cię ulepszyć).Wkrótce opublikuję o tym na moim blogu.Oto post na ten temat (z linkiem do strony Marcela).źródło
Używam
xml-reformat-tags
z xml-parse.el . Zwykle będziesz chciał mieć punkt na początku pliku podczas uruchamiania tego polecenia.Ciekawe, że plik jest włączony do Emacspeak . Kiedy używałem Emacspeak na co dzień, myślałem, że
xml-reformat-tags
to wbudowany Emacs. Pewnego dnia go zgubiłem i musiałem poszukać tego w Internecie, a tym samym wszedłem na wspomnianą powyżej stronę wiki.Załączam również mój kod, aby rozpocząć analizę xml. Nie jestem pewien, czy to najlepszy fragment kodu Emacsa, ale wydaje mi się, że działa dla mnie.
(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)) )
źródło
Jeśli używasz spacemacs , po prostu użyj polecenia „spacemacs / indent-region-or-buffer”.
M-x spacemacs/indent-region-or-buffer
źródło
od 2017 roku emacs ma już tę możliwość domyślnie, ale musisz zapisać tę małą funkcję w swoim
~/.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))))
po prostu zadzwoń
M-x reformat-xml
źródło: https://davidcapello.com/blog/emacs/reformat-xml-on-emacs/
źródło
Obawiam się, że wersja Benjamina Ferrari bardziej mi się podoba. Wewnętrzny ładny wydruk zawsze umieszcza znacznik końcowy w nowym wierszu po wartości, wstawiając niechciane CR w wartościach znaczników.
źródło