XML バリデーター

整形式チェックとスキーマ検証。アップロードは一切ありません。

入力
待機中文書を貼り付けると検査します。入力中にそのまま検証されます。

すべてこのタブ内で実行されます。貼り付けた内容がアップロード・記録・送信されることはありません。 ネットワークパネルを開いて確認する.

上のエディターに文書を貼り付けると、入力しながら検査されます。問題は行・列・代わりに書くべき内容つきで報告され、最初の 1 件で止まらず、すべてが一度に出ます。アップロードは一切ありません。パーサーもスキーマエンジンもエディターも、このタブの中で動いています。ブラウザーのネットワークパネルを開いたまま作業すれば、何も流れないことをその場で確認できます。

最後の点は宣伝文句ではありません。この検索で上位に出るツールのいくつかは、検査のためにあなたの文書をサーバーへ送っています。そのうちの 1 つは、データがサーバーに保存され保持される場合があることを理解したというチェックボックスを求めます。ベアラートークンを含む SOAP エンベロープや、接続文字列の入った設定ファイルをデバッグしているなら、それは現実の問題であり、このサイトが存在する理由でもあります。

このバリデーターは XML が定める 2 種類の検査を両方おこない、しかも区別して扱います。両者は別の問いに答えるものなのに、無料ツールのほとんどが混同しているからです。

「整形式」と「妥当」は別の検査

文書が整形式であるとは、構文が正しいということです。タグが閉じられ正しく入れ子になっている、ルート要素がちょうど 1 つある、特殊文字がエスケープされている、属性値が引用符で囲まれている。これは文書そのもの以外に何も要らないので、入力しながら自動で実行されます。

文書が妥当であるとは、整形式であり、かつスキーマに適合しているということです。あるべき要素が、正しい順序で、正しい型で存在している。これには XSD や DTD という 2 つめのファイルが必要なので、自分の意思で実行する別の操作になっています。

この区別が重要なのは、「妥当な XML」という言葉がどちらの意味でも使われるからです。あるシステムがあなたの文書を「invalid だ」と言って拒否したなら、まず間違いなくスキーマ検査を実行しています。整形式チェッカーの緑のチェックマークは、その失敗の理由を教えてくれません。ここの結果パネルは、どちらの検査を実行したかを必ず明記します。

  • 整形式だが妥当ではない例:<from> も必須とするスキーマに対する <note><to>Alice</to></note>。構文は完璧で、内容が違います。
  • 妥当だが整形式ではない例:ありえません。妥当性は整形式であることを含みます。だからスキーマ検査は、構文がきれいになるまで実行を拒みます。

エラーが実際に何を教えてくれるか

この分野で足りていないのは機能ではなく、エラーメッセージです。ブラウザーのパーサーは最初の問題で止まり、しかもパーサーを書いた人向けの言葉で説明します。エスケープされていないアンパサンドを、Firefox は「EntityRef: expecting ';'」と報告します。libxml2 は同じものを「xmlParseEntityRef: no name」と呼びます。どちらもアンパサンドにもエスケープにも、ほぼ確実に原因である URL のクエリ文字列にも触れません。

ここでの各診断は、あなたが使うであろう言葉で失敗を名指しし、正確な位置を示し、直し方を提案します。行:列 のマーカーを押せばカーソルがそこへ飛びます。よくあるエラーには、原因を解説するページへのリンクが付き、他の 6 つのパーサーが出す同等のメッセージも載せてあります。次にビルドがそちらの文言で報告してきたときに、同じ問題だと気づけるようにです。

大きな文書と、悪意のある文書

解析は Web Worker で実行されるので、大きな文書を走査している間も画面は反応し続けます。100 KB のファイルは約 20 ミリ秒、1 MB は約 110 ミリ秒、10 MB は 1 秒強で検査できます。20 MB を超えると、このツールは処理を断ります。すべてがこのタブのメモリー上にあり、それ以上の文書はブラウザーを「遅く」ではなく「操作不能に」してしまうからです。

