2016-11-08 1 views
9
나는 다음과 같은 Json Schema 예를 복제하려고 시도하고

, Newtonsoft.Json.Schema 사용하여 코드에서 스키마를 정의하여 코드에서 정의를 포함하는 JSON 스키마 정의 : 내가있어로어떻게 내가

{ 
    "$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" } 
    } 

이 가깝다 지금까지. (예 F 번호에 있지만 단지뿐만 아니라 C#으로 수 있습니다.)

은 코드 :

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 

는 출력 : 당신이 볼 수 있듯이

{ 
    "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" 
    } 
    } 
} 

, 두 개의 주소 중 하나만 정의 다른 스키마에 대한 참조를 사용하며 주소 스키마는 "정의"가 아닌 "속성"에 있습니다. "정의"에서 스키마를 정의하고 다른 곳에서 스키마를 참조하는 트릭은 무엇입니까?

답변

8

Hackfest! :-)

source code에 따르면 JSON.NET 스키마는 이야기 끝인 definitions 속성을 작성하지 않습니다. 그래서 그것은 절망적입니다 ... 거의.

definitions 속성을 다른 곳에서 사용합니다. 즉 - when generating schema from a type. 이 과정에서 JObject을 만들고 모든 스키마를 해당 스키마에 푸시 한 다음 JSchema.ExtensionDatadefinitions 키 아래에 해당 개체를 추가합니다. 그리고 다른 장소에서 스키마를 참조 할 때 스키마 작성자는 해당 객체를 존중하여 모든 객체가 함께 작동하도록합니다.

그래서,이 지식으로 무장 한, 우리는 그것으로 우리의 방법을 해킹 할 수

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 

그리고 짜잔를!

{ 
    "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" 
    } 
    } 
} 

몇 가지 참고 사항을 :

  1. definitions 이름이 JSON.NET의 관점에서 특별한없는 결과 스키마는 이제 경전은 우리에게 그것을해야 단지 같은 definitions 개체가 보기의. schema.ExtensionData.["definitions"] 행을 다른 것으로 변경하면 (예 : schema.ExtensionData.["xyz"]) 여전히 작동하며 참조 번호는 모두 "#/xyz/address"을 가리 킵니다.
  2. 이 전체 메커니즘은 분명히 해킹입니다. 분명히 아니요, according to James Netwon-King. 핵심 통찰력은 JsonSchemaWriter이 이전에 언급 된 스키마를 조회하고 다른 곳에서 스키마에 대한 참조를 사용할 수있는 것으로 보입니다. 이것은 사람들이 어디에서나 스키마를 참조 할 수있게 해줍니다.
  3. op_Implicit 전화가 필요합니다. JSchemaJToken의 하위 유형이 아니므로 definitions.["address"]에 잼 할 수 없으므로 먼저 JToken으로 변환해야합니다. 다행스럽게도 그것에 대해 정의 된 implicit cast operator이 있습니다. 불행히도, 그것은 간단하지 않습니다, 거기에 어떤 마법이 진행되는 것 같습니다. 이 happens transparently in C# (혼란 스럽기 때문에 혼란 스럽지만), F #에서는 명시 적으로 호출해야합니다.
+0

정말 고마워요! 우리는 이것에 가깝지만 op_Implicit는 우리를 이끄는 것이 었습니다. https://github.com/JamesNK/Newtonsoft.Json.Schema/issues/60에 문제가 기록되었습니다. 내가 이것을 테스트했을 때 대답으로 표시됩니다. (나는 괜찮다고 확신한다.) -) – Kit

+0

"real world"코드에서이 접근법을 사용했고 매력적으로 작용했다. 다시 한 번 감사드립니다! – Kit

+0

도움이 된다니 기쁘다. –