XMLファイルを扱っているとき、「入力した半角スペースが消えてしまう」「連続したスペースが1つにまとまってしまう」といった経験はありませんか?
これは実は、XMLの仕様による正常な動作なんです。でも、意図したスペースまで消えてしまうと困りますよね。特にプログラムでXMLを読み書きしたり、データを整形したりする場合、この問題は大きな障害になることがあります。
この記事では、XMLで半角スペースが消える理由から、具体的な対処法まで、初心者の方にもわかりやすく解説していきます。この問題を理解して、確実にスペースを保持する方法を身につけましょう。
XMLで半角スペースが消える現象とは

よくある症状
XMLを扱う際に、以下のような問題が発生します:
パターン1:連続スペースが1つになる
<!-- 入力 -->
<text>これは テストです</text>
<!-- 結果 -->
これは テストです
4つのスペースが1つになってしまいます。
パターン2:前後のスペースが削除される
<!-- 入力 -->
<text> 前後にスペース </text>
<!-- 結果 -->
前後にスペース
前後のスペースが消えてしまうんです。
パターン3:改行とインデントのスペースが消える
<!-- 入力 -->
<message>
こんにちは
世界
</message>
<!-- 結果 -->
こんにちは 世界
改行とインデント用のスペースがすべて無視されます。
なぜ問題になるのか
影響を受ける場面:
- テキストデータの整形情報が失われる
- プログラムコードのインデントが崩れる
- 詩や台本など、レイアウトが重要なコンテンツが壊れる
- 住所や氏名などのデータで意図しない変換が起こる
- データベースとの連携で不整合が発生
こういった問題を防ぐには、XMLの空白処理の仕組みを理解する必要があります。
半角スペースが消える原因
XMLの空白正規化(White Space Normalization)
XMLには「空白正規化」という仕様があります。これは、XMLパーサー(XMLを読み取るプログラム)が空白文字を自動的に処理する仕組みのこと。
空白文字とは:
- 半角スペース(U+0020)
- タブ文字(U+0009)
- 改行(LF:U+000A)
- キャリッジリターン(CR:U+000D)
これらの文字は、XMLの読み取り時に特別な扱いを受けるんです。
空白処理の3つのルール
XMLでは、要素の種類によって空白の扱い方が変わります。
ルール1:要素間の空白は無視される
<root>
<child>内容</child>
</root>
タグとタグの間にあるインデント用の空白は、通常無視されます。
ルール2:要素内容の前後の空白は削除される
<text> 内容 </text>
要素の内容の前後にある空白は、自動的に削除されることがあります。
ルール3:連続する空白は1つにまとめられる
<text>連続 する スペース</text>
連続したスペースは、1つのスペースに正規化されるんですね。
パーサーによる違い
XMLを読み取るプログラム(パーサー)によって、空白の扱い方が少し異なる場合があります。
DOM(Document Object Model)パーサー:
多くの場合、空白を正規化する
SAX(Simple API for XML)パーサー:
空白をそのまま渡すこともある
アプリケーション側での処理:
パーサーが渡した空白を、アプリケーションがさらに処理することもある
結果として、意図したスペースが消えてしまうわけです。
解決方法1:xml:space属性を使う
xml:space=”preserve”の基本
最も標準的な解決方法は、xml:space属性を使うことです。
基本的な使い方:
<text xml:space="preserve">これは テストです</text>
xml:space="preserve"を指定すると、その要素内のすべての空白が保持されます。
適用範囲
親要素に指定した場合:
<root xml:space="preserve">
<child> 前後にスペース </child>
<child>連続 する スペース</child>
</root>
親要素に指定すると、子要素すべてに効果が及びます。ただし、子要素で明示的にxml:space="default"を指定すれば、その部分だけ標準動作に戻せますよ。
具体的な使用例
例1:詩やテキストアートの保存
<poem xml:space="preserve">
桜咲く
春の日に
君を想う
</poem>
インデントや改行がそのまま保持されます。
例2:プログラムコードの保存
<code xml:space="preserve">
function hello() {
console.log("Hello, World!");
}
</code>
コードのインデントが崩れずに保存できるんです。
例3:整形済みテキスト
<pre xml:space="preserve">
名前 年齢 職業
田中太郎 30 エンジニア
鈴木花子 28 デザイナー
</pre>
表形式の整形が保持されます。
解決方法2:CDATAセクションを使う