XML には JSON にはないサービス拒否の形があり、ここではそれを想定ではなく制限として実装しています。指数的に展開される入れ子の実体を宣言した文書、いわゆる「billion laughs」は、約 2 ミリ秒で拒否されます。展開コストを宣言から先に計算し、1 文字も展開しないうちに判断するからです。大きな実体を数千回参照する二次的な変種も、同じ予算で捕まえます。入れ子の深さには上限があり、実体の循環はたどらずに検出し、外部実体は報告はしても決して取得しません。

実際に貼り付けられている文書

バリデータは汎用のツールですが、そこに届く文書の種類は均等ではありません。ごく少数の型がトラフィックの大半を占めていて、それぞれに固有の壊れ方があります。

こうした場合のほとんどで、検証と整形は同じ作業です。ファイルが読めないのは、ミニファイされた状態で届いたか、三つの別々のツールで順に字下げされたからで、整えて並べるまで誤りは見えません。上の「整形」ボタンはその場で整形し、別のサイトを経由しません。XML フォーマッタはその完全版で、字下げ幅やコメントの扱いを指定できます。

  • XML サイトマップ。サイトマップバリデータは構文だけでなく sitemaps.org のプロトコルそのものを検査します。50,000 URL と 50 MB の上限、lastmod が実際に要求する W3C Datetime 形式、そしてすべての URL がサイトマップと同じホスト上になければならないという規則です。Google 向けのサイトマップは整形式であっても拒否されることがあり、たいていはこの三つのどれかです。
  • SEPA をはじめとする ISO 20022 の支払いメッセージ。pain.008 の口座振替指図や camt.053 の取引明細は、公開されている XSD と突き合わせて初めて意味を持つので、スキーマを隣に貼り付けたうえで XSD バリデータへ渡してください。何もアップロードしないという保証が抽象論でなくなるのがこの分野です。テスト用のファイルでも、実在の IBAN や債権者識別子を含んでいます。
  • ゲームサーバーの設定。DayZ や Arma、および同じエンジン上のサーバーは起動時に types.xml、cfgspawnabletypes.xml、events.xml を読み込みますが、閉じられていない <type> 要素がひとつあるだけでサーバーは停止し、そのメッセージはファイル名も行番号も示しません。ここに貼り付ければ両方が分かり、壊れた位置の入れ子の深さも分かります。
  • SOAP エンベロープと、そこから返ってくる応答。ベアラトークンや接続文字列を含んでいる可能性が最も高い文書で、SOAP フォーマッタが独立したページとして存在する理由もそこにあります。
  • RSS と Atom のフィード。よくある失敗はタイトル内の URL に生のアンパサンドが入っていることで、フィードリーダーは「フィードが壊れている」としか言いません。

Notepad++ で検証してきた方へ

Notepad++ 自体に XML 対応はありません。XML Tools プラグインがそれを足しており、このプラグインは libxml2 へのバインディングです。つまりこのサイトが WebAssembly にコンパイルしているのと同じエンジンなので、検査の中身自体は一致します。違うのはその周りにあるものすべてです。

プラグインは文書上ではなくダイアログで失敗を知らせるため、行番号を読んでから自分で探しに行くことになります。Notepad++ が Windows 専用なのでプラグインもそうで、ビルドはエディタのアーキテクチャと一致している必要があります。入れたばかりなのにメニューが灰色のまま、というよくある原因はこれです。スキーマ検証はありますが、XSD が文書自身の宣言からたどれることを前提としており、大きなファイルから切り出した断片にはまずその宣言がありません。

どちらか一方が他方を置き換えるわけではなく、正直な線引きは「その文書が今どこにあるか」です。ディスク上のファイルで、すでにエディタを開いていて、ネットワークがないなら、プラグインのほうが近道です。サポートチケットやクリップボード、ブラウザのタブから来たのであれば、あるいはダイアログ一つにつき一件ではなく一度にすべての誤りを見たいのであれば、Windows 以外を使っているのであれば、ページを開くほうがプラグインを入れるより速く済みます。スキーマの場合も同じで、ここの二つ目のペインに XSD を貼るのに文書内の宣言は一切要りません。

