implemented Set, revamped GET and wrote an internal implementation
diff --git a/src/gojsonpointer/pointer.go b/src/gojsonpointer/pointer.go
index be7be8a..19f633a 100644
--- a/src/gojsonpointer/pointer.go
+++ b/src/gojsonpointer/pointer.go
@@ -26,6 +26,20 @@
const_invalid_start = `JSON pointer must be empty or start with a "` + const_pointer_separator
)
+type implStruct struct {
+ mode string // "SET" or "GET"
+
+ inDocument interface{}
+
+ setInValue interface{}
+
+ getOutNode interface{}
+ getOutKind reflect.Kind
+
+ setOutDocument interface{}
+ outError error
+}
+
func NewJsonPointer(jsonPointerString string) (JsonPointer, error) {
var p JsonPointer
@@ -60,16 +74,41 @@
// Uses the pointer to retrieve a value from a JSON document
func (p *JsonPointer) Get(document interface{}) (interface{}, reflect.Kind, error) {
+ is := &implStruct{mode: "GET", inDocument: document}
+ p.implementation(is)
+ return is.getOutNode, is.getOutKind, is.outError
+
+}
+
+// Uses the pointer to update a value from a JSON document
+func (p *JsonPointer) Set(document interface{}, value interface{}) (interface{}, error) {
+
+ is := &implStruct{mode: "SET", inDocument: document, setInValue: value}
+ p.implementation(is)
+ return is.setOutDocument, is.outError
+
+}
+
+func (p *JsonPointer) implementation(i *implStruct) {
+
kind := reflect.Invalid
// Full document when empty
if len(p.referenceTokens) == 0 {
- return document, kind, nil
+ i.getOutNode = i.inDocument
+ i.outError = nil
+ i.getOutKind = kind
+
+ i.setOutDocument = i.setInValue
+ i.outError = nil
+ return
}
- node := document
+ node := i.inDocument
- for _, token := range p.referenceTokens {
+ for ti, token := range p.referenceTokens {
+
+ isLastToken := ti == len(p.referenceTokens)-1
rValue := reflect.ValueOf(node)
kind = rValue.Kind()
@@ -80,25 +119,47 @@
m := node.(map[string]interface{})
if _, ok := m[token]; ok {
node = m[token]
+ if isLastToken && i.mode == "SET" {
+ m[token] = i.setInValue
+ }
} else {
- return nil, kind, errors.New(fmt.Sprintf("Object has no key '%s'", token))
+ i.outError = errors.New(fmt.Sprintf("Object has no key '%s'", token))
+ i.getOutKind = kind
+ i.getOutNode = nil
+ i.setOutDocument = nil
+ return
}
case reflect.Slice:
s := node.([]interface{})
tokenIndex, err := strconv.Atoi(token)
if err != nil {
- return nil, kind, errors.New(fmt.Sprintf("Invalid array index '%s'", token))
+ i.outError = errors.New(fmt.Sprintf("Invalid array index '%s'", token))
+ i.getOutKind = kind
+ i.getOutNode = nil
+ i.setOutDocument = nil
+ return
}
sLength := len(s)
if tokenIndex < 0 || tokenIndex >= sLength {
- return nil, kind, errors.New(fmt.Sprintf("Out of bound array[0,%d] index '%d'", tokenIndex, sLength))
+ i.outError = errors.New(fmt.Sprintf("Out of bound array[0,%d] index '%d'", tokenIndex, sLength))
+ i.getOutKind = kind
+ i.getOutNode = nil
+ i.setOutDocument = nil
+ return
}
node = s[tokenIndex]
+ if isLastToken && i.mode == "SET" {
+ s[tokenIndex] = i.setInValue
+ }
default:
- return nil, kind, errors.New(fmt.Sprintf("Invalid token reference '%s'", token))
+ i.outError = errors.New(fmt.Sprintf("Invalid token reference '%s'", token))
+ i.getOutKind = kind
+ i.getOutNode = nil
+ i.setOutDocument = nil
+ return
}
}
@@ -106,7 +167,10 @@
rValue := reflect.ValueOf(node)
kind = rValue.Kind()
- return node, kind, nil
+ i.getOutNode = node
+ i.getOutKind = kind
+ i.outError = nil
+ i.setOutDocument = i.inDocument
}
// Pointer to string representation function