CDATAとは
CDATA(Character Data)セクションは、XMLのマークアップとして解釈されない生のテキストデータを記述するための仕組みです。
構文:
<text><![CDATA[これは テスト です]]></text>
<![CDATA[ と ]]> で囲まれた部分は、すべて文字データとして扱われます。
CDATAのメリット
特徴:
- すべての空白が保持される
<や>などの特殊文字をエスケープ不要- HTMLコードなども安全に格納できる
使用例:
<script><![CDATA[
function test() {
if (a < b && c > d) {
console.log("テスト 実行");
}
}
]]></script>
JavaScriptコードの<や>をエスケープせずに書けますし、スペースも保持されます。
CDATAの注意点
制限事項:
]]>という文字列はCDATA内に書けない- 入れ子にはできない
- XMLとして解析されないので、タグは使えない
例(不可能):
<text><![CDATA[これは]]>終了記号を含む]]></text>
]]>がCDATAセクションの終了と認識されてエラーになります。
解決方法3:文字実体参照を使う
ノーブレークスペースを使う
半角スペースの代わりに、「ノーブレークスペース」という特殊な空白文字を使う方法もあります。
記述方法:
<text>これは    テストです</text>
 は、改行されない空白(ノーブレークスペース)を表す文字実体参照です。
または:
<text>これは テストです</text>
HTMLでおなじみの も使えます(ただし、XMLで使う場合は事前に定義が必要)。
他の空白文字実体参照
よく使われる空白文字:
 – 通常の半角スペース(U+0020) – ノーブレークスペース(U+00A0) – enスペース(U+2002) – emスペース(U+2003)	– タブ文字(U+0009)
使用例:
<text>値1	値2	値3</text>
タブで区切られたデータを明示的に表現できます。
この方法の利点と欠点
利点:
- xml:space属性なしでスペースを保持できる
- 細かい制御が可能
欠点:
- 可読性が低い
- 編集が面倒
- データ量が増える
解決方法4:プログラムでの処理
XMLを読み込む際の設定
プログラミング言語でXMLを扱う場合、パーサーの設定で空白処理を制御できます。
Python(xml.etree.ElementTree):
import xml.etree.ElementTree as ET
# XMLを解析
tree = ET.parse('file.xml')
root = tree.getroot()
# テキストを取得(空白は正規化される可能性がある)
text = root.find('text').text
# xml:space属性を確認
if root.find('text').get('{http://www.w3.org/XML/1998/namespace}space') == 'preserve':
# 空白を保持する処理
pass
Java(DOM Parser):
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringElementContentWhitespace(false); // 空白を無視しない
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse("file.xml");
setIgnoringElementContentWhitespace(false)で、要素間の空白を保持できます。
XMLを書き出す際の設定
Python:
import xml.etree.ElementTree as ET
root = ET.Element('root')
text_elem = ET.SubElement(root, 'text')
text_elem.set('{http://www.w3.org/XML/1998/namespace}space', 'preserve')
text_elem.text = 'これは テスト です'
tree = ET.ElementTree(root)
tree.write('output.xml', encoding='utf-8', xml_declaration=True)
プログラムでxml:space属性を追加して書き出すこともできますよ。
C#(.NET)での処理
XMLの読み込み:
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true; // 空白を保持
doc.Load("file.xml");
XMLの書き出し:
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = " ";
using (XmlWriter writer = XmlWriter.Create("output.xml", settings))
{
writer.WriteStartElement("text");
writer.WriteAttributeString("xml", "space", null, "preserve");
writer.WriteString("これは テスト です");
writer.WriteEndElement();
}
実践的なケーススタディ