コードで同じことをする

XML を最もよく扱う言語での同じ検査です。いずれも安全な書き方にしてあります。これらのライブラリのいくつかは既定で外部実体を平然と解決してしまい、それが XXE 脆弱性です。以下のフラグは定型文ではなく、まさに要点です。

// DOMParser does not throw on malformed input. It returns a document
// containing a <parsererror> element instead, which is why so much code
// silently accepts broken XML.
function parseXml(source) {
  const doc = new DOMParser().parseFromString(source, 'application/xml');
  const error = doc.querySelector('parsererror');
  if (error) {
    throw new Error(error.textContent.trim());
  }
  return doc;
}

// Browsers do not resolve external entities, so XXE is not reachable here.
// Internal entity expansion is, so cap the input size before parsing.
# The standard library is not safe against entity-expansion attacks.
# defusedxml is the maintained answer and is a drop-in replacement.
from defusedxml.ElementTree import fromstring, ParseError

try:
    root = fromstring(source)
except ParseError as e:
    # e.position is a (line, column) tuple, 1-based line, 0-based column
    line, column = e.position
    raise SystemExit(f"XML error at line {line}, column {column + 1}: {e}")

# With lxml, disable resolution explicitly:
#   parser = etree.XMLParser(resolve_entities=False, no_network=True,
#                            huge_tree=False, load_dtd=False)
#   root = etree.fromstring(source.encode(), parser)
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

// FEATURE_SECURE_PROCESSING caps entity expansion. The three
// disallow-doctype settings close XXE. None of this is the default.
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setXIncludeAware(false);
factory.setExpandEntityReferences(false);

var builder = factory.newDocumentBuilder();
try {
    var document = builder.parse(new java.io.ByteArrayInputStream(bytes));
} catch (org.xml.sax.SAXParseException e) {
    System.err.printf("XML error at line %d, column %d: %s%n",
        e.getLineNumber(), e.getColumnNumber(), e.getMessage());
}
using System.Xml;

var settings = new XmlReaderSettings
{
    // Null resolver means external DTDs and entities are never fetched.
    DtdProcessing = DtdProcessing.Prohibit,
    XmlResolver = null,
    MaxCharactersFromEntities = 1024 * 1024,
    MaxCharactersInDocument = 20L * 1024 * 1024,
};

try
{
    using var reader = XmlReader.Create(new StringReader(source), settings);
    var document = new XmlDocument { XmlResolver = null };
    document.Load(reader);
}
catch (XmlException e)
{
    Console.Error.WriteLine(
        $"XML error at line {e.LineNumber}, column {e.LinePosition}: {e.Message}");
}
<?php
// libxml_disable_entity_loader was deprecated in PHP 8.0 because external
// entity loading became off by default. On PHP 7 you still need it.
libxml_use_internal_errors(true);

$doc = new DOMDocument();
$loaded = $doc->loadXML($source, LIBXML_NONET | LIBXML_NOENT & ~LIBXML_NOENT);

if (!$loaded) {
    foreach (libxml_get_errors() as $error) {
        fprintf(
            STDERR,
            "XML error at line %d, column %d: %s\n",
            $error->line,
            $error->column,
            trim($error->message)
        );
    }
    libxml_clear_errors();
    exit(1);
}
# xmllint is part of libxml2 and is almost certainly already installed.
# --nonet stops it fetching a DTD referenced by the document.
xmllint --noout --nonet document.xml

# Validate against a schema:
xmllint --noout --nonet --schema schema.xsd document.xml
xmllint --noout --nonet --valid document.xml        # against its own DTD

# Exit status is 0 when valid. Note that xmllint's exit code does not
# always reflect namespace errors, so check the output too.

