2016-11-08 6 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" } 
    } 

इस रूप में मुझे मिल गया है के रूप में करीब है अब तक। (उदाहरण एफ # में है, लेकिन बस के रूप में अच्छी तरह से सी # में हो सकता है।)

कोड:

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

हैकफेस्ट! :-)

source code के अनुसार, JSON.NET स्कीमा definitions संपत्ति, कहानी के अंत में नहीं लिखता है। तो यह सब निराशाजनक है ... लगभग।

यह definitions किसी अन्य स्थान पर संपत्ति का उपयोग करता है, हालांकि। अर्थात् - when generating schema from a type। उस प्रक्रिया के दौरान, यह JObject बनाता है, इसमें सभी स्कीमा को धक्का देता है, और फिर उस ऑब्जेक्ट को JSchema.ExtensionData पर definitions कुंजी के अंतर्गत जोड़ता है। और जब किसी अन्य स्थान से स्कीमा का संदर्भ लेते हैं, तो स्कीमा लेखक definitions ऑब्जेक्ट का सम्मान करेगा, यदि मौजूद है, तो इस प्रकार पूरी चीज एक साथ काम कर रही है।

तो, यह ज्ञान के साथ सशस्त्र, हम इस पर ध्यान हमारे रास्ते हैक कर सकते हैं:

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 वस्तु है, पवित्र ग्रंथों ने हमें बताया है बस के रूप में यह होना चाहिए:

{ 
    "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 के दृष्टिकोण से विशेष नहीं है मानना ​​है कि। यदि आप 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# (क्योंकि, आप जानते हैं, इसमें पर्याप्त भ्रम नहीं है), लेकिन एफ # में आपको इसे स्पष्ट रूप से कॉल करना होगा।
+0

बहुत बहुत धन्यवाद! हम इसके करीब थे लेकिन op_Implicit हमें लाइन पर धक्का दिया था। मैंने एक समस्या लॉग कर दी है: https://github.com/JamesNK/Newtonsoft.Json.Schema/issues/60। जब मैंने इसका परीक्षण किया है तो जवाब के रूप में चिह्नित किया जाएगा। (मुझे यकीन है कि यह ठीक है।; -) – Kit

+0

हमारे "असली दुनिया" कोड में इस दृष्टिकोण का उपयोग किया और यह एक आकर्षण की तरह काम किया। एक बार फिर धन्यवाद! – Kit

+0

मदद की खुशी है –

संबंधित मुद्दे