ケース1:住所データの保存
住所には全角・半角スペースが混在することがあります。
問題のある例:
<address>東京都 渋谷区 神南 1-1-1</address>
複数のスペースが1つにまとめられてしまいます。
解決策:
<address xml:space="preserve">東京都 渋谷区 神南 1-1-1</address>
または:
<address><![CDATA[東京都 渋谷区 神南 1-1-1]]></address>
ケース2:HTMLコードの保存
HTMLコードをXML内に保存する場合、CDATAが便利です。
解決策:
<html-snippet><![CDATA[
<div class="container">
<p>これは サンプル です</p>
</div>
]]></html-snippet>
HTMLのタグも、スペースも、すべてそのまま保存できるんです。
ケース3:設定ファイルでの値の保持
設定ファイルで、意図的に前後にスペースを含む値を保存したい場合があります。
解決策:
<config>
<padding xml:space="preserve"> 10px </padding>
<margin xml:space="preserve"> 5px </margin>
</config>
ケース4:データベースのデータ移行
データベースから出力したデータをXMLで保存する場合、元のスペースを保持する必要があります。
解決策:
<records>
<record>
<name xml:space="preserve">田中 太郎</name>
<description xml:space="preserve">
これは
複数行の
説明文です
</description>
</record>
</records>
XMLスキーマでの空白制御
XSD(XML Schema)での定義
XMLスキーマを使う場合、要素の空白処理方法を定義できます。
スキーマ定義例:
<xs:element name="text">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:whiteSpace value="preserve"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
whiteSpace属性の値:
- preserve – すべての空白を保持
- replace – タブ、改行、キャリッジリターンをスペースに置き換え
- collapse – replaceに加えて、連続スペースを1つにまとめ、前後のスペースを削除
スキーマを活用した統一的な処理
組織やプロジェクトでXMLを扱う場合、スキーマで空白処理のルールを統一しておくと、混乱を防げます。
例:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="code">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="space" fixed="preserve"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:schema>
トラブルシューティング
xml:space属性が効かない場合
確認ポイント:
- 属性名のスペルは正しいか(
xml:space) - 値は
preserveになっているか - 使用しているパーサーが対応しているか
- アプリケーション側で空白を削除していないか
デバッグ方法:
XMLファイルを直接開いて、ソースコードを確認しましょう。それでも問題がある場合は、パーサーやアプリケーションの設定を見直す必要があります。
CDATAセクションが表示される
CDATAセクションのマーカー(<![CDATA[と]]>)がそのまま表示される場合、XMLとして正しく解析されていません。
原因:
- ファイルの拡張子が
.xmlでない - Content-Typeが正しくない
- テキストエディタで開いている
正しいXMLパーサーを使って読み込みましょう。
プログラムで読み込むと消える
パーサーやアプリケーションの設定を確認してください。
チェック項目:
- パーサーの空白処理設定
- trim()などの文字列処理関数を使っていないか
- テンプレートエンジンが空白を削除していないか
意図しない場所で空白が削除されている可能性があります。
ベストプラクティス
用途に応じた方法の選択
シンプルなテキスト:xml:space="preserve"を使用
コードやHTMLを含む:
CDATAセクションを使用
プログラムでの自動生成:
パーサーの設定で制御
厳密なデータ管理:
XMLスキーマで定義
目的に応じて、最適な方法を選びましょう。
一貫性のある命名規則
XML要素名で、空白を保持する要素であることを示すのも良い方法です。
例:
<formatted-text xml:space="preserve">...</formatted-text>
<plain-text>...</plain-text>
<code xml:space="preserve">...</code>
要素名から、空白の扱い方が推測できるようにするんですね。
ドキュメント化
XMLファイルやスキーマに、空白処理の方針をコメントで記載しておくと、後から見た人にもわかりやすくなります。
例:
<!-- この要素ではxml:space="preserve"を使用して空白を保持しています -->
<description xml:space="preserve">
詳細な説明文...
</description>
まとめ
XMLで半角スペースが消える問題は、XMLの仕様による空白正規化が原因です。
この記事のポイント:
- XMLは空白を自動的に正規化する仕様がある
- 連続スペースは1つにまとめられ、前後のスペースは削除される
- xml:space=”preserve”属性で空白を保持できる
- CDATAセクションでも空白をそのまま保存可能
- 文字実体参照(
 など)を使う方法もある - プログラムではパーサーの設定で制御できる
- XMLスキーマで空白処理のルールを定義できる
- 用途に応じて最適な方法を選ぶことが重要
この問題を理解していないと、データの不整合やレイアウト崩れなど、予期しないトラブルに遭遇することがあります。でも、適切な対処法を知っていれば、確実にスペースを保持して、意図した通りのXMLを作成できるんです。
XMLを扱う際は、空白処理の仕様を意識して、必要に応じてxml:space属性やCDATAセクションを活用しましょう。そうすることで、データの整合性を保ちながら、安全にXMLを扱えるようになりますよ。


コメント