どの例も何かを「オフ」にしています。これは偶然ではありません。危険なほうの挙動が既定なのは Java、PHP 8.0 より前、そして Python の標準ライブラリであり、実運用の XML 解析の多くはその既定値のまま動いています。

よくある質問

貼り付けた XML はどこかにアップロードされますか。

いいえ。パーサーもフォーマッターもスキーマエンジンも、このタブで動く JavaScript と WebAssembly です。そもそも送信先となるサーバー側の仕組みがありません。

信用していただく必要はありません。ブラウザーの開発者ツールを開き、ネットワークタブに切り替えて、文書を貼り付けて検証してみてください。ページ自身のアセットが一度読み込まれ、そのあとは何も起きないのが見えます。このサイトにはエディターへアクセスできる解析ツールも、サードパーティのスクリプトも、エラー報告サービスもありません。

整形式と妥当の違いは何ですか。

整形式とは構文が正しいことです。タグが閉じている、正しく入れ子になっている、ルート要素が 1 つ、特殊文字がエスケープされている、属性値が引用符で囲まれている。妥当とは、整形式であり、かつスキーマ(どの要素がどこに許されるかを記した別ファイル)に適合していることです。

文書は妥当でなくても整形式でありえます。整形式でないのに妥当ということはありえません。システムが「XML が invalid だ」と言うとき、たいていはスキーマ検査を実行しています。ですから構文チェッカーだけでは、その失敗の理由は分かりません。

XSD に対する検証もできますか。

できます。しかもサーバーなしでできるのは珍しいことです。ブラウザーにはスキーマバリデーターが組み込まれていないため、無料ツールはスキーマ検証を省くか、ファイルをアップロードするかのどちらかです。このサイトは WebAssembly にコンパイルした libxml2 を実行し、XSD 1.0 と DTD の検証をすべてブラウザー内でおこないます。

エンジンは圧縮後で約 480 KB あるため、ページ読み込み時ではなく、実際にスキーマ検査を求めたときにだけ取得されます。なお libxml2 が実装しているのは XSD 1.0 だけです。xs:assert のような XSD 1.1 の機能を使うスキーマはコンパイルできず、そのときは分かりにくい構造エラーではなく、その旨をはっきり伝えます。

他のバリデーターは 1 件しか出さないのに、ここが複数のエラーを出すのはなぜですか。

1 件のエラーが全体像であることはまれですし、最初の問題で止まるパーサーは、大きな文書を 1 往復ずつ直させることになるからです。

このスキャナーは失敗のあとも復帰して続行するので、1 回のパスで 4 行目の引用符のない属性、12 行目の生のアンパサンド、末尾の閉じられていないタグをまとめて見つけます。ただし注意も必要です。閉じ忘れのような早い段階のミスは、それ以降のすべてを誤りに見せてしまうことがあります。リストを下から潰すのではなく、最初の数件を直して再検査してください。

どのくらいの大きさのファイルまで扱えますか。

20 MB までです。10 MB の文書は 1 秒強で走査でき、解析は Web Worker で動くのでページが固まることはありません。

この上限はクラッシュして分かったものではなく、意図して決めたものです。すべてがこのタブのメモリーに載り、おおむね 20 MB を超えると解析木が数百 MB を消費しかねません。本当に大きなファイルには、手元のマシンでストリーミング解析をするのが正解です。xmllint、Python の iterparse、SAX パーサーなど、どれも木全体を作りません。

名前空間は正しく扱われますか。

はい。プレフィックスはスコープ内の宣言に照らして解決され、束縛されていないプレフィックスの使用はエラーとして報告し、追加すべき宣言も示します。これは大きな文書から断片をコピーしたときに起きやすい失敗で、xmlns 宣言が元のルート要素に置き去りになっているのが原因です。

エディターはさらに、プレフィックスをローカル名より淡く表示します。おかげで soap:Body は「足場つきの Body」として読めます。小さな工夫ですが、深く入れ子になった SOAP エンベロープは目で追いやすくなります。

認証情報を含む文書を貼り付けても安全ですか。

