XMLミニファイアー
空白とコメントを削除してXMLを圧縮
XML入力
圧縮されたXML
XMLミニファイとは?
XMLミニファイとは、XMLドキュメントの意味を変えずに不要な文字をすべて削除するプロセスです。XMLミニファイアーはタグ間の空白を取り除き、コメントを削除し、改行をなくし、インデントを圧縮して、コンパクトな1行出力を生成します。結果として得られるXML文字列は、元のフォーマット済みバージョンとまったく同じようにパーサーに読み込まれ、同一のデータモデルを生成します。
XML 1.0仕様(W3C勧告、第5版)はセクション2.10で空白の扱いに関するルールを定義しています。意味的な値を持たないタグ間の空白は「意味のない空白」と呼ばれます。XMLプロセッサーはこれを破棄することが許可されています。ただし、テキストコンテンツ内の空白は、親要素がxml:space="default"を宣言しない限り、デフォルトでは意味を持ちます。正しいXMLミニファイアーはこの2つのケースを区別し、安全に削除できるものだけを削除します。
ミニファイは圧縮(gzip、Brotli)とは異なります。圧縮はトランスポート層でサイズを削減し、解析前に展開が必要です。ミニファイはドキュメント自体の生のサイズを削減するため、XMLは展開不要で任意のパーサーで有効かつ読み取り可能なまま保たれます。実際には、ミニファイ後に圧縮すると最良の結果が得られます。まず冗長な文字を排除し、次に圧縮アルゴリズムがよりコンパクトな入力に対して動作します。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Product catalog for Q1 2026 -->
<catalog>
<product id="p101">
<name>Widget A</name>
<price currency="USD">29.99</price>
<!-- Temporarily discounted -->
<stock>142</stock>
</product>
<product id="p102">
<name>Widget B</name>
<price currency="EUR">19.50</price>
<stock>87</stock>
</product>
</catalog><?xml version="1.0" encoding="UTF-8"?><catalog><product id="p101"><name>Widget A</name><price currency="USD">29.99</price><stock>142</stock></product><product id="p102"><name>Widget B</name><price currency="EUR">19.50</price><stock>87</stock></product></catalog>
XMLミニファイアーを使う理由
インデントとコメント付きのフォーマット済みXMLは開発やコードレビューに最適です。ストレージ、送信、機械処理においては、その余分なフォーマットはメリットなくバイト数を増やすだけです。XMLミニファイアーがそのギャップを埋めます。
XMLミニファイアーの使用例
XMLミニファイが削除するもの
XMLドキュメントのすべての内容が安全に削除できるわけではありません。この参照表は削除可能なコンテンツの種類と、それを破棄することが常に安全か、ユースケース次第かを示しています。
| 項目 | 例 | 安全性 |
|---|---|---|
| Indentation | Spaces/tabs before tags | Always safe to remove |
| Line breaks | \n and \r\n between tags | Always safe to remove |
| Comments | <!-- ... --> | Safe unless parsed by app |
| XML declaration | <?xml version="1.0"?> | Keep if encoding is non-UTF-8 |
| Processing instructions | <?xml-stylesheet ...?> | Keep if consumed downstream |
| Trailing whitespace | Spaces after closing tags | Always safe to remove |
| Text node whitespace | Spaces inside text content | Remove only between tags, not within |
ミニファイ vs Gzip vs バイナリ形式
ミニファイ、圧縮、バイナリエンコードはそれぞれサイズ問題の異なる層に対処します。ミニファイは出力を有効で人間が読めるXMLとして保持します。圧縮(gzip、Brotli)はさらに縮小しますが、解析前に展開ステップが必要です。バイナリ形式は最も圧縮率が高いですが、接続の両端で互換性のあるエンコーダー/デコーダーが必要です — 組み込みシステムやWSDLを多用するエンタープライズサービスで主に実用的です。
コード例
XMLをプログラムでミニファイする処理は、どの言語でも同じパターンに従います。ドキュメントをツリーとして解析し、必要に応じてコメントノードを削除してから、インデントなしでシリアライズします。
// Minify XML by parsing and re-serializing (strips formatting)
const raw = `<root>
<item id="1">
<!-- note -->
<name>Test</name>
</item>
</root>`
const parser = new DOMParser()
const doc = parser.parseFromString(raw, 'application/xml')
// Remove comment nodes
const walker = doc.createTreeWalker(doc, NodeFilter.SHOW_COMMENT)
const comments = []
while (walker.nextNode()) comments.push(walker.currentNode)
comments.forEach(c => c.parentNode.removeChild(c))
const minified = new XMLSerializer().serializeToString(doc)
// → "<root><item id=\"1\"><name>Test</name></item></root>"from lxml import etree
xml = """<root>
<item id="1">
<!-- note -->
<name>Test</name>
</item>
</root>"""
tree = etree.fromstring(xml.encode())
# Remove comments
for comment in tree.iter(etree.Comment):
comment.getparent().remove(comment)
# Serialize without pretty-print (minified)
result = etree.tostring(tree, xml_declaration=False).decode()
# → '<root><item id="1"><name>Test</name></item></root>'
# With xml.etree (stdlib, no lxml needed)
import xml.etree.ElementTree as ET
root = ET.fromstring(xml)
ET.indent(root, space='') # Python 3.9+
print(ET.tostring(root, encoding='unicode'))package main
import (
"encoding/xml"
"fmt"
"strings"
)
func minifyXML(input string) (string, error) {
decoder := xml.NewDecoder(strings.NewReader(input))
var out strings.Builder
encoder := xml.NewEncoder(&out)
// No indentation = minified output
for {
tok, err := decoder.Token()
if err != nil {
break
}
// Skip comments
if _, ok := tok.(xml.Comment); ok {
continue
}
// Skip whitespace-only char data
if cd, ok := tok.(xml.CharData); ok {
if strings.TrimSpace(string(cd)) == "" {
continue
}
}
encoder.EncodeToken(tok)
}
encoder.Flush()
return out.String(), nil
}
// minifyXML("<a>\n <b>1</b>\n</a>") → "<a><b>1</b></a>"# Minify XML with xmllint (part of libxml2) xmllint --noblanks input.xml > minified.xml # Minify from stdin echo '<root> <item>hello</item> </root>' | xmllint --noblanks - # → <?xml version="1.0"?><root><item>hello</item></root> # Strip comments too (combine with sed or xmlstarlet) xmlstarlet ed -d '//comment()' input.xml | xmllint --noblanks - # Check size reduction echo "Before: $(wc -c < input.xml) bytes" echo "After: $(xmllint --noblanks input.xml | wc -c) bytes"