パーシングとは、構造化データを構文解析し、JSON、XML、CSV、Protobufから情報を抽出してアプリケーションで使用するプロセスです。Square Engineering(2025年)によると、パーシング戦略の選択はモバイルアプリケーションのパフォーマンスに直接影響します。ストリーミングパーシングを使用すると、ドキュメント全体をメモリに読み込まずにメガバイト単位のデータを処理できます。
重要なポイント
パーシング(構文解析)とは、文字の並びをプログラムによる処理に適した構造化表現に変換するプロセスです。モバイル開発の文脈では、パーシングとはサーバー応答、設定ファイル、ローカルキャッシュ、リソースファイルの処理を指します。各形式には独自のアプローチが必要です。JSON — 軽量でSDKに組み込み、XML — XSDスキーマ検証付きで厳格、CSV — 表形式データ用にミニマル、Protobuf — 厳格なスキーマを持つバイナリ形式です。
どのパーサーも、形式に関係なく3つの段階を経ます。字句解析は生のテキストをキー、文字列、数値、区切り文字、コメントなどのトークンに分割します。構文解析は文法の正しさをチェックします。JSONでの括弧のバランス、XMLでのタグのネストの正確さです。出力構造の構築は、JSONObject、Map、または以降の処理のためのトークンストリームなどのオブジェクト表現を形成します。Apple(2026年)によると、iOSの組み込みFoundationパーサーは遅延解析を使用しており、JSONの先頭のみを検証してリソースを節約します。
手動パーシング(JSONSerialization、XmlPullParser)はプロセスを完全に制御でき、非標準形式や各フィールドのカスタム検証が必要な場合に役立ちます。自動ライブラリ(JSONDecoder、Moshi、kotlinx.serialization)は開発を高速化しますが、エラー処理の詳細を隠蔽します。選択は要件によって異なります。データ構造が動的または事前に不明な場合は手動パーシングが適しています。スキーマが固定されている場合は、自動デシリアライゼーションによりコードが60〜70%削減されます。
パーシングはより広範な操作であり、ストリーミング方式で実行でき、必ずしも型付きオブジェクトを作成するわけではありません。デシリアライゼーションはパーシングの特定のケースであり、その結果は常に特定のプロパティ型を持つ既知のクラスのインスタンスです。JSONパーサーはドキュメントをMapまたはJsonElementに分解しますが、デシリアライザーは同じJSONを既知のフィールドとその型を持つUser、Order、またはProductオブジェクトに変換します。
| 特性 | パーシング | デシリアライゼーション |
|---|---|---|
| 結果 | JsonElement、Map、トークンストリーム | 型付きオブジェクト(User、Order) |
| ストリーミングモード | あり(SAX、JsonReader) | なし(オブジェクト全体をメモリに) |
| 型付け | オプション、動的型 | 必須、静的型 |
| 例 | XmlPullParser.next()、SAXイベント | json.decodeFromString<User>() |
ストリーミングパーシングは、デシリアライゼーションに対するパーシングの主な利点です。AndroidのXmlPullParserは、ドキュメント全体をRAMに読み込まずに、読み取りながらXMLを解析します。これは、大規模なAPI応答、数百のアイテムを含むRSSフィードの解析、サーバーダンプからの数千のJSONオブジェクトの配列処理に重要です。ストリーミングパーサーはトークンを1つずつ読み取り、ドキュメントサイズに関係なく一定のメモリを消費します。
JSONは支配的なデータ交換形式です。iOSでは、組み込みのJSONSerializationがJSONをAnyに解析し、JSONDecoderは直接Codable構造に解析します。Androidでは、標準のorg.jsonが手動解析用にJSONObjectとJSONArrayを提供します。GsonとMoshiは自動変換を追加します。手動アプローチと自動アプローチの選択は、ネットワーキング層の最初のアーキテクチャ上の決定です。
val jsonString = """{"users":[{"id":1,"name":"Alice"}]}"""
val jsonObject = JSONObject(jsonString)
val usersArray = jsonObject.getJSONArray("users")
for (i in 0 until usersArray.length()) {
val item = usersArray.getJSONObject(i)
val id = item.getInt("id")
val name = item.getString("name")
// ユーザー処理
}
org.jsonによる手動パーシングは、応答構造が事前に不明な場合や大きく異なる場合に役立ちます。このアプローチはエラー処理とnull許容フィールドを完全に制御できますが、自動デシリアライゼーションと比較してより多くのボイラープレートコードが必要です。小規模なプロジェクトやプロトタイプでは許容範囲ですが、本番環境ではMoshiまたはkotlinx.serializationが推奨されます。
MoshiライブラリのJsonReaderは、ストリーミングJSONパーシングのための強力なツールです。beginObject、nextName、nextString、nextInt、endObjectなどのメソッドを使用して、ドキュメントをトークンごとに読み取ります。このアプローチにより、一定のメモリ消費で任意のサイズのドキュメントを処理できます。Google(2026年)によると、JsonReaderによるストリーミングパーシングは、ドキュメント全体をJsonObjectに読み込むより2〜3倍高速で、最大80%少ないメモリを消費します。
val reader = JsonReader(StringReader(json))
reader.beginObject()
while (reader.hasNext()) {
val name = reader.nextName()
when (name) {
"id" -> val id = reader.nextInt()
"name" -> val name = reader.nextString()
"email" -> val email = reader.nextString()
else -> reader.skipValue()
}
}
reader.endObject()
この例は、JsonReaderがストリーミング方式でJSONを解析する様子を示しています。nextName()とnextInt()を呼び出すたびに、カーソルが次のトークンに進みます。skipValue()は、解析せずに不要なフィールドをスキップします。これは、JSONに50のフィールドがあるが3つだけが必要な場合に特に便利です。結果として、メモリ消費は最小限で、速度は最大になります。
XMLは、AndroidプロジェクトのリソースやエンタープライズアプリケーションのSOAPサービスで引き続き使用されています。Androidでは、組み込みのXmlPullParserが最小限のメモリ消費でストリーミング解析を提供します。DOMツリーを読み込まず、START_TAG、TEXT、END_TAGイベントを生成します。iOSでは、デリゲートアプローチでXMLParserを使用します。parser(didStartElement:)メソッドとparser(foundCharacters:)メソッドが要素を順次処理します。
CSVは、表形式データをエクスポートおよびインポートするための最も単純な形式です。モバイルアプリでは、CSVはレポートのエクスポート、参照データ(国リスト、通貨、コード)の読み込み、オフラインデータ同期に使用されます。ストリーミングライブラリはCSVパーシングに適しています。Apache Commons CSVとOpenCSVは、ファイルを1行ずつ処理し、値内の引用符とカンマをエスケープします。iOSでは、NSString.components(separatedBy:)デリミタメソッドを使用して、エッジケースを処理しながらCSVパーシングを実装できます。
class CSVParser: NSObject, XMLParserDelegate {
private var currentItem: [String: String] = [:]
private var currentElement: String = ""
func parser(
_ parser: XMLParser,
didStartElement elementName: String,
namespaceURI: String?,
qualifiedName qName: String?,
attributes attributeDict: [String: String]
) {
currentElement = elementName
if elementName == "item" {
currentItem = [:]
}
}
func parser(_ parser: XMLParser,
foundCharacters string: String) {
currentItem[currentElement] = string
}
}
RSSフィードを解析するためのiOSでのXMLParserデリゲートの例。didStartElementメソッドは開始タグごとに呼び出され、foundCharactersはタグ間のテキストコンテンツを返し、didEndElementは要素を完了します。このイベントベースのアーキテクチャにより、DOMツリーをメモリに読み込まずに任意のサイズのXMLを処理できます。これは、モバイルデバイスの限られたリソースにとって重要です。
Androidでは、CSVパーサーの選択はデータ量によって異なります。OpenCSVは、フルーエントAPI、POJOマッピング用のアノテーション、カスタムデリミタをサポートしています。Apache Commons CSVはより低レベルですが、大きなファイルでは高速です。単純なケース(1〜2カラム)では、エスケープ処理を伴うString.split(",")による手動パーシングで十分です。大きなCSVファイルを扱う本番プロジェクトでは、OpenCSVが推奨されます。
GoogleのProtocol Buffersは、速度とコンパクトさにおいてJSONを凌駕するバイナリシリアライゼーション形式です。Protobufメッセージは同等のJSONより3〜6倍少ない容量で、バイナリ形式と厳格なスキーマのおかげで4〜10倍高速に解析されます。主な欠点は、人間が読めないことと、protocコンパイラを介して.protoファイルからコードを生成する必要があることです。
ストリーミングProtobufパーシングはCodedInputStreamを介して実装されます。クライアントはメッセージ全体を読み込まずに、到着したフィールドを読み取ります。各フィールドにはタグ(番号+型)があり、パーサーは未知のフィールドをスキップできます。Google(2026年)によると、ストリーミングProtobufパーシングは1MB以上のメッセージを処理する際に最大90%少ないメモリを消費し、RAMが限られたモバイルデバイスにとって重要です。Protobuf-liteは、生成されるコードサイズに最適化されたAndroid向けの特別なバージョンです。
よくある質問
JSONSerializationは、型付けなしでAny(Dictionary、Array)を返す手動パーシングです。JSONDecoderはCodable型への自動デシリアライゼーションです。JSONSerializationは動的構造に柔軟性を提供し、JSONDecoderは既知のスキーマに対して速度と型安全性を提供します。本番環境では、JSONDecoderが推奨されます。
ストリーミングパーシングは、500KBを超える応答、RSS/Atomフィードの解析、メモリが限られたデバイスでのファイル処理には必須です。最大100KBの一般的なAPI応答では、JSONDecoderまたはMoshiによる自動デシリアライゼーションが推奨されます。コードがよりクリーンで、開発がより高速です。
Android SDKには、org.json(JSONObject、JSONArray)、XmlPullParser(XML)、android.util.JsonReaderが含まれています。CSV、YAML、Protobufには追加のライブラリが必要です。CSVにはOpenCSV、YAMLにはSnakeYAML、Protobufにはprotobuf-javaliteが必要です。
kotlinx.serializationのlenientモード、またはMoshiのJsonReader.setLenient(true)を使用してください。末尾のカンマ、エスケープされていない引用符、1行コメントを許容します。完全な検証には、PactまたはSpring Cloud Contractを介したコントラクトテストを実装してください。
SAX(Simple API for XML)は、ドキュメントを走査しながらstartElement、characters、endElementイベントを生成するストリーミングXMLパーサーです。AndroidではXmlPullParser、iOSではXMLParserを介して実装されています。RSSリーダー、オフラインデータ同期、SVGファイル処理で使用されます。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。