世界を動かす技術を、日本語で。

XMLは手頃なDSLです

概要

  • IRSが新しい Tax Withholding Estimator (TWE) をリリース
  • TWEは オープンソース で、初めて 一般からの貢献 を受け入れ
  • XMLによる宣言的な仕様 で税計算ロジックを記述
  • Fact Graph エンジンを利用し、計算の透明性と追跡性を実現
  • JSONよりもXMLが適している理由 を解説

IRS新Tax Withholding Estimator (TWE)の概要

  • 2026年3月13日、IRSが新しい Tax Withholding Estimator (TWE) を発表
  • TWEは 無料かつオープンソース、初めて一般からのコントリビューションも歓迎
  • 利用者は 収入や控除額 などを入力し、年末の納税額を推定・給与天引き額を調整可能
  • TWE開発を通じて得られた パブリックセクターソフトウェア開発の知見 の共有
  • 本記事は 個人の立場 で執筆、公式見解ではない点を明記

XMLの再評価とFact Graphの仕組み

  • XML は古臭い・冗長との評価が多いが、 宣言的な仕様言語 として現代でも有用
  • Fact Graph は、税法を Fact Dictionary(事実辞書) としてXMLで記述し、依存関係をもとに計算
  • 例:/totalOwedは/totalTaxから/totalPaymentsを引いた値として定義
    • XML例:
      <Fact path="/totalOwed">
        <Derived>
          <Subtract>
            <Minuend>
              <Dependency path="/totalTax"/>
            </Minuend>
            <Subtrahends>
              <Dependency path="/totalPayments"/>
            </Subtrahends>
          </Subtract>
        </Derived>
      </Fact>
      
  • 冗長だが構造が明快 で、数式の意味を直感的に把握可能

具体的なXML定義例とその意義

  • リファンダブルクレジット (還付可能税額控除)は複数の控除を合算
  • ノンリファンダブルクレジット は税額をゼロまで減らせるが、マイナスにはならない
    • <GreaterOf>演算子で「ゼロまたは差額の大きい方」を選択
  • 入力値<Writable>で定義、金額なら<Dollar/>, 真偽値なら<Boolean/>を指定
  • Fact同士の依存関係 により、最終的な税額を導出

宣言的仕様のメリット

  • JavaScriptなどの 命令型言語 では計算過程や中間値が失われやすい
    • 例:const totalOwed = totalTax - totalPayments
  • 宣言的なFact Graph では「何をどう計算するか」のみ記述し、計算順序や実装詳細を意識しない
  • 監査性・追跡性 が高く、「なぜその値になったか」を容易に説明・検証可能
    • 例:TurboTaxの“Tax Knowledge Graph”も同様の思想だが、IRSのFact Graphは オープンソースかつパブリックドメイン
  • 複雑な税制ロジック の透明性・拡張性を確保

XMLとJSONの比較

  • 計算ロジックの 宣言的表現 にはXMLが適している
  • JSONは データ転送や設定ファイル には良いが、複雑なDSL(ドメイン固有言語)には不向き
  • XMLは 階層構造・拡張性 に優れ、Fact Graphのような複雑な依存関係を扱う用途に最適
  • JSONによる同等の記述は 冗長で可読性が低下 しやすい

まとめ:パブリックセクター開発におけるXMLの意義

  • 税制のような複雑なビジネスロジック は宣言的DSLで明示的に表現すべき
  • XMLベースのFact Graph は、拡張性・透明性・監査性が高い
  • オープンソース化 により、誰でも仕様を確認・拡張・修正可能
  • 今後の 公共ITシステム開発 において、XMLと宣言的設計思想の活用が期待

Hackerたちの意見

いい記事だけど、実はこのリンク先の投稿[0]の方がもっと良かった。著者がXMLがブラウザ戦争に負けたせいで、現代のウェブ開発ツールがたくさん生まれたって説明してるんだ。追記:もちろん、JSONのツールが増えたのはJSONが共通語になったからだよ。XMLが解決してたJSONの欠点に対処する必要が出てきたってことね。0: https://marcosmagueta.com/blog/the-lost-art-of-xml/

よくあるケースだよね。「複雑なことを学ぶのは面倒だから、簡単なものをくれ」って。2年後、「あれ、もっと機能が必要だ、問題が思ったより複雑だ」。

