4

我正在尝试使用 Prismatic/Schema 匹配以下序列:

[{:n "some text"}] ; => valid

[{:k "some text"} {:n "some text"}] ; => valid

我试过的:

(s/def Elem3
  {:k s/Str})

(s/def Elem2
  {:n s/Str})

(s/def Elem
  [(s/optional Elem2 "elem2") Elem3])

(s/validate Elem [{:k "huji"}])
;; =>
;; Value does not match schema: [(named {:n missing-required-key, :k
;; disallowed-key} "elem2")]

(s/def Elem
  [(s/maybe Elem2) Elem3])

(s/validate Elem [{:k "huji"}])
;; =>
;; [(maybe {:n Str}) {:k java.lang.String}] is not a valid sequence
;; schema; a valid sequence schema consists of zero or more `one`
;; elements, followed by zero or more `optional` elements, followed by
;; an optional schema that will match the remaining elements.

(s/defrecord ElemOption1
  [elem3 :- Elem3])

(s/defrecord ElemOption2
    [elem2 :- Elem2
     elem3 :- Elem3])

(s/def Elem
  (s/conditional
   #(= 2 (count %)) ElemOption2
   :else ElemOption1))

(s/validate Elem [{:k "huji"}])
;; =>
;; Value does not match schema: (not (instance?
;;  peg_dsl.standard_app.ElemOption1 [{:k "huji"}]))

主要问题是我不明白编写允许省略指定向量的第一个元素的模式的方法是什么。从上面匹配两个向量的正确方法是什么?

4

1 回答 1

1

您第一次尝试的问题是,从可选开始意味着它需要 {:ks/Str} 或什么都没有,并且它正在看到 {:n s/Str},所以这显然是不对的。

您的第二次尝试有两个问题。Maybe可以是值 or nil,但它必须存在。您也没有正确编写序列模式。但是顺序模式的问题是元素需要按顺序排列s/one* s/optional*,并且您想要s/optional s/one

您的第三次尝试更接近,使用条件,但您没有匹配,因为您没有验证记录的实例,您正在验证地图。

解决方案如下所示:

(def ElemKNList [(s/one {:k s/Str} "k") (s/one {:n s/Str} "n")])
(def ElemNList [(s/one {:n s/Str} "n")])

(def Elem (s/conditional #(= 2 (count %)) ElemKNList 
                         :else ElemNList))

(s/validate Elem [{:k "huji"} {:n "huji"}])    
    => [{:k "huji"} {:n "huji"}]
(s/validate Elem [{:n "huji"}])
    => [{:n "huji"}]          
(s/validate Elem [{:k "huji"}])
    => ExceptionInfo Value does not match schema: [(named {:n missing-required-key, :k disallowed-key} "n")]  schema.core/validator/fn--18435 (core.clj:151)               
于 2015-12-25T21:49:39.383 回答