DEV Community

Cover image for Format XML in Notepad++, VS Code, xmllint and Python
Ayoub Kharbouch
Ayoub Kharbouch

Posted on Originally published at xmlnest.com AI-assisted

Format XML in Notepad++, VS Code, xmllint and Python

Notepad++ and VS Code do not format XML on their own: each needs a free extension, and then one shortcut does the job. xmllint and Python do it from a terminal or a script. Here are the menu paths, shortcuts and commands to format XML in Notepad++, VS Code, xmllint and Python, and the two Python traps that leave a file full of blank lines or not indented at all.

Which tool should you use to format XML?

The one you already have open. Formatting, also called pretty-printing, adds line breaks and indentation between elements. The data does not change, and a program that reads the file sees the same document. The four tools below give the same kind of result:

  • Notepad++ with the XML Tools plugin: Ctrl+Alt+Shift+B.
  • VS Code with the XML extension by Red Hat: Shift+Alt+F.
  • xmllint, on Linux, macOS or WSL: xmllint --format file.xml.
  • Python, for scripts that handle many files: minidom, ElementTree.indent() or lxml.

All of them need well-formed XML. If a tag is not closed, they refuse to format the file and point to a line number, which is where to start looking.

If you only want to read a file, you may not need to format it at all. Chrome indents XML by itself: open the XML file in Chrome and you get a tree, even when the file is one long line.

No editor at hand? Our free XML formatter indents a file in your browser, and the XML validator gives the line and column of the first error.

Format XML in Notepad++ with XML Tools

Notepad++ has no XML formatter of its own. The free XML Tools plugin adds one.

  1. Open Plugins > Plugins Admin.
  2. In the Available tab, search for "XML Tools", tick it and click Install. Notepad++ restarts.
  3. Open your XML file, then choose Plugins > XML Tools > Pretty print, or press Ctrl+Alt+Shift+B.

The same menu has variants. Pretty print - indent attributes (Ctrl+Alt+Shift+A) also puts each attribute on its own line, which helps with long elements such as SVG paths or configuration entries. Pretty print - indent only fixes the indentation without adding line breaks. Linearize (Ctrl+Alt+Shift+L) does the reverse: it puts the whole document back on one line, which is handy before pasting XML into a test or a string.

If the shortcut seems to do nothing, run Plugins > XML Tools > Check XML syntax now. It reports the first error in the file. And if XML Tools is missing from Plugins Admin, its README describes the manual install: create an XMLTools folder in the plugins folder of Notepad++, copy XMLTools.dll into it, and restart.

Format XML in VS Code with the XML extension

VS Code formats JavaScript, TypeScript, JSON, HTML and CSS out of the box, but not XML. Run Format Document on an XML file without an extension, and VS Code tells you that no formatter is installed for XML files.

  1. Open the Extensions view (Ctrl+Shift+X), search for "XML" and install XML by Red Hat. Since version 0.15, it runs without Java.
  2. Open your file and press Shift+Alt+F on Windows, Shift+Option+F on macOS or Ctrl+Shift+I on Linux. Format Document is also in the Command Palette (Ctrl+Shift+P).
  3. To format only part of the file, select it and use Format Selection (Ctrl+K Ctrl+F).

If another installed extension also formats XML, VS Code asks which one to use. To make that choice permanent, set the indentation for XML only and format on every save, add this to your settings.json:

"[xml]": {
  "editor.defaultFormatter": "redhat.vscode-xml",
  "editor.tabSize": 2,
  "editor.formatOnSave": true
}
Enter fullscreen mode Exit fullscreen mode

The Red Hat extension takes its indentation from editor.tabSize and editor.insertSpaces. Its own settings start with xml.format.: xml.format.splitAttributes decides whether attributes go on separate lines, and xml.format.maxLineWidth sets the maximum line width, 100 characters by default, or no limit with 0.

Format XML on the command line with xmllint

xmllint comes with libxml2. macOS ships it. On Debian and Ubuntu it is in the libxml2-utils package, and on Windows the easiest route is WSL with the same command:

sudo apt install libxml2-utils
Enter fullscreen mode Exit fullscreen mode

Then:

xmllint --format input.xml                          # print the formatted XML
xmllint --format --output pretty.xml input.xml      # write it to a new file
curl -s https://example.com/sitemap.xml | xmllint --format -   # read from a pipe
Enter fullscreen mode Exit fullscreen mode

Do not run xmllint --format file.xml > file.xml: the shell empties the file before xmllint reads it, and you lose it. Write to a new file, then rename it.

The indentation is two spaces by default. The XMLLINT_INDENT environment variable changes it:

XMLLINT_INDENT="    " xmllint --format input.xml   # four spaces
XMLLINT_INDENT=$'\t' xmllint --format input.xml    # tabs, in bash
Enter fullscreen mode Exit fullscreen mode

--format drops the whitespace already present between elements before it indents again, so a file that was badly indented by hand comes out clean. When the XML is not well-formed, xmllint prints the file name, the line and the parser error, and exits with a non-zero code. That makes it a good check in a script or a CI job. To check a file without printing it, use xmllint --noout input.xml.

Pretty-print XML in Python: minidom, ElementTree and lxml

The quickest way in the standard library is xml.dom.minidom:

from xml.dom import minidom

dom = minidom.parse("input.xml")
print(dom.toprettyxml(indent="  "))
Enter fullscreen mode Exit fullscreen mode

It has two traps. On a file that already has line breaks, toprettyxml() keeps the old whitespace and adds its own, so you get empty lines between elements. In our test with Python 3.14, a small indented file came out with blank lines around every child of the root. And without an encoding argument, the declaration it writes has no encoding: <?xml version="1.0" ?>. Pass encoding="UTF-8" to get bytes with the encoding declared.

Since Python 3.9, xml.etree.ElementTree.indent() avoids the first trap, because it replaces the whitespace between elements instead of adding to it:

import xml.etree.ElementTree as ET

tree = ET.parse("input.xml")
ET.indent(tree, space="  ")
tree.write("pretty.xml", encoding="UTF-8", xml_declaration=True)
Enter fullscreen mode Exit fullscreen mode

With lxml (pip install lxml), pretty_print=True only indents elements that have no whitespace around them yet. The lxml FAQ explains why, and gives the fix: parse with remove_blank_text=True first.

from lxml import etree

parser = etree.XMLParser(remove_blank_text=True)
tree = etree.parse("input.xml", parser)
tree.write("pretty.xml", pretty_print=True, xml_declaration=True, encoding="UTF-8")
Enter fullscreen mode Exit fullscreen mode

Without that parser option, our test file kept its one-line element as it was. lxml is also the library we used for server-side XSLT in Python, so a script that transforms files can format the result in the same pass.

Read a long XML file without reformatting it

Formatting is for editing and for clean diffs. To read a long file, a view that folds the structure is often faster than scrolling through thousands of indented lines, and it leaves the file untouched.

Chrome shows local and online XML files as an indented tree with no setup. XMLNest, an XML viewer for Chrome, available on the Chrome Web Store, adds folding, search in element names and values, a source view with line numbers, and the line and column of the error when a file is broken. That tells you where to look before you open the file in Notepad++ or VS Code to fix it.

Sources


This post was first published on xmlnest.com.

Top comments (1)

Collapse
 
alexshev profile image
Alex Shev •

Useful comparison, especially the distinction between a one-off editor action and a scriptable formatter. One guardrail worth calling out for automation: format only after parsing succeeds, and keep an original or use a diff in CI. Pretty-printing normally preserves document meaning, but whitespace-sensitive content, mixed content, and serialization settings can still create surprising review noise if a formatter is run blindly across a repository.