EmacsでXMLファイルをきれいに印刷する


84

emacsを使用してxmlファイルを編集し(nxml-mode)、ファイルはマシンによって生成されたもので、タグの適切なフォーマットがありません。

インデントを付けてファイル全体をきれいに印刷して保存することを検索しましたが、自動的な方法を見つけることができませんでした。

方法はありますか?または、それを実行できるLinux上の少なくともいくつかのエディター。

回答:


25

編集にはnXMLモードを使用し、XMLまたはHTMLをフォーマットしてインデントする場合はTidyを使用します。TidyへのEmacsインターフェースあります。


2013年末までにtidy.elバージョン:20111222.1756はEmacs 24で実行できませんwrong type argument: stringp, nil
keiw 2013

@keiwこれは、ファイル名のないバッファで実行しているためと考えられます。同じエラーが発生し、少なくとも私の側のエラーまで追跡しました。
アルフ2014年

108

独自の関数を作成する必要はありません。sgml-mode(gnu emacsコアモジュール)には、領域の開始引数と終了引数を受け取る(sgml-pretty-print ...)という組み込みのプリティプリント関数があります。

xmlを切り取って貼り付けていて、端末が任意の場所で行を切り刻んでいることがわかった場合は、最初に破線を修正するこのプリティプリンターを使用できます。


1
(sgml-pretty-print(region-beginning)(region-end))
ScootyPuff 2011年

7
sgml-mode時間の経過とともにどのように変化したのかわかりません。今日、私は呼び出されC-x C-f foo.xmlM-x sgml-modeそして、M-x sgml-pretty-printそして私のxmlファイルはかなり印刷してしまいました。(まあ、emacsは完了する前に20秒以上
ハングしまし

1
実際、C-x gバッファ全体をリージョンとして選択する必要もありました。
daveloyall 2015

3
sgmlモードに切り替える必要すらありませんでした。これはnXMLモードのMxコマンドでした。
nroose 2018

1
Emacsの26.2を使用して、私は、NXMLモードのままバッファ全体を選択することができC-x h、その後とM-x sgml-pretty-print。xmlは今ではきれいにフォーマットされています
スウェーデン

87

改行を導入せずにかなりのインデントが必要な場合は、indent-region次のキーストロークを使用してコマンドをバッファ全体に適用できます。

C-x h
C-M-\

改行も導入する必要があり、開始タグと終了タグが別々の行にある場合は、BenjaminFerrariによって作成された次の非常に優れた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のような外部ツールに依存していません。


1
よろしくお願いします。上記のプリティプリントデファンから(nxml-mode)を削除すると、emacs22.2.1に組み込まれているsgml-modeで動作できるようになります。しかし、それが私の主なものであるため、バッファー全体(point-min)から(point-max)を実行するように変更しました。また、1つのバグ:挿入する改行ごとに、endをインクリメントする必要があります。
Cheeso 2009年

Emacsでこの関数を使用するにはどうすればよいですか?関数コードをコピーしてスクラッチバッファに貼り付け、評価しました。では、この関数を呼び出すにはどうすればよいですか?
Alexandre Rademaker 2011

1
defunを評価した後、他の関数と同じように呼び出すことができます:Mxbf-pretty-print-xml-region。(もちろん、すべてを入力する必要はありません。タブ補完を使用してください。Mxbf<tab>で十分です。)使用するたびに関数を定義する必要はないので、どこかに配置します。開始時に読み込まれる場所、たとえば〜/ .emacs.d / init.el
Christian Berg

1
長い属性リストを壊すのはどうですか?
2012

tidyが無効な文字エンコードについて不平を言い、ファイルを再フォーマットするにそれらをクリーンアップすることを望んでいるので、これは素晴らしいです!壊れたxmlファイルの構造を確認することが重要な場合があり、tidyは支援を拒否します。
TauPan 2016年

35

EmacsはM- |で任意のコマンドを実行できます。xmllintがインストールされている場合:

「M- | xmllint --format-」は、選択した領域をフォーマットします

"Cu M- | xmllint --format-"は同じことを行い、領域を出力に置き換えます


バッファの内容全体を処理する領域としてマークするには、前にMxmark-whole-bufferを使用します。
ハラルド

19

上記のTimHelmstedtのおかげで、私は次のように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)))

速くて簡単。どうもありがとう。


2
:私は最後の行を変更してこれは、GNU Emacsの24日に私にエラーを与えた(indent-region 0 (count-lines (point-min) (point-max)))
ジョン・J. Camilleri

19

改行を導入してからプリティプリントする場合

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

8

ベンジャミンフェラーリのバージョンに加えたいくつかの調整は次のとおりです。

  • search-forward-regexp終了を指定しなかったので、(領域の終わりではなく)領域の最初からバッファの終わりまでのものを操作します
  • endCheesoが指摘したように、適切にインクリメントするようになりました。
  • の間<tag></tag>に区切りを挿入し、その値を変更します。はい、技術的にはここですべての値を変更していますが、空の開始/終了が重要になる可能性がはるかに高くなります。これを回避するために、2つの別々の少し厳密な検索を使用するようになりました。

まだ「外部整理に頼らない」などがあります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!"))

5

1つの方法は、以下の形式のものがある場合です。

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

お役に立てれば。


2
  1. Emacs nxml-modeは提示されたフォーマットで機能しますが、行を分割する必要があります。
  2. 単にそれだけの価値がない長いファイルの場合。このスタイルシート(理想的には、IMHOが行のインデントを正しく取得するSaxonを使用)を長いファイルに対して実行して、きれいな印刷を取得します。空白を保持したい要素については、「programlisting yourElementName」のように、「programlisting」の横に名前を追加します。

HTH


2

私が取ったジェイソン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!"))

1

整頓は良いモードのように見えます。それを見なければなりません。それが提供するすべての機能が本当に必要な場合に使用します。

とにかく、この問題は私を約1週間悩ませ、適切に検索していませんでした。投稿した後、私は検索を開始し、それをかなりうまく行うelisp機能を備えた1つのサイトを見つけました。著者はまた、Tidyの使用を提案しています。

答えてくれてありがとうMarcel (残念ながら私はあなたをアップモッドするのに十分なポイントがありません)

すぐに私のブログに投稿します。これはそれについて投稿です(Marcelのサイトへのリンク付き)。


1

xml-parse.elxml-reformat-tagsから使用しますます。通常、このコマンドを実行するときは、ファイルの先頭をポイントにする必要があります。

ファイルがEmacspeakに組み込まれているのは興味深いことです。Emacspeakを毎日使っていたとき、私は思ったxml-reformat-tagsはEmacsが組み込まれている。ある日、私はそれを失い、それをインターネットで検索しなければならなかったので、上記のwikiページに入りました。

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

1

spacemacsを使用する場合は、コマンド 'spacemacs / indent-region-or-buffer'を使用するだけです。

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

1

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/


0

私はベンジャミンフェラーリバージョンの方がずっと好きだと思います。内部プリティプリントは常に終了タグを値の後の新しい行に配置し、タグ値に不要なCRを挿入します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.