
My name is Arne Brasseur (@plexus)
I’m from Belgium, but based in Berlin.
I do Clojure consulting & training.
Detailed screencasts about all things Clojure & ClojureScript.
Been going for ~2.5 years.
You should check it out.
clojure.zip API
Functional Zipper concept
Clojure implementation
fast-zip & rewrite-clj
A zipper (or loc) combines two pieces of information
some kind of tree-shaped data structure
a pointer to a node within the tree
zipper = tree + path
The zipper API allows you to
Move around in the tree
Modify the tree at your current location
(require '[clojure.zip :as z])
(def loc (z/vector-zip [[1 2] [3 4]]))
Note: I’m using loc, location, and zipper interchangeably.
Nested vectors (z/vector-zip v)
Nested sequences (z/seq-zip s)
XML documents (z/xml-zip doc)
Anything that has nodes and child nodes (z/zipper ... root)
(-> [[1 2] [3 [4 5] 6]]
z/vector-zip
z/down
z/right
z/down
z/rightmost
z/left
(z/append-child :x)
z/up
z/node)
;;=> [3 [4 5 :x] 6]
(-> [[1 2] [3 [4 5] 6]]
z/vector-zip
z/down
z/right
z/down
z/rightmost
z/left
(z/append-child :x)
z/root)
;;=> [[1 2] [3 [4 5 :x] 6]]
<cart>
<line-items>
<product sku="CH56" qty="1" price="2.5">Chocolate</product>
<product sku="CA94" qty="1" price="1.7">Candy</product>
<discount amount="10%" />
</line-items>
<customer>
<name>Arne</name>
<address>Berlin</address>
</customer>
</cart>
(require '[clojure.java.io :as io]
'[clojure.xml :as xml])
(def cart-xml
(-> "zipper_demo/cart.xml"
io/resource
io/file
xml/parse))
cart-xml
;;=>
{:tag "cart", :attrs {}
:content
[{:tag "line-items", :attrs {}
:content
[{:tag "product"
:attrs {:sku "CH56"
:qty "1"
:price "2.5"}
:content ["Chocolate"]}
,,,]}
{:tag "customer" ,,,}]}
(def cart-zipper
(z/xml-zip cart-xml))
cart-zipper
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
nil]
(-> cart-zipper
z/down)
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})}]
(-> cart-zipper
z/down
z/down)
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil})}]
(-> cart-zipper
z/down
z/down
z/right)
[{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:l
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :discount,
:attrs {:amount "10%"},
:content nil})}]
(-> cart-zipper
z/down
z/down
z/right
z/right)
[{:tag :discount,
:attrs {:amount "10%"},
:content nil}
{:l
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r nil}]
(-> cart-zipper
z/down
z/down
z/right
z/right
z/leftmost)
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil})}]
(-> cart-zipper
z/down
z/down
z/right
z/right
z/leftmost
z/down)
["Chocolate"
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil})},
:r nil}]
(-> cart-zipper
z/down
z/down
z/down
(z/replace
"luxury chocolate"))
["luxury chocolate"
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil})},
:r nil,
:changed? true}]
(-> cart-zipper
z/down
z/down
z/down
(z/replace
"luxury chocolate")
z/up)
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["luxury chocolate"]}
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}),
:changed? true}]
(-> cart-zipper
z/down
z/down
z/down
(z/replace
"luxury chocolate")
z/up
(z/edit
assoc-in [:attrs :price] 2.9))
[{:tag :product,
:attrs
{:price 2.9,
:qty "1",
:sku "CH56"},
:content ["luxury chocolate"]}
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}),
:changed? true}]
(-> cart-zipper
z/down
z/down
z/down
(z/replace
"luxury chocolate")
z/up
(z/edit
assoc-in [:attrs :price] 2.9)
z/root)
;;=> {:tag "cart", ...}
vector-zip
xml-zip
seq-zip
zipper
up
down
left
right
leftmost
rightmost
root
insert-left
insert-right
append-child ;; rightmost
insert-child ;; leftmost
edit
remove
replace
make-node
lefts
rights
children
node
path
branch?
next
prev
end?
(nth
(iterate z/next cart-zipper)
0)
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
nil]
(nth
(iterate z/next cart-zipper)
1)
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})}]
(nth
(iterate z/next cart-zipper)
2)
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil})}]
(nth
(iterate z/next cart-zipper)
3)
["Chocolate"
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil})},
:r nil}]
(nth
(iterate z/next cart-zipper)
4)
[{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:l
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :discount,
:attrs {:amount "10%"},
:content nil})}]
(nth
(iterate z/next cart-zipper)
5)
["Candy"
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}],
:ppath
{:l
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :discount,
:attrs {:amount "10%"},
:content nil})},
:r nil}]
(nth
(iterate z/next cart-zipper)
6)
[{:tag :discount,
:attrs {:amount "10%"},
:content nil}
{:l
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r nil}]
(nth
(iterate z/next cart-zipper)
7)
[{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}
{:l
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}],
:ppath nil,
:r nil}]
(nth
(iterate z/next cart-zipper)
8)
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}],
:ppath
{:l
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r nil},
:r
({:tag :address,
:attrs nil,
:content ["Berlin"]})}]
(nth
(iterate z/next cart-zipper)
9)
["Arne"
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}
{:tag :name,
:attrs nil,
:content ["Arne"]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}],
:ppath
{:l
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r nil},
:r
({:tag :address,
:attrs nil,
:content ["Berlin"]})},
:r nil}]
(nth
(iterate z/next cart-zipper)
10)
[{:tag :address,
:attrs nil,
:content ["Berlin"]}
{:l
[{:tag :name,
:attrs nil,
:content ["Arne"]}],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}],
:ppath
{:l
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r nil},
:r nil}]
(nth
(iterate z/next cart-zipper)
11)
["Berlin"
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}],
:ppath
{:l
[{:tag :name,
:attrs nil,
:content ["Arne"]}],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}],
:ppath
{:l
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r nil},
:r nil},
:r nil}]
(nth
(iterate z/next cart-zipper)
12)
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
:end]
No boundary checks. Don’t fall off!
No way back from :end
It’s not a cursor: beware of empty containers
(-> [[1 2]]
z/vector-zip
z/down ;; [1 2]
z/down ;; 1
z/down
)
;;=> nil
;; ... oops ...
(if-let [l (z/left loc)]
(do-something-with l)
(do-something-else loc))
:end(-> [[1 2]]
z/vector-zip
z/next ;; [1 2]
z/next ;; 1
z/next ;; 2
z/next ;; :end
z/prev)
;; => nil
;; ... oops ...
A zipper points at a node, not in between nodes.
Corrolary: a zipper can not enter an empty container.
(-> [[1 2]]
z/vector-zip
z/down
z/down
z/remove
z/remove
(z/insert-left 3))
;;=> ???
(defn remove
"Removes the node at loc, returning the loc that
would have preceded it in a depth-first walk."
{:added "1.0"}
[loc]
,,,)
(-> [[1 2]]
z/vector-zip
z/down
z/down
z/remove
z/remove
(z/insert-left 3))
;; Exception: Insert at top
(ns ^{:doc "Functional hierarchical zipper,
with navigation, editing,
and enumeration. See Huet"
:author "Rich Hickey"}
clojure.zip)

