@@ -3,23 +3,10 @@ package orderedmap
33import (
44 "bytes"
55 "encoding/json"
6- "errors"
76 "sort"
87 "strings"
98)
109
11- var NoValueError = errors .New ("No value for this key" )
12-
13- type KeyIndex struct {
14- Key string
15- Index int
16- }
17- type ByIndex []KeyIndex
18-
19- func (a ByIndex ) Len () int { return len (a ) }
20- func (a ByIndex ) Swap (i , j int ) { a [i ], a [j ] = a [j ], a [i ] }
21- func (a ByIndex ) Less (i , j int ) bool { return a [i ].Index < a [j ].Index }
22-
2310type Pair struct {
2411 key string
2512 value interface {}
@@ -117,201 +104,134 @@ func (o *OrderedMap) UnmarshalJSON(b []byte) error {
117104 if o .values == nil {
118105 o .values = map [string ]interface {}{}
119106 }
120- var err error
121- err = mapStringToOrderedMap (string (b ), o )
107+ err := json .Unmarshal (b , & o .values )
122108 if err != nil {
123109 return err
124110 }
125- return nil
126- }
127-
128- func mapStringToOrderedMap (s string , o * OrderedMap ) error {
129- // parse string into map
130- m := map [string ]interface {}{}
131- err := json .Unmarshal ([]byte (s ), & m )
132- if err != nil {
111+ dec := json .NewDecoder (bytes .NewReader (b ))
112+ if _ , err = dec .Token (); err != nil { // skip '{'
133113 return err
134114 }
135- // Get the order of the keys
136- orderedKeys := []KeyIndex {}
137- for k , _ := range m {
138- kEscaped := strings .Replace (k , `"` , `\"` , - 1 )
139- kQuoted := `"` + kEscaped + `"`
140- // Find how much content exists before this key.
141- // If all content from this key and after is replaced with a close
142- // brace, it should still form a valid json string.
143- sTrimmed := s
144- for len (sTrimmed ) > 0 {
145- lastIndex := strings .LastIndex (sTrimmed , kQuoted )
146- if lastIndex == - 1 {
147- break
148- }
149- sTrimmed = sTrimmed [0 :lastIndex ]
150- sTrimmed = strings .TrimSpace (sTrimmed )
151- if len (sTrimmed ) > 0 && sTrimmed [len (sTrimmed )- 1 ] == ',' {
152- sTrimmed = sTrimmed [0 : len (sTrimmed )- 1 ]
153- }
154- maybeValidJson := sTrimmed + "}"
155- testMap := map [string ]interface {}{}
156- err := json .Unmarshal ([]byte (maybeValidJson ), & testMap )
157- if err == nil {
158- // record the position of this key in s
159- ki := KeyIndex {
160- Key : k ,
161- Index : len (sTrimmed ),
162- }
163- orderedKeys = append (orderedKeys , ki )
164- // shorten the string to get the next key
165- startOfValueIndex := lastIndex + len (kQuoted )
166- valueStr := s [startOfValueIndex : len (s )- 1 ]
167- valueStr = strings .TrimSpace (valueStr )
168- if len (valueStr ) > 0 && valueStr [0 ] == ':' {
169- valueStr = valueStr [1 :len (valueStr )]
115+ o .keys = make ([]string , 0 , len (o .values ))
116+ return decodeOrderedMap (dec , o )
117+ }
118+
119+ func decodeOrderedMap (dec * json.Decoder , o * OrderedMap ) error {
120+ hasKey := make (map [string ]bool , len (o .values ))
121+ for {
122+ token , err := dec .Token ()
123+ if err != nil {
124+ return err
125+ }
126+ if delim , ok := token .(json.Delim ); ok && delim == '}' {
127+ return nil
128+ }
129+ key := token .(string )
130+ if hasKey [key ] {
131+ // duplicate key
132+ for j , k := range o .keys {
133+ if k == key {
134+ copy (o .keys [j :], o .keys [j + 1 :])
135+ break
170136 }
171- valueStr = strings .TrimSpace (valueStr )
172- if valueStr [0 ] == '{' {
173- // if the value for this key is a map
174- // find end of valueStr by removing everything after last }
175- // until it forms valid json
176- hasValidJson := false
177- i := 1
178- for i < len (valueStr ) && ! hasValidJson {
179- if valueStr [i ] != '}' {
180- i = i + 1
181- continue
182- }
183- subTestMap := map [string ]interface {}{}
184- testValue := valueStr [0 : i + 1 ]
185- err = json .Unmarshal ([]byte (testValue ), & subTestMap )
186- if err == nil {
187- hasValidJson = true
188- valueStr = testValue
189- break
190- }
191- i = i + 1
137+ }
138+ o .keys [len (o .keys )- 1 ] = key
139+ } else {
140+ hasKey [key ] = true
141+ o .keys = append (o .keys , key )
142+ }
143+
144+ token , err = dec .Token ()
145+ if err != nil {
146+ return err
147+ }
148+ if delim , ok := token .(json.Delim ); ok {
149+ switch delim {
150+ case '{' :
151+ if values , ok := o .values [key ].(map [string ]interface {}); ok {
152+ newMap := OrderedMap {
153+ keys : make ([]string , 0 , len (values )),
154+ values : values ,
155+ escapeHTML : o .escapeHTML ,
192156 }
193- // convert to orderedmap
194- // this may be recursive it values in the map are also maps
195- if hasValidJson {
196- newMap := New ()
197- err := mapStringToOrderedMap (valueStr , newMap )
198- if err != nil {
199- return err
200- }
201- m [k ] = * newMap
157+ if err = decodeOrderedMap (dec , & newMap ); err != nil {
158+ return err
202159 }
203- } else if valueStr [0 ] == '[' {
204- // if the value for this key is a slice
205- // find end of valueStr by removing everything after last ]
206- // until it forms valid json
207- hasValidJson := false
208- i := 1
209- for i < len (valueStr ) && ! hasValidJson {
210- if valueStr [i ] != ']' {
211- i = i + 1
212- continue
213- }
214- subTestSlice := []interface {}{}
215- testValue := valueStr [0 : i + 1 ]
216- err = json .Unmarshal ([]byte (testValue ), & subTestSlice )
217- if err == nil {
218- hasValidJson = true
219- valueStr = testValue
220- break
221- }
222- i = i + 1
160+ o .values [key ] = newMap
161+ } else if oldMap , ok := o .values [key ].(OrderedMap ); ok {
162+ newMap := OrderedMap {
163+ keys : make ([]string , 0 , len (oldMap .values )),
164+ values : oldMap .values ,
165+ escapeHTML : o .escapeHTML ,
223166 }
224- // convert to slice with any map items converted to
225- // orderedmaps
226- // this may be recursive if values in the slice are slices
227- if hasValidJson {
228- newSlice := []interface {}{}
229- err := sliceStringToSliceWithOrderedMaps (valueStr , & newSlice )
230- if err != nil {
231- return err
232- }
233- m [k ] = newSlice
167+ if err = decodeOrderedMap (dec , & newMap ); err != nil {
168+ return err
234169 }
235- } else {
236- o .Set (k , m [k ])
170+ o .values [key ] = newMap
171+ } else if err = decodeOrderedMap (dec , & OrderedMap {}); err != nil {
172+ return err
173+ }
174+ case '[' :
175+ if values , ok := o .values [key ].([]interface {}); ok {
176+ if err = decodeSlice (dec , values , o .escapeHTML ); err != nil {
177+ return err
178+ }
179+ } else if err = decodeSlice (dec , []interface {}{}, o .escapeHTML ); err != nil {
180+ return err
237181 }
238- break
239182 }
240183 }
241184 }
242- // Sort the keys
243- sort .Sort (ByIndex (orderedKeys ))
244- // Convert sorted keys to string slice
245- k := []string {}
246- for _ , ki := range orderedKeys {
247- k = append (k , ki .Key )
248- }
249- // Set the OrderedMap values
250- o .values = m
251- o .keys = k
252- return nil
253185}
254186
255- func sliceStringToSliceWithOrderedMaps (valueStr string , newSlice * []interface {}) error {
256- // if the value for this key is a []interface, convert any map items to an orderedmap.
257- // find end of valueStr by removing everything after last ]
258- // until it forms valid json
259- itemsStr := strings .TrimSpace (valueStr )
260- itemsStr = itemsStr [1 : len (itemsStr )- 1 ]
261- // get next item in the slice
262- itemIndex := 0
263- startItem := 0
264- endItem := 0
265- for endItem <= len (itemsStr ) {
266- couldBeItemEnd := false
267- couldBeItemEnd = couldBeItemEnd || endItem == len (itemsStr )
268- couldBeItemEnd = couldBeItemEnd || (endItem < len (itemsStr ) && itemsStr [endItem ] == ',' )
269- if ! couldBeItemEnd {
270- endItem = endItem + 1
271- continue
272- }
273- // if this substring compiles to json, it's the next item
274- possibleItemStr := strings .TrimSpace (itemsStr [startItem :endItem ])
275- var possibleItem interface {}
276- err := json .Unmarshal ([]byte (possibleItemStr ), & possibleItem )
187+ func decodeSlice (dec * json.Decoder , s []interface {}, escapeHTML bool ) error {
188+ for index := 0 ; ; index ++ {
189+ token , err := dec .Token ()
277190 if err != nil {
278- endItem = endItem + 1
279- continue
191+ return err
280192 }
281- if possibleItemStr [0 ] == '{' {
282- // if item is map, convert to orderedmap
283- oo := New ()
284- err := mapStringToOrderedMap (possibleItemStr , oo )
285- if err != nil {
286- return err
287- }
288- // add new orderedmap item to new slice
289- slice := * newSlice
290- slice = append (slice , * oo )
291- * newSlice = slice
292- } else if possibleItemStr [0 ] == '[' {
293- // if item is slice, convert to slice with orderedmaps
294- newItem := []interface {}{}
295- err := sliceStringToSliceWithOrderedMaps (possibleItemStr , & newItem )
296- if err != nil {
297- return err
193+ if delim , ok := token .(json.Delim ); ok {
194+ switch delim {
195+ case '{' :
196+ if index < len (s ) {
197+ if values , ok := s [index ].(map [string ]interface {}); ok {
198+ newMap := OrderedMap {
199+ keys : make ([]string , 0 , len (values )),
200+ values : values ,
201+ escapeHTML : escapeHTML ,
202+ }
203+ if err = decodeOrderedMap (dec , & newMap ); err != nil {
204+ return err
205+ }
206+ s [index ] = newMap
207+ } else if oldMap , ok := s [index ].(OrderedMap ); ok {
208+ newMap := OrderedMap {
209+ keys : make ([]string , 0 , len (oldMap .values )),
210+ values : oldMap .values ,
211+ escapeHTML : escapeHTML ,
212+ }
213+ if err = decodeOrderedMap (dec , & newMap ); err != nil {
214+ return err
215+ }
216+ s [index ] = newMap
217+ }
218+ } else if err = decodeOrderedMap (dec , & OrderedMap {}); err != nil {
219+ return err
220+ }
221+ case '[' :
222+ if index < len (s ) {
223+ values := s [index ].([]interface {})
224+ if err = decodeSlice (dec , values , escapeHTML ); err != nil {
225+ return err
226+ }
227+ } else if err = decodeSlice (dec , []interface {}{}, escapeHTML ); err != nil {
228+ return err
229+ }
230+ case ']' :
231+ return nil
298232 }
299- // replace original slice item with new slice
300- slice := * newSlice
301- slice = append (slice , newItem )
302- * newSlice = slice
303- } else {
304- // any non-slice and non-map item, just add json parsed item
305- slice := * newSlice
306- slice = append (slice , possibleItem )
307- * newSlice = slice
308233 }
309- // remove this item from itemsStr
310- startItem = endItem + 1
311- endItem = endItem + 1
312- itemIndex = itemIndex + 1
313234 }
314- return nil
315235}
316236
317237func (o OrderedMap ) MarshalJSON () ([]byte , error ) {
0 commit comments