アップロードするツールよりは安全です。何も送信されないからです。文書はタブの外に出ず、記録もされず、どんなエラー報告にも含まれません。

ひとつだけ明記しておきます。入力内容は、再読み込みで作業が消えないようにこのブラウザーの localStorage に保存されます。これはお使いのマシン内に閉じており送信はされませんが、消すまで文書が残るということでもあります。クリアボタンで即座に削除でき、300 KB を超える文書はそもそも保存されません。

XML サイトマップの検証にも使えますか?

使えますが、サイトマップであれば専用のサイトマップバリデータのほうが適しています。このページが見るのは文書が整形式の XML かどうかで、それは必要条件ではあっても十分条件ではありません。Google に拒否されるサイトマップはたいてい整形式で、代わりにプロトコルの規則に違反しています。

専用ページは規則そのものを検査します。50,000 URL と非圧縮 50 MB の上限、sitemaps.org の名前空間、フレームワークが出力したままの値ではなく W3C Datetime 形式の lastmod、そしてすべての URL がサイトマップファイルと同じホスト上にあるという要件です。Google が無視すると公表している要素も指摘するので、効果のない値を調整し続けずに済みます。

SEPA や pain.008、camt.053 などの ISO 20022 ファイルに対応していますか?

対応しています。ISO 20022 のメッセージは大きなスキーマを背後に持つ普通の XML なので、メッセージを XSD バリデータに、対応する pain.008 や camt.053 のスキーマを二つ目のペインに貼り付けてください。検証はそのスキーマに対してブラウザ内で走り、アカウント登録は不要、全体の 20 MB 制限以外の上限もありません。

文書がどこへ行くかが最も重要になるのがこの場面です。テスト用の支払いファイルであっても、実在の IBAN、債権者識別子、マンデート参照番号を含んでいます。ISO 20022 ファイルを受け付ける無料バリデータのいくつかは、まずサーバーへ送信します。ここでは何も送信されず、作業しながらネットワークタブで確認できます。知っておくべき制限がひとつ。エンジンが実装しているのは XSD 1.0 で、公開されている ISO 20022 のスキーマはその版で書かれています。

DayZ の types.xml のようなサーバーファイルにも使えますか?

使えますし、相性は良いほうです。DayZ の経済ファイル、types.xml、cfgspawnabletypes.xml、events.xml、cfgeventspawns.xml はいずれも普通の XML で、どれかひとつが壊れているとサーバーは起動を拒みます。そのとき出るメッセージはたいていファイル名も位置も示さず、そのせいで山括弧ひとつの脱落が一晩仕事になります。

ここに貼り付ければ、すべての構文エラーが行と列つきで一度に報告されるので、何度かに分けて手で編集したファイルも、再起動を繰り返さずに一回で直せます。断っておくべき点が二つあります。これらのファイルに公開された XSD はないため、ここで確かめられるのは XML が整形式かどうかであって、属性値がゲームの受け付ける値かどうかではありません。また nominal や lifetime の値が XML としては正しくてもルート経済の設定として誤っている場合、ここは通過したうえでゲーム内では正しく動きません。

Notepad++ の XML バリデータと比べてどうですか?

エンジンは同じです。Notepad++ 単体に XML 対応はなく、XML Tools プラグインがそれを提供していて、その土台は libxml2、つまりこのサイトが WebAssembly として実行しているものです。文書が整形式かどうかについて、両者の判断は一致します。

違いは実務的なところにあります。プラグインは Windows 専用で、ビルドはエディタのアーキテクチャと一致していなければならず、入れたばかりでメニューが灰色になるのはたいていこれが理由です。エラーは文書上ではなくダイアログに出ますし、スキーマ検証は XSD がファイル内で宣言されていることを期待しますが、コピーしてきた断片にその宣言はまずありません。このページは宣言なしで二つ目のペインに貼った XSD を受け取り、すべての構文エラーを一度に報告し、ブラウザさえあればどこでも動きます。ファイルがすでに Notepad++ で開いていてオフラインなら、プラグインを使ってください。そこはプラグインの勝ちです。

