2016-11-08 14 views
9

Tôi đang cố gắng để nhân rộng các Json Schema ví dụ sau, bằng cách định nghĩa lược đồ trong mã sử dụng Newtonsoft.Json.Schema:Làm thế nào để xác định một Schema Json chứa các định nghĩa, trong mã

{ 
    "$schema": "http://json-schema.org/draft-04/schema#", 

    "definitions": { 
    "address": { 
     "type": "object", 
     "properties": { 
     "street_address": { "type": "string" }, 
     "city":   { "type": "string" }, 
     "state":   { "type": "string" } 
     }, 
     "required": ["street_address", "city", "state"] 
    } 
    }, 

    "type": "object", 

    "properties": { 
    "billing_address": { "$ref": "#/definitions/address" }, 
    "shipping_address": { "$ref": "#/definitions/address" } 
    } 

Đây là càng gần như tôi đã có cho đến nay. (Ví dụ là trong F # nhưng cũng giống như cũng có thể là trong C#.)

Code:

open Newtonsoft.Json.Schema 
open Newtonsoft.Json.Linq 

let makeSchema = 
    let addressSchema = JSchema() 
    addressSchema.Properties.Add("street_address", JSchema(Type = Nullable(JSchemaType.String))) 
    addressSchema.Properties.Add("city", JSchema(Type = Nullable(JSchemaType.String))) 
    addressSchema.Properties.Add("state", JSchema(Type = Nullable(JSchemaType.String))) 
    addressSchema.Required.Add "street_address" 
    addressSchema.Required.Add "city" 
    addressSchema.Required.Add "state" 

    let schema = JSchema() 
    schema.Properties.Add("billing_address", addressSchema) 
    schema.Properties.Add("shipping_address", addressSchema) 
    schema 

Output:

{ 
    "properties": { 
    "billing_address": { 
     "properties": { 
     "street_address": { 
      "type": "string" 
     }, 
     "city": { 
      "type": "string" 
     }, 
     "state": { 
      "type": "string" 
     } 
     }, 
     "required": [ 
     "street_address", 
     "city", 
     "state" 
     ] 
    }, 
    "shipping_address": { 
     "$ref": "#/properties/billing_address" 
    } 
    } 
} 

Như bạn có thể thấy, chỉ có một trong hai địa chỉ được xác định sử dụng tham chiếu đến một giản đồ khác và lược đồ địa chỉ nằm trong "thuộc tính" thay vì "định nghĩa". Bí quyết để xác định lược đồ trong "định nghĩa" là gì và tham chiếu nó ở nơi khác?

Trả lời

8

Hackfest! :-)

Theo source code, Lược đồ JSON.NET không viết thuộc tính definitions, kết thúc câu chuyện. Vì vậy, tất cả đều vô vọng ... Hầu như.

Hiện tại, sử dụng thuộc tính definitions ở một nơi khác. Cụ thể là - when generating schema from a type. Trong quá trình đó, nó tạo ra một JObject, đẩy tất cả các lược đồ vào nó, và sau đó thêm đối tượng đó vào JSchema.ExtensionData dưới khóa definitions. Và khi tham chiếu một lược đồ từ một vị trí khác, trình soạn thảo lược đồ sẽ tôn trọng đối tượng definitions, nếu có, do đó làm cho toàn bộ công việc hoạt động cùng nhau.

Vì vậy, trang bị kiến ​​thức này, chúng ta có thể hack theo cách của chúng tôi vào nó:

let makeSchema = 
    let addressSchema = JSchema() 
    ... 

    let definitions = JObject() :> JToken 
    definitions.["address"] <- addressSchema |> JSchema.op_Implicit 

    let schema = JSchema() 
    schema.ExtensionData.["definitions"] <- definitions 
    schema.Properties.Add("billing_address", addressSchema) 
    schema.Properties.Add("shipping_address", addressSchema) 
    schema 

Và thì đấy! Giản đồ kết quả bây giờ có một đối tượng definitions, cũng giống như các văn bản thiêng liêng cho chúng tôi biết nó nên:

{ 
    "definitions": { 
    "address": { 
     "properties": { 
     "street_address": { 
      "type": "string" 
     }, 
     "city": { 
      "type": "string" 
     }, 
     "state": { 
      "type": "string" 
     } 
     }, 
     "required": [ 
     "street_address", 
     "city", 
     "state" 
     ] 
    } 
    }, 
    "properties": { 
    "billing_address": { 
     "$ref": "#/definitions/address" 
    }, 
    "shipping_address": { 
     "$ref": "#/definitions/address" 
    } 
    } 
} 

Một vài lưu ý:

  1. Tên definitions không phải là đặc biệt từ quan điểm của JSON.NET xem. Nếu bạn thay đổi dòng schema.ExtensionData.["definitions"] thành thứ gì đó khác, hãy nói schema.ExtensionData.["xyz"], nó sẽ vẫn hoạt động, với tất cả các tham chiếu trỏ đến "#/xyz/address".
  2. Toàn bộ cơ chế này, rõ ràng là hack Rõ ràng là không, according to James Netwon-King. Thông tin chi tiết quan trọng dường như là JsonSchemaWriter sẽ có thể tra cứu bất kỳ đề cập nào về các lược đồ trước đó và sử dụng các tham chiếu đến chúng ở những vị trí khác. Điều này cho phép người ta bỏ các lược đồ ở bất cứ nơi nào người ta thích và mong đợi họ được tham chiếu.
  3. Điều đó cần op_Implicit cuộc gọi. JSchema không phải là loại phụ của JToken, vì vậy bạn không thể chỉ bị kẹt thành definitions.["address"] như vậy, trước tiên bạn phải chuyển đổi nó thành JToken. May mắn thay, có một số implicit cast operator được xác định cho điều đó. Thật không may, nó không phải đơn giản, có vẻ như có một số phép thuật đang diễn ra. Điều này happens transparently in C# (bởi vì, bạn biết đấy, không có đủ sự nhầm lẫn vì nó), nhưng trong F # bạn phải gọi nó một cách rõ ràng.
+0

Thankyou rất nhiều! Chúng tôi đã gần với điều này nhưng op_Implicit là những gì đẩy chúng tôi qua đường dây. Tôi đã đăng sự cố: https://github.com/JamesNK/Newtonsoft.Json.Schema/issues/60. Sẽ đánh dấu là câu trả lời khi tôi đã thử nghiệm điều này. (Tôi chắc chắn nó là tốt.; -) – Kit

+0

Sử dụng cách tiếp cận này trong "thế giới thực" của chúng tôi mã và nó làm việc như một say mê. Cảm ơn một lần nữa! – Kit

+0

Vui mừng được trợ giúp –

Các vấn đề liên quan