A path is like a zipper, allowing one to rip the tree structure down to a
certain location. It contains its listlof left siblings , its father pathp,
and its listrof right siblings.
path = Top | (left siblings, parent path, right siblings)
A location in the tree adresses a subtree, together with its path
location = (current node, path)
(-> cart-zipper)
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
nil]
(-> cart-zipper
z/down)
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})}]
(-> cart-zipper
z/down
z/down)
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil})}]
(-> cart-zipper
z/down
z/down
z/right)
[{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:l
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :discount,
:attrs {:amount "10%"},
:content nil})}]
(-> cart-zipper
z/down
z/down
z/right
z/right)
[{:tag :discount,
:attrs {:amount "10%"},
:content nil}
{:l
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r nil}]
(-> cart-zipper
z/down
z/down
z/right
z/right
z/leftmost)
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil})}]
(-> cart-zipper
z/down
z/down
z/right
z/right
z/leftmost
z/down)
["Chocolate"
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil})},
:r nil}]
(-> cart-zipper
z/down
z/down
z/down
(z/replace
"luxury chocolate"))
["luxury chocolate"
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil})},
:r nil,
:changed? true}]
(-> cart-zipper
z/down
z/down
z/down
(z/replace
"luxury chocolate")
z/up)
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["luxury chocolate"]}
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}],
:ppath
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content
["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]})},
:r
({:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}),
:changed? true}]
(-> cart-zipper
z/down
z/down
z/down
(z/replace
"luxury chocolate")
z/up
z/up)
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["luxury chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:l [],
:pnodes
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content ["Chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}],
:ppath nil,
:r
({:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}),
:changed? true}]
(-> cart-zipper
z/down
z/down
z/down
(z/replace
"luxury chocolate")
z/up
z/up
z/up)
[{:tag :cart,
:attrs nil,
:content
[{:tag :line-items,
:attrs nil,
:content
[{:tag :product,
:attrs
{:price "2.5",
:qty "1",
:sku "CH56"},
:content
["luxury chocolate"]}
{:tag :product,
:attrs
{:price "1.7",
:qty "1",
:sku "CA94"},
:content ["Candy"]}
{:tag :discount,
:attrs {:amount "10%"},
:content nil}]}
{:tag :customer,
:attrs nil,
:content
[{:tag :name,
:attrs nil,
:content ["Arne"]}
{:tag :address,
:attrs nil,
:content ["Berlin"]}]}]}
nil]
(zipper branch? children make-node root)
;; Can this node have children?
(branch? node) ;;=> bool
;; Return the children of a branch node.
(children node) ;;=> sequence
;; Given an existing node and a new set of child nodes,
;; return a new node with those children.
(make-node node seq) ;;=> node
(defn zipper [branch? children make-node root]
^{:zip/branch? branch?
:zip/children children
:zip/make-node make-node}
[root nil])
(defn vector-zip
"Returns a zipper for nested vectors, given a root vector"
[root]
(zipper vector?
seq
(fn [node children]
(with-meta (vec children) (meta node)))
root))
(defn branch?
[loc]
((:zip/branch? (meta loc)) (node loc)))
(defn children
[loc]
((:zip/children (meta loc)) (node loc)))
(defn make-node
[loc node children]
((:zip/make-node (meta loc)) node children))
(vector-zip [[1 2] [3 [4 5] 6]])
;;=> [ [[1 2] [3 [4 5] 6]] nil ]
(meta (vector-zip [[1 2] [3 [4 5] 6]]))
;;=>
{:zip/branch? #function[clojure.core/vector?--5314],
:zip/children #function[clojure.core/seq--5302],
:zip/make-node #function[clojure.zip/vector-zip/fn--9127]}
(-> [[1 2] [3 [4 5] 6]]
z/vector-zip
z/down
z/right
z/down
z/rightmost
z/left
(z/append-child :x)
z/up
z/node)
;;=> [3 [4 5 :x] 6]
(-> [[1 2] [3 [4 5] 6]]
z/vector-zip
z/down
z/right
z/down
z/rightmost
z/left
(z/append-child :x)
z/root)
;;=> [[1 2] [3 [4 5 :x] 6]]
{fast-zip {:mvn/version "0.7.0"}}
- (:require [clojure.zip :as z])
+ (:require [fast-zip.core :as z])
Identical API, but faster!
Careful not to rely on implementation details.
{rewrite-clj {:mvn/version "0.6.1"}}
(require '[rewrite-clj.zip :as z])
(def loc (z/of-string (slurp "burrito.clj")))
Zipper over source code, Retains whitespace
Extra goodies: z/find, z/sexpr, …
cljfmt
zprint
lein-ancient
refactor-nrepl
mutant
…
(defn update-requires [loc renames]
(loop [loc loc]
(cond
(z/end? loc) loc
(and (z/list? loc) (-> loc z/down z/sexpr (= :require)))
(recur (-> loc z/down (update-requires* renames) z/next))
:else
(recur (z/next loc)))))
(-> [[[1 2] [3 4]] [[5 6] 7]]
z/vector-zip
z/down
z/down
z/down
(z/replace :X)
z/root)
(assoc-in [[[1 2] [3 4]] [[5 6] 7]]
[0 0 0]
:X)