1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gojsonschema
28
29 import (
30 "errors"
31 "fmt"
32 "reflect"
33
34 "github.com/xeipuuv/gojsonreference"
35 )
36
37 type schemaPoolDocument struct {
38 Document interface{}
39 Draft *Draft
40 }
41
42 type schemaPool struct {
43 schemaPoolDocuments map[string]*schemaPoolDocument
44 jsonLoaderFactory JSONLoaderFactory
45 autoDetect *bool
46 }
47
48 func (p *schemaPool) parseReferences(document interface{}, ref gojsonreference.JsonReference, pooled bool) error {
49
50 var (
51 draft *Draft
52 err error
53 reference = ref.String()
54 )
55
56 if _, ok := p.schemaPoolDocuments[reference]; pooled && ok {
57 return fmt.Errorf("Reference already exists: \"%s\"", reference)
58 }
59
60 if *p.autoDetect {
61 _, draft, err = parseSchemaURL(document)
62 if err != nil {
63 return err
64 }
65 }
66
67 err = p.parseReferencesRecursive(document, ref, draft)
68
69 if pooled {
70 p.schemaPoolDocuments[reference] = &schemaPoolDocument{Document: document, Draft: draft}
71 }
72
73 return err
74 }
75
76 func (p *schemaPool) parseReferencesRecursive(document interface{}, ref gojsonreference.JsonReference, draft *Draft) error {
77
78
79
80
81
82
83 switch m := document.(type) {
84 case []interface{}:
85 for _, v := range m {
86 p.parseReferencesRecursive(v, ref, draft)
87 }
88 case map[string]interface{}:
89 localRef := &ref
90
91 keyID := KEY_ID_NEW
92 if existsMapKey(m, KEY_ID) {
93 keyID = KEY_ID
94 }
95 if existsMapKey(m, keyID) && isKind(m[keyID], reflect.String) {
96 jsonReference, err := gojsonreference.NewJsonReference(m[keyID].(string))
97 if err == nil {
98 localRef, err = ref.Inherits(jsonReference)
99 if err == nil {
100 if _, ok := p.schemaPoolDocuments[localRef.String()]; ok {
101 return fmt.Errorf("Reference already exists: \"%s\"", localRef.String())
102 }
103 p.schemaPoolDocuments[localRef.String()] = &schemaPoolDocument{Document: document, Draft: draft}
104 }
105 }
106 }
107
108 if existsMapKey(m, KEY_REF) && isKind(m[KEY_REF], reflect.String) {
109 jsonReference, err := gojsonreference.NewJsonReference(m[KEY_REF].(string))
110 if err == nil {
111 absoluteRef, err := localRef.Inherits(jsonReference)
112 if err == nil {
113 m[KEY_REF] = absoluteRef.String()
114 }
115 }
116 }
117
118 for k, v := range m {
119
120 if k == KEY_CONST || k == KEY_ENUM {
121 continue
122 }
123
124
125 if k == KEY_PROPERTIES || k == KEY_DEPENDENCIES || k == KEY_PATTERN_PROPERTIES {
126 if child, ok := v.(map[string]interface{}); ok {
127 for _, v := range child {
128 p.parseReferencesRecursive(v, *localRef, draft)
129 }
130 }
131 } else {
132 p.parseReferencesRecursive(v, *localRef, draft)
133 }
134 }
135 }
136 return nil
137 }
138
139 func (p *schemaPool) GetDocument(reference gojsonreference.JsonReference) (*schemaPoolDocument, error) {
140
141 var (
142 spd *schemaPoolDocument
143 draft *Draft
144 ok bool
145 err error
146 )
147
148 if internalLogEnabled {
149 internalLog("Get Document ( %s )", reference.String())
150 }
151
152
153 refToURL, _ := gojsonreference.NewJsonReference(reference.String())
154
155
156
157
158 if spd, ok = p.schemaPoolDocuments[refToURL.String()]; ok {
159 if internalLogEnabled {
160 internalLog(" From pool")
161 }
162 return spd, nil
163 }
164
165
166
167
168 refToURL.GetUrl().Fragment = ""
169
170 if cachedSpd, ok := p.schemaPoolDocuments[refToURL.String()]; ok {
171 document, _, err := reference.GetPointer().Get(cachedSpd.Document)
172
173 if err != nil {
174 return nil, err
175 }
176
177 if internalLogEnabled {
178 internalLog(" From pool")
179 }
180
181 spd = &schemaPoolDocument{Document: document, Draft: cachedSpd.Draft}
182 p.schemaPoolDocuments[reference.String()] = spd
183
184 return spd, nil
185 }
186
187
188 if !reference.IsCanonical() {
189 return nil, errors.New(formatErrorDescription(
190 Locale.ReferenceMustBeCanonical(),
191 ErrorDetails{"reference": reference.String()},
192 ))
193 }
194
195 jsonReferenceLoader := p.jsonLoaderFactory.New(reference.String())
196 document, err := jsonReferenceLoader.LoadJSON()
197
198 if err != nil {
199 return nil, err
200 }
201
202
203 p.parseReferences(document, refToURL, true)
204
205 _, draft, _ = parseSchemaURL(document)
206
207
208 document, _, err = reference.GetPointer().Get(document)
209
210 if err != nil {
211 return nil, err
212 }
213
214 return &schemaPoolDocument{Document: document, Draft: draft}, nil
215 }
216
View as plain text