このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

XJSONのセレクター式/パス式

Catyでは、JSONにタグを許したXJSONというデータ形式をいたるところで使っています。タグ付きのデータとは、@tel "03-1234-5678", @YEN 1200, @person {"name": "m-hiyama", "gender": "male"} とかです。

XJSONデータの一部を抜き出すセレクター式/パス式については、「JSON向けのシンプルセレクター」で述べました。が、もっと単純化できないかと考えていて、やっと満足できるほどに単純な構文にたどり着きました。

セレクターのコア構文では、文字列、番号、名前というトークンと、メンバーアクセス演算子のドット'.'、2種のワイルドカード'*'と'#'しか使いません。

トーク

文字列はJSONと同じ構文ですが、シングルクォートで囲んだ文字列も許します。


Esc ::= '\"' | "\'" | '\\' | '\/' |
'\b' | '\f' | '\n' | '\r' | '\t' |
'\u' FourHexDigits

Printable ::= {任意の印字可能Unicode文字、間隔空白文字とタブ文字を含める}

PrintableSpecial ::= '"' | "'" | '\'

StringContentChar ::= (Printable - PrintableSpecial) | Esc

DQString ::= '"' (StringContentChar | "'")* '"'

SQString ::= "'" (StringContentChar | '"')* "'"

名前の定義は、最近は次を使っています。


Name ::= NameStartChar (NameChar)*

NameStartChar ::= [A-Z] | "_" | [a-z] | ExtNameStartChar

NameChar ::= NameStartChar | "-" | [0-9] | ExtNameChar

ExtNameStartChar :: = [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] |
[#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] |
[#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] |
[#xFDF0-#xFFFD] | [#x10000-#xEFFFF]

ExtNameChar ::= #xB7 | [#x0300-#x036F] | [#x203F-#x2040]

番号(インデックス)は、非負整数を表す表現です。


Index ::= '0' | [1-9][0-9]*

セレクター式/パス式

セレクター式の一般的な構文は次のようになります。


Member ::= Name '()'? | DQString | SQString | Index | '*' | '#'

Selector ::= Mebmer ('.' Member)*

このなかで、「JSON向けのシンプルセレクター」に出てこないのは、Name '()' というお尻に丸括弧が付いたメンバーだけです。これは後で説明することにして、セレクター式の例をいくつか出します。

  1. authors
  2. authors.#
  3. authors.2.name
  4. authors.2.*
  5. authors.2.name.first
  6. authors.2.contact.tag()
  7. authors.length()

セレクター式で、ワイルドカード('*', '#')を含まないものがパス式です。

メソッド風の記法

先の例で、authors.2.contact.tag(), authors.length() では、tag(), length() というメソッド風のメンバーが出てきます。お尻に'()'が付いた名前は、実際のデータプロパティではなくて、そのデータになんらかの操作をして得られる値です。見た目のとおり、メソッドと思ってかまいません。

現在考えているメソッド風の記法は次のものです*1

  1. length() -- 配列の長さ
  2. tag() -- XJSONのタグ
  3. untagged() または content() -- XJSONのタグを取り除いた部分

互換性や拡張

以前から、与えられたデータそのもの(ルートデータ)を '$' で表していました。この'$'は、「あってもなくてもいい」という位置付けです。ブラケットを使った記法、authors[2] とか authors[2]["name"] とかもあったほうがいいでしょう。セレクターの場合は、論理条件式によるフィルタリングがあれば便利です。これもサポートするつもりです。

しかし、「ドットとワイルドカードだけ」という最小限の構文でも、実用上けっこう間にあうことは経験済みです。これより簡単にはできないので、究極に単純な構文だと思います。

*1:もっと追加するかも知れません。