この XML バリデータは無料ですか。登録は必要ですか?

無料です。アカウントもメールアドレスの入力も、一日あたりの回数制限も、スキーマ検証を出し惜しみする有料プランもありません。このサイトに制限のかかった機能はひとつもありません。

これは聞こえるほど難しい約束ではなく、単に費用の構造が違うだけです。サーバー上で動くバリデータは、あなたが検査する文書ごとに CPU の代金を払っています。だからそうしたツールは利用回数を数え、ファイルサイズに上限を設け、登録を求めます。ここでは解析があなたの端末で行われるので、10 MB のファイルでもサイト側の費用はゼロで、何件検証したかを数える理由がありません。

何もインストールせずにオンラインで XML を検証できますか?

このページがまさにそれです。Windows、macOS、Linux、Android、iOS のいずれでも、最近のブラウザであれば動きます。インストールも拡張機能もアカウントも要りません。

ひとつ区別しておく価値があります。「オンライン」という語がここでは二つの役割を担っているからです。多くのオンラインバリデータは両方の意味でオンラインです。ページがウェブ上にあり、かつあなたの文書が検査のために相手のサーバーへ送られます。これは前者の意味でだけオンラインです。ページは一度ネットワーク越しに配信され、それ以降はパーサもスキーマエンジンもエディタもタブの中でローカルに動きます。一度読み込めば、ネットワークを切っても動き続けます。

これは XML のバリデータ兼フォーマッタですか。それとも二つのツールが必要ですか?

両方あります。上の操作列にある「整形」ボタンは、エディタの内容をその場で整形し直します。読めないものを貼り付け、体裁を整えてから誤りを見つける、という普段の流れがサイトを行き来せずに済みます。

XML フォーマッタのほうは、整形そのものが目的であって何かの途中の一歩ではない場合の完全版です。半角スペース二つ、四つ、あるいはタブでの字下げ、コメントの扱い、そして逆方向の圧縮まで指定できます。あちらのページでも検証は走ります。文書は整形式でなければ、そもそも整形し直すことができないからです。

検証だけでなく XML を整形(beautify)できますか?

できます。整形、プリティプリント、フォーマットはいずれも同じ操作です。入れ子が見えるように字下げをやり直すことであり、たいていはそれが誤りを見つけられるようにしてくれます。

ひとつ知っておく価値のある点があります。多くの整形ツールがここを間違えるからです。要素と要素のあいだの空白は無意味で、変えても安全です。しかしテキストも含む要素の内側にある空白はデータであり、字下げをやり直すと文書の意味が変わります。<p>Hello <b>there</b></p> を三行に分けて字下げする整形ツールは、見せ方ではなく内容そのものを変えてしまっています。このツールは混在内容を見つけたときのまま残すので、整形後の文書でも一部が一行のままになります。

最良の XML バリデータはどれですか?

文書がすでにどこにあるのか、そして何を確かめたいのかによります。正直に答えるなら、それがこのサイトではない場合も含まれます。

貼り付けられる文書であれば、ブラウザのツールが最短です。比べる価値があるのは三点、スキーマ検証をそもそも行うか、そのためにファイルをアップロードするか、そして報告された誤りをもとに手を動かせるか、です。すでにプロジェクトで開いているファイルなら、エディタのほうが近い。VS Code に Red Hat の XML 拡張を入れるか IntelliJ を使えば、入力しながらスキーマ検証が走ります。メモリに載らないほど大きなファイルや、ビルドの一工程であれば、xmllint が適切で、たいていの環境にはすでに入っています。CI パイプラインなら、そこに置くべきはパイプラインを書いている言語のバリデータです。

このサイトが作られているのは、その中間の場合です。サーバーなしでのスキーマ検証、最初の一件だけでなくすべての構文エラーを一度に、そしてパーサの作者にではなく読む人に向けて書かれたメッセージ。

関連ツール

関連する解説

これで解決できるエラー