XMLファイルを扱っているときに、こんなトラブルに遭遇したことはありませんか?
「なんでこのデータだけエラーが出るんだろう?」
「正常に保存したはずなのに、読み込んだら壊れている…」
「データベースからエクスポートしたXMLが開けない」
実は、これらの問題の多くは XMLで使えない文字(禁則文字) が原因です。
XMLは非常に厳密な規則を持つデータ形式のため、特定の文字を含むとエラーが発生したり、ファイルが正しく処理されなかったりします。
特に、外部システムからデータを取り込んだり、ユーザーが入力したテキストをXMLに変換したりする際に、この問題はよく発生します。
しかし、禁則文字のルールを理解し、適切な対処法を知っていれば、これらのトラブルは簡単に防ぐことができます。
この記事では、XMLの禁則文字を一覧でまとめ、それを回避する具体的な方法まで、初心者にもわかりやすく解説します。
XMLで禁止されている文字(禁則文字)とは?

XMLが文字に厳しい理由
XMLはデータを正確に表現し、システム間で確実にやり取りするために設計された言語です。
そのため、使用できる文字が仕様で厳格に制限されています。
この制限は、以下のような目的があります:
データの確実性を保つ:
- 文字化けを防ぐ
- システム間でのデータ破損を避ける
- パーサー(解析プログラム)の動作を安定させる
構造の明確性を保つ:
- タグとデータの区別を明確にする
- XMLの構造が壊れることを防ぐ
禁則文字の種類
XMLで問題となる文字は、大きく2つのカテゴリに分けられます:
- エスケープが必要な特殊文字:XMLの構造に関わる文字で、データとして使う場合は変換が必要
- 完全に禁止される制御文字:XML仕様上、使用が認められていない文字
それぞれについて、詳しく見ていきましょう。
XMLの代表的な禁則文字(エスケープ必須)
5つの特殊文字
以下の5つの文字は、XMLでは特別な意味を持つため、データとして使うときは**必ずエスケープ(実体参照)**が必要です。
禁則文字 | XMLでの意味 | エスケープ後 | 使用例 |
---|---|---|---|
< | タグの開始 | < | 「5 < 10」 |
> | タグの終了 | > | 「10 > 5」 |
& | エンティティ開始 | & | 「A & B」 |
" | 属性値の区切り | " | 「”こんにちは”」 |
' | 属性値の区切り | ' | 「’Hello’」 |
なぜエスケープが必要なのか
これらの文字は、XMLの構造を定義するために使われます。たとえば:
<メッセージ 種類="重要">こんにちは</メッセージ>
この例では:
<
と>
でタグを表現"
で属性値を囲む- データ部分は「こんにちは」
もしデータの中に <
が含まれていると、XMLパーサーは「新しいタグが始まった」と誤解してしまいます。
エスケープの具体例
数学的な表現
間違った書き方:
<数式>5 < 10 & 3 > 1</数式>
正しい書き方:
<数式>5 < 10 & 3 > 1</数式>
プログラムコード
間違った書き方:
<コード>if (x < 5 && y > 10) { return "OK"; }</コード>
正しい書き方:
<コード>if (x < 5 && y > 10) { return "OK"; }</コード>
HTML文字列
間違った書き方:
<HTML><p class="important">重要な情報</p></HTML>
正しい書き方:
<HTML><p class="important">重要な情報</p></HTML>
属性値での注意点
属性値を書くときは、使用する引用符に特に注意が必要です。
ダブルクォートで囲む場合:
<引用 内容="彼は"こんにちは"と言った">
シングルクォートで囲む場合:
<引用 内容='彼は'Hello'と言った'>
完全に禁止される制御文字

