# 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](https://xmlnest.com/guides/open-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](https://xmlnest.com/tools/xml-formatter/) indents a file in your browser, and the [XML validator](https://xmlnest.com/tools/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`:

```json
"[xml]": {
  "editor.defaultFormatter": "redhat.vscode-xml",
  "editor.tabSize": 2,
  "editor.formatOnSave": true
}
```

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:

```bash
sudo apt install libxml2-utils
```

Then:

```bash
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
```

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:

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

`--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`:

```python
from xml.dom import minidom

dom = minidom.parse("input.xml")
print(dom.toprettyxml(indent="  "))
```

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:

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

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.

```python
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")
```

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](https://xmlnest.com/blog/xslt-server-side-php-node-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](https://xmlnest.com/extension/), 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

- [Notepad++ User Manual: Plugins](https://npp-user-manual.org/docs/plugins/)
- [XML Tools for Notepad++, README and menu source of morbac/xmltools on GitHub](https://github.com/morbac/xmltools)
- [Visual Studio Code documentation: Basic editing, Formatting](https://code.visualstudio.com/docs/editing/codebasics)
- [Visual Studio Marketplace: XML by Red Hat](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-xml)
- [vscode-xml documentation: Formatting](https://github.com/redhat-developer/vscode-xml/blob/main/docs/Formatting.md)
- [libxml2: xmllint manual page](https://gnome.pages.gitlab.gnome.org/libxml2/xmllint.html)
- [Debian packages: libxml2-utils](https://packages.debian.org/stable/libxml2-utils)
- [Python documentation: xml.dom.minidom](https://docs.python.org/3/library/xml.dom.minidom.html)
- [Python documentation: xml.etree.ElementTree, indent()](https://docs.python.org/3/library/xml.etree.elementtree.html)
- [lxml FAQ: Why doesn't the pretty_print option reformat my XML output?](https://lxml.de/FAQ.html)

---

*This post was first published on* [*xmlnest.com*](https://xmlnest.com/blog/format-xml-notepad-vscode-xmllint-python/)*.*
