github.com/prebid/prebid-server@v0.275.0/util/jsonutil/jsonutil.go (about) 1 package jsonutil 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "io" 7 ) 8 9 var comma = []byte(",")[0] 10 var colon = []byte(":")[0] 11 var sqBracket = []byte("]")[0] 12 var openCurlyBracket = []byte("{")[0] 13 var closingCurlyBracket = []byte("}")[0] 14 var quote = []byte(`"`)[0] 15 16 // Finds element in json byte array with any level of nesting 17 func FindElement(extension []byte, elementNames ...string) (bool, int64, int64, error) { 18 elementName := elementNames[0] 19 buf := bytes.NewBuffer(extension) 20 dec := json.NewDecoder(buf) 21 found := false 22 var startIndex, endIndex int64 23 var i interface{} 24 for { 25 token, err := dec.Token() 26 if err == io.EOF { 27 // io.EOF is a successful end 28 break 29 } 30 if err != nil { 31 return false, -1, -1, err 32 } 33 if token == elementName { 34 err := dec.Decode(&i) 35 if err != nil { 36 return false, -1, -1, err 37 } 38 endIndex = dec.InputOffset() 39 40 if dec.More() { 41 //if there were other elements before 42 if extension[startIndex] == comma { 43 startIndex++ 44 } 45 for { 46 //structure has more elements, need to find index of comma 47 if extension[endIndex] == comma { 48 endIndex++ 49 break 50 } 51 endIndex++ 52 } 53 } 54 found = true 55 break 56 } else { 57 startIndex = dec.InputOffset() 58 } 59 } 60 if found { 61 if len(elementNames) == 1 { 62 return found, startIndex, endIndex, nil 63 } else if len(elementNames) > 1 { 64 for { 65 //find the beginning of nested element 66 if extension[startIndex] == colon { 67 startIndex++ 68 break 69 } 70 startIndex++ 71 } 72 for { 73 if endIndex == int64(len(extension)) { 74 endIndex-- 75 } 76 77 //if structure had more elements, need to find index of comma at the end 78 if extension[endIndex] == sqBracket || extension[endIndex] == closingCurlyBracket { 79 break 80 } 81 82 if extension[endIndex] == comma { 83 endIndex-- 84 break 85 } else { 86 endIndex-- 87 } 88 } 89 if found { 90 found, startInd, endInd, err := FindElement(extension[startIndex:endIndex], elementNames[1:]...) 91 return found, startIndex + startInd, startIndex + endInd, err 92 } 93 return found, startIndex, startIndex, nil 94 } 95 } 96 return found, startIndex, endIndex, nil 97 } 98 99 // Drops element from json byte array 100 // - Doesn't support drop element from json list 101 // - Keys in the path can skip levels 102 // - First found element will be removed 103 func DropElement(extension []byte, elementNames ...string) ([]byte, error) { 104 found, startIndex, endIndex, err := FindElement(extension, elementNames...) 105 if err != nil { 106 return nil, err 107 } 108 if found { 109 extension = append(extension[:startIndex], extension[endIndex:]...) 110 } 111 return extension, nil 112 }