禁止される文字の範囲
以下の文字は、XML仕様上、絶対に使用できません:
文字コード | 文字の種類 | 説明 |
---|---|---|
0x00-0x08 | 制御文字 | NULL、BEL等 |
0x0B | 垂直タブ | VT |
0x0C | フォームフィード | FF |
0x0E-0x1F | 制御文字 | SO、SI等 |
0x7F | DEL文字 | 削除コード |
使用可能な制御文字(例外)
ただし、以下の文字は例外的に使用できます:
文字コード | 文字名 | 説明 |
---|---|---|
0x09 | タブ | TAB文字 |
0x0A | 改行 | LF(Line Feed) |
0x0D | 復帰 | CR(Carriage Return) |
制御文字が混入する典型的なケース
データベースからのエクスポート
古いシステムのデータベースには、NULL文字(0x00)や制御文字が含まれていることがあります:
-- データベースに不正な文字が含まれている例
SELECT name, description FROM products WHERE id = 1;
-- 結果: "商品A", "説明文\x00\x0B\x0C"
このデータをそのままXMLに変換すると、エラーが発生します。
外部ファイルからの読み込み
CSVファイルやテキストファイルから読み込んだデータにも、制御文字が含まれていることがあります:
商品名,説明
"ノートパソコン","高性能で軽量\x0B持ち運びに便利"
ユーザー入力データ
Webフォームやアプリケーションでのユーザー入力でも、コピー&ペーストによって制御文字が混入することがあります。
XMLで文字化け・エラーを防ぐための対処法
エスケープ処理の実装
手動でのエスケープ
最も基本的な方法は、文字列を置換することです:
元の文字列: A & B < C > D "Hello" 'World'
↓
処理後: A & B < C > D "Hello" 'World'
プログラムでのエスケープ例
Python:
import xml.sax.saxutils
def escape_xml(text):
return xml.sax.saxutils.escape(text, {'"': '"', "'": '''})
# 使用例
original = 'A & B < C > D "Hello"'
escaped = escape_xml(original)
print(escaped) # A & B < C > D "Hello"
Java:
import org.apache.commons.text.StringEscapeUtils;
public class XmlEscape {
public static String escapeXml(String text) {
return StringEscapeUtils.escapeXml11(text);
}
// 使用例
public static void main(String[] args) {
String original = "A & B < C > D \"Hello\"";
String escaped = escapeXml(original);
System.out.println(escaped);
}
}
制御文字の除去・置換
制御文字を完全に削除
import re
def remove_control_chars(text):
# 使用可能な制御文字(タブ、改行、復帰)以外を削除
return re.sub(r'[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]', '', text)
# 使用例
dirty_text = "商品名\x00\x0B説明文"
clean_text = remove_control_chars(dirty_text)
print(clean_text) # "商品名説明文"
制御文字を意味のある文字に置換
def replace_control_chars(text):
replacements = {
'\x00': '', # NULL文字は削除
'\x0B': ' ', # 垂直タブは空白に
'\x0C': '\n', # フォームフィードは改行に
}
for old_char, new_char in replacements.items():
text = text.replace(old_char, new_char)
return text
文字エンコーディングの統一
UTF-8での保存
XMLファイルは、必ずUTF-8で保存し、ファイルの先頭で宣言しましょう:
<?xml version="1.0" encoding="UTF-8"?>
<データ>
<項目>日本語テキスト</項目>
</データ>
BOM(Byte Order Mark)の注意
UTF-8ファイルでも、BOM付きで保存すると問題が起きることがあります。XMLファイルは BOMなしのUTF-8 で保存するのが安全です。
バリデーション(検証)の実装
XMLの正当性をチェック
データをXMLに変換した後は、必ず検証を行いましょう:
import xml.etree.ElementTree as ET
def validate_xml(xml_string):
try:
ET.fromstring(xml_string)
return True, "XMLは正常です"
except ET.ParseError as e:
return False, f"XMLエラー: {e}"
# 使用例
xml_data = "<test>サンプル & テスト</test>"
is_valid, message = validate_xml(xml_data)
print(f"結果: {is_valid}, メッセージ: {message}")
実際のトラブル事例と対処法

事例1:データベースエクスポートでのエラー
問題: 顧客管理システムからXMLエクスポートを実行すると、一部のレコードでエラーが発生。
原因: 顧客名に「田中 & 山田商事」という文字列があり、&
がエスケープされていなかった。
対処法:
<!-- 修正前(エラー) -->
<顧客名>田中 & 山田商事</顧客名>
<!-- 修正後(正常) -->
<顧客名>田中 & 山田商事</顧客名>
事例2:Webフォームからの入力データエラー
問題: Webサイトの問い合わせフォームから送信されたデータをXMLで保存しようとするとエラー。
原因: ユーザーが入力した文章に <script>
タグが含まれていた。
対処法:
<!-- 修正前(エラー) -->
<問い合わせ内容><script>alert('test')</script>よろしくお願いします</問い合わせ内容>
<!-- 修正後(正常) -->
<問い合わせ内容><script>alert('test')</script>よろしくお願いします</問い合わせ内容>
事例3:CSVインポートでの制御文字エラー
問題: ExcelからエクスポートしたCSVファイルをXMLに変換する際にエラー。
原因: Excelファイルに不可視の制御文字(0x0B)が含まれていた。
対処法:
- CSVファイルをテキストエディタで開いて制御文字を確認
- プログラムで制御文字を除去してからXML変換
# CSVデータクリーニングの例
import csv
import re
def clean_csv_data(filename):
cleaned_rows = []
with open(filename, 'r', encoding='utf-8') as file:
reader = csv.reader(file)
for row in reader:
cleaned_row = []
for cell in row:
# 制御文字を除去
clean_cell = re.sub(r'[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]', '', cell)
cleaned_row.append(clean_cell)
cleaned_rows.append(cleaned_row)
return cleaned_rows
開発ツールとライブラリの活用
テキストエディタでの対策
Visual Studio Code
制御文字を可視化する拡張機能:
- “Control Characters” 拡張機能
- “Whitespace” 表示機能
設定例:
{
"editor.renderControlCharacters": true,
"editor.renderWhitespace": "all"
}
Notepad++
制御文字表示設定:
- 「表示」メニュー
- 「すべての文字を表示」を選択
- 制御文字が記号で表示される
XMLライブラリの活用
Python xml.etree.ElementTree
import xml.etree.ElementTree as ET
def create_safe_xml_element(tag, text):
element = ET.Element(tag)
# 自動的にエスケープされる
element.text = text
return element
# 使用例
root = ET.Element("データ")
item = create_safe_xml_element("項目", "A & B < C")
root.append(item)
# XML文字列として出力
xml_string = ET.tostring(root, encoding='unicode')
print(xml_string) # <データ><項目>A & B < C</項目></データ>
JavaScript DOMParser
function createSafeXMLElement(tagName, textContent) {
const parser = new DOMParser();
const doc = parser.parseFromString('<root></root>', 'text/xml');
const element = doc.createElement(tagName);
// 自動的にエスケープされる
element.textContent = textContent;
return element;
}
// 使用例
const element = createSafeXMLElement('項目', 'A & B < C');
console.log(element.outerHTML); // <項目>A & B < C</項目>
XMLファイルの検証とデバッグ

オンライン検証ツール
XMLバリデーター:
- W3C Markup Validator
- XML Validator (freeformatter.com)
- XML Lint (xmllint.com)
これらのツールに問題のあるXMLファイルをアップロードすると、エラーの箇所と原因を教えてくれます。
コマンドラインツール
xmllint(Linux/Mac)
# XMLファイルの検証
xmllint --noout sample.xml
# エラーがある場合の出力例
sample.xml:3: parser error : xmlParseCharRef: invalid xmlChar value 11
<text>商品説明文</text>
^
PowerShell(Windows)
# XMLファイルの読み込みテスト
try {
$xml = [xml](Get-Content "sample.xml")
Write-Host "XMLは正常です"
} catch {
Write-Host "XMLエラー: $($_.Exception.Message)"
}
デバッグのコツ
エラーメッセージを読み解く
よくあるエラーメッセージ:
- “not well-formed (invalid token)”
- 原因:エスケープされていない特殊文字
- 対処:
<
,>
,&
をエスケープ
- “invalid xmlChar value”
- 原因:制御文字が含まれている
- 対処:制御文字を除去
- “character content of element”
- 原因:CDATA以外の場所に不正な文字
- 対処:CDATA セクションの使用を検討
CDATA セクションの活用
特殊文字や制御文字を多く含むデータは、CDATA セクションを使うと便利です:
<プログラムコード>
<![CDATA[
if (x < 5 && y > 10) {
console.log("OK & Running");
return true;
}
]]>
</プログラムコード>
CDATA セクション内では、<
や &
をエスケープする必要がありません。
まとめ
今回は「XMLの禁則文字(使えない文字)」について、一覧と対処法を詳しく解説しました。
重要なポイント:
- 5つの特殊文字(
<
,>
,&
,"
,'
)は必ずエスケープが必要 - 制御文字(NULL、BEL等)はXMLでは完全に禁止
- UTF-8統一と制御文字除去でトラブルを防げる
- 事前検証と適切なライブラリ使用が重要
実践的な対策:
- データ処理時は必ずエスケープ処理を実装
- 外部データ取り込み時は制御文字をチェック
- XMLライブラリの自動エスケープ機能を活用
- 定期的なバリデーションでエラーを早期発見
コメント