両方読んだけど、どちらもXMLの悪い時代にAPIと一緒に働くことがどうだったかを見落としてる気がする。確かにXMLは説明的だけど、プログラマーにとっては扱いにくいんだ。XMLベースのプロトコルを使うクライアントやサーバーは、XML文字列をその言語で意味のあるメモリ内データ構造(辞書やオブジェクト、配列など)にマッピングするための独自のエンコーダ/デコーダを持たなきゃいけなかった。これらはしばしば大きくて、メンテナンスも大変だった。JavaやC#のような言語には、XMLをオブジェクトにマッピングするための魔法のライブラリがあったけど、XMLの一部しかサポートしてなくて、XMLがその靴に合わないと、95%まで行っても最後の5%を入れる方法がなくて、ひどいストリーミングXMLパーサー(SAXみたいな)で全てを書き直さなきゃいけなかった。JSONは完璧ではないけど、ほとんどの言語が持ってるデータ構造(配列、オブジェクト、辞書)にきれいにマッピングできるから人気が出たんだ。それが理由で、他に理由はない。絶対に「流行」とかそんな馬鹿げた理由ではないよ。何十万人もの開発者がXMLストリームを生成して解析するのに20%の労力を費やすことに疲れ果ててたんだ。ほんとにひどかった。そして、XMLスキーマを設計しようとする人たちの終わりのない会議についてはもう話したくもない。これを属性にすべきか、子要素にすべきか?リストの中で異なる子要素を混ぜるのを許すか、それともパーサーをシンプルにするために間接レベルを追加するか?みんなが最もエレガントだと思うことについて違う考えを持ってて、結局どれも重要じゃなかった。JSONはAPIデザインにおいて、Prettierがタブとスペースの議論に与えた影響と同じことをしたんだ。

著者が「(XML)はJavaScriptが勝ったから捨てられた。ブラウザが勝った。」って言ってるのはよく分からないな。ブラウザはXMLもJavaScriptもサポートしてたし。「AJAX」の「X」はXMLのことだし、「XMLHttpRequest」は元々XMLでデータを取得するために使われる予定だったんだ。後にJSONデータを取得するために使われるようになったけど。JavaScriptがXMLを捨てる理由にはならないよ。開発者コミュニティがXMLを使ってみたけど、全然好きじゃなかっただけなんだ。開発者コミュニティが「正しかった」かどうかはコメントしづらいけど、リンク先の記事は愚痴が多くて、文脈の詳細が少ないからね。例えば、JSONのようなシンプルなフォーマットが「協力するサービス間の小さなデータ転送やスキーマ検証が過剰になるシナリオ」には適しているって認めてるし。じゃあ、彼らは「ドキュメント」や「ファイル」をJSON形式で保存する人たちのことを言ってるのかな?それもあると思うけど、他のフォーマット、例えばYAMLと比べてJSONがそんなに一般的に使われてるとは思えないな(ブラウザでJavaScriptが勝ったからってのは全然関係ないし)。個人的には、XMLが捨てられたのは設計が悪かったからだと思うし、もしかしたら過剰設計もあったかも。スキーマチェックのあるシンプルなフォーマットの方が理想的だと思う。

XMLは多くの言語で正しく解析するのがすごく高コストなんだ。実際、世界中のほとんどは3つのオープンソース実装(libxml2、expat、Xerces)に依存してる。これらを使わないと、実際の準拠には近づけないからね。それでも、いくつかの課題にぶつかることがある(libxml2は最近ほとんどメンテされてなかったけど、多くの他の言語のバインディングの基盤になってる)。SGML由来の言語の主な特徴は、「リスト」を第一級オブジェクトにして、ネストを第二級にしていること(「終了」タグを必要とするからね)。メタデータを追加するための2つの軸があって、一つはタグ名、もう一つは属性。だから、いろんなことに適したDSLではあるけど(ウェブコンポーネントの定義でも新たに使われてるし)、実際にはXMLに似た言語の話をしてるだけで、XMLそのものではないんだ。XMLそのものを使うなら、「安価」という概念は捨てなきゃいけない。ここで言いたいのは、命令的に見えるDSLでも、宣言的に解釈できることがあるってこと。例えば、totalOwed = totalTax - totalPayments、totalTax = tentativeTaxNetNonRefundableCredits + totalOtherTaxes、totalPayments = totalEstimatedTaxesPaid + totalTaxesPaidOnSocialSecurityIncome + totalRefundableCreditsって書いても、XMLに似たDSLと同じ意味になるんだ。命令的に見える宣言的な言語の一例はMETAFONTだよ。例えば、https://en.wikipedia.org/wiki/Metafont#Example(例がうまく示せてないかもしれないけど、すべての方程式を並べ替えても同じ結果が得られるはず)。

