Merge pull request #3 from Aetheus/master
Add Delete function
diff --git a/README.md b/README.md
index dbe4d50..0005924 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,39 @@
# gojsonpointer
An implementation of JSON Pointer - Go language
+## Usage
+ jsonText := `{
+ "name": "Bobby B",
+ "occupation": {
+ "title" : "King",
+ "years" : 15,
+ "heir" : "Joffrey B"
+ }
+ }`
+
+ var jsonDocument map[string]interface{}
+ json.Unmarshal([]byte(jsonText), &jsonDocument)
+
+ //create a JSON pointer
+ pointerString := "/occupation/title"
+ pointer, _ := NewJsonPointer(pointerString)
+
+ //SET a new value for the "title" in the document
+ pointer.Set(jsonDocument, "Supreme Leader of Westeros")
+
+ //GET the new "title" from the document
+ title, _, _ := pointer.Get(jsonDocument)
+ fmt.Println(title) //outputs "Supreme Leader of Westeros"
+
+ //DELETE the "heir" from the document
+ deletePointer := NewJsonPointer("/occupation/heir")
+ deletePointer.Delete(jsonDocument)
+
+ b, _ := json.Marshal(jsonDocument)
+ fmt.Println(string(b))
+ //outputs `{"name":"Bobby B","occupation":{"title":"Supreme Leader of Westeros","years":15}}`
+
+
## References
http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07
diff --git a/pointer.go b/pointer.go
index 06f1918..7faf5d7 100644
--- a/pointer.go
+++ b/pointer.go
@@ -90,6 +90,13 @@
}
+// Uses the pointer to delete a value from a JSON document
+func (p *JsonPointer) Delete(document interface{}) (interface{}, error) {
+ is := &implStruct{mode: "DEL", inDocument: document}
+ p.implementation(is)
+ return document, is.outError
+}
+
// Both Get and Set functions use the same implementation to avoid code duplication
func (p *JsonPointer) implementation(i *implStruct) {
@@ -106,9 +113,14 @@
node := i.inDocument
+ previousNodes := make([]interface{}, len(p.referenceTokens))
+ previousTokens := make([]string, len(p.referenceTokens))
+
for ti, token := range p.referenceTokens {
isLastToken := ti == len(p.referenceTokens)-1
+ previousNodes[ti] = node
+ previousTokens[ti] = token
switch v := node.(type) {
@@ -118,7 +130,11 @@
node = v[decodedToken]
if isLastToken && i.mode == "SET" {
v[decodedToken] = i.setInValue
+ } else if isLastToken && i.mode =="DEL" {
+ delete(v,decodedToken)
}
+ } else if (isLastToken && i.mode == "SET") {
+ v[decodedToken] = i.setInValue
} else {
i.outError = fmt.Errorf("Object has no key '%s'", decodedToken)
i.getOutKind = reflect.Map
@@ -144,6 +160,11 @@
node = v[tokenIndex]
if isLastToken && i.mode == "SET" {
v[tokenIndex] = i.setInValue
+ } else if isLastToken && i.mode =="DEL" {
+ v[tokenIndex] = v[len(v)-1]
+ v[len(v)-1] = nil
+ v = v[:len(v)-1]
+ previousNodes[ti-1].(map[string]interface{})[previousTokens[ti-1]] = v
}
default:
diff --git a/pointer_test.go b/pointer_test.go
index 9e66d51..612f76e 100644
--- a/pointer_test.go
+++ b/pointer_test.go
@@ -245,3 +245,103 @@
}
}
+
+func TestSetEmptyNode(t *testing.T) {
+
+ jsonText := `{}`
+
+ var jsonDocument interface{}
+ json.Unmarshal([]byte(jsonText), &jsonDocument)
+
+ in := "/a"
+
+ p, err := NewJsonPointer(in)
+ if err != nil {
+ t.Errorf("NewJsonPointer(%v) error %v", in, err.Error())
+ }
+
+ _, err = p.Set(jsonDocument, 999)
+ if err != nil {
+ t.Errorf("Set(%v) error %v", in, err.Error())
+ }
+
+ firstNode := jsonDocument.(map[string]interface{})
+ target := firstNode["a"].(int)
+ if target != 999 {
+ t.Errorf("Set(%s) failed", in)
+ }
+}
+
+func TestDelObject(t *testing.T) {
+ jsonText := `{
+ "a":["apple sauce", "ketchup", "soy sauce"],
+ "d": {
+ "z" : {
+ "v" : {
+ "name" : "donald mcbobble",
+ "occupation" : "corporate overlord"
+ }
+ }
+ }
+ }`
+
+ var jsonDocument map[string]interface{}
+ json.Unmarshal([]byte(jsonText), &jsonDocument)
+
+ //Deleting an object key
+ in := "/d/z/v/occupation"
+ p, err := NewJsonPointer(in)
+ if err != nil {
+ t.Errorf("NewJsonPointer(%v) error %v", in, err.Error())
+ }
+
+ _, err = p.Delete(jsonDocument)
+ if err != nil {
+ t.Errorf("Delete(%v) error %v", in, err.Error())
+ }
+
+ var d map[string]interface{} = jsonDocument["d"].(map[string]interface{})
+ var z map[string]interface{} = d["z"].(map[string]interface{})
+ var v map[string]interface{} = z["v"].(map[string]interface{})
+
+ if _, present := v["occupation"]; present {
+ t.Errorf("Delete (%s) failed: key is still present in the map", in)
+ }
+}
+
+
+func TestDelArray(t *testing.T) {
+ jsonText := `{
+ "a":["applesauce", "ketchup", "soysauce", "oliveoil"],
+ "d": {
+ "z" : {
+ "v" : {
+ "name" : "donald mcbobble",
+ "occupation" : "corporate overlord",
+ "responsibilities" : ["managing", "hiring"]
+ }
+ }
+ }
+ }`
+
+ var jsonDocument map[string]interface{}
+ json.Unmarshal([]byte(jsonText), &jsonDocument)
+
+ //Deleting an array member
+ in := "/a/2"
+ p, err := NewJsonPointer(in)
+ if err != nil {
+ t.Errorf("NewJsonPointer(%v) error %v", in, err.Error())
+ }
+
+ _, err = p.Delete(jsonDocument)
+ if err != nil {
+ t.Errorf("Delete(%v) error %v", in, err.Error())
+ }
+
+ a := jsonDocument["a"].([]interface{})
+ if len(a) != 3 || a[2] == "soysauce" {
+ t.Errorf("Delete(%v) error (%s)", in, a)
+ }
+
+}