ちなみに、これもMathMLが数学の「入力」言語にならなかった理由の一つなんだ。レイアウト重視の(La)TeXが事実上の標準として残ってる。入力の使いやすさは重要で、正確性を高めるからね。通常、厳密でセマンティックなまま(例えば、LaTeXはPlain TeXよりもレイアウト重視ではない)保つことができる。

これでドメインの表記はできるけど、処理するエンジンが必要だよね。Prolong+CLPFDはそれに合ってるかも(税のドメインにはあまり詳しくないけど)。グリーンスプンの第10ルールをこの組み合わせに言い換えることもできるかも。

XMLは安い[...] > XMLは多くの言語で正しく解析するのが非常に高コストだって有名だよね。これがトップコメントで嬉しい。企業向けのJavaとXMLに関してはかなりの経験があるけど、XMLは安いなんてことは全然ないよ。実際、XMLで何かトリビアルじゃないことをするのは、メモリとCPUのボトルネックになることが多かった。

ここに著者がいるよ。これには同意するし、宣言的な仕様を命令的な数学表記のようにすることを妨げるものは何もないってことは重要だと思うけど、ちょっと本質から外れてる部分もあるよね。確かに、自分だけのカスタム言語を作ることはできるけど、そうするとこの記事が言ってる問題が生じるんだ。つまり、使いたい場所ごとにパーサーを移植しなきゃいけなくなるってこと。今はすべての構文の決定をしなきゃいけないしね。中置記法を使いたいなら、演算子の優先順位についてたくさんの選択をしなきゃいけない。この記事ではドメインを説明するためにシンプルな関数をたくさん使ってるけど、switch文もあるよね。あれはどう表現するの?共通の数学表記がない関数、例えば段階的な掛け算とかも同じだよ。これらはすべて解決できるけど、パーサーがもっと複雑になって、実装が一つしかない状況になりがちなんだ。もし、接頭辞記法や括弧に標準化しようとすると、s式が必要になる(この記事でも触れられている選択肢だね)。この文脈で「安い」というのは、すぐに解析できるライブラリがどの環境にもあって、ドキュメントをクエリするための成熟したツールがあるってことなんだ。XML DSLに新しいアイデアを追加しても、解析の複雑さは全然増えないよ。これって小さなチームにはすごく助かる!タイトルの「安い」って言葉には悩んだけど、「コスト効果が高い」とかもっとポジティブな言葉を使おうかとも考えた。でもやっぱり「安い」が正しいと思う。構文でコスト削減の選択をしてるわけで、それにはOPが指摘してるように表現力のトレードオフがあるけど、多くのドメイン、特に指定しているものを広く(安く)構築できるようにしたい場合には、絶対に正しい選択なんだ。

XMLが犯した同じ間違いを繰り返してる人たちをよく見るけど、学んでないんだよね。問題をこう説明するよ:> インターチェンジフォーマットに機能を追加すればするほど、そのフォーマットは解析が難しくなる。JSONが人気なのには理由があって、サポートする機能が少ないからこそ、インポートが本当に簡単なんだ。一方でXMLは属性、名前空間、CDATA、DTD、QName、xml:base、xml:lang、XIncludeなどなど、いろいろサポートしてる。キッチンシンクまで全部詰め込まれたんだ。最近、複雑さを減らすためにSqliteをインターチェンジフォーマットとして使うってスレッドがあったけど、Sqliteはアプリケーション特化型のデータストアとしては好きだけど、XMLと同じように機能がたくさんあって、データストアには良いけど、複数のプロデューサーやコンシューマーがそれぞれのアイデアを持つインターチェンジフォーマットには最悪なんだ。CSVは仕様が少ないかもしれないけど、生成や消費が簡単だから人気があるんだ。残念ながら、最近JSONを壊す人たちがいて、例えばフォーマットにコマンドを追加したり、その「コメント」をデータ(例えば型情報)を保持するために使ったりして、解析が必要になる。これはXML属性の悪いバージョンだよ。

XMLの複雑さの多くは、既存の文字やデータエンコーディングとのラウンドトリップ互換性を持たせたいという欲求や、SGMLとの前方互換性を持たせたいという欲求から来ている。特定の「プロファイル」のXML(例えば、UTF-8のみ、ユーザー定義のエンティティや一般的なDTDサポートなし)だけをサポートするパーサーは、言語の99%の価値を捉えつつ、もっとシンプルで効率的になれるんだ。

本当に大規模なDSL仕様をコンパイルしているわけじゃないなら、解析の速度を最適化する必要はないよ。この用途にXMLを使うなら、DOMを使っても十分速いしね。心配なのは、無限に解析が続く問題だけど、これを制御する方法はいくつかあるよ。

Hacker Newsで議論の続きを見る