liveBook · Manning

Clojure.zip

As explained in Clojure: The Essential Reference

clojure.zip is the Clojure namespace that implements zipper data structures for navigating and functionally editing tree-shaped data.

`clojure.zip` provides zippers for navigating and functionally editing tree-shaped data. A zipper location holds a focus within a tree. Moving returns another location; `zip/node` returns the data at the focus. Edits produce a changed location without mutating the original tree. Call `zip/root` to obtain the resulting data; to navigate that result again, create a new zipper. section 8.4.4

Choose a constructor for the tree, then work with locations until the result is ready:

  • Use `zip/vector-zip`, `zip/seq-zip`, or `zip/xml-zip` for their respective inputs. Use `zip/zipper` when the tree needs custom rules for identifying branches, finding children, and rebuilding nodes. section 8.4.4
  • Use `zip/down`, `zip/up`, `zip/left`, and `zip/right` to move locally; `zip/leftmost` and `zip/rightmost` jump to the outermost sibling. `zip/children`, `zip/lefts`, and `zip/rights` retrieve data rather than locations. A move with nowhere to go can return `nil`. section 8.4.4
  • Use `zip/replace` or `zip/edit` to change the focused node, `zip/remove` to delete it, and insertion functions to add siblings or children. Inserting a child at a leaf raises an exception. section 8.4.4

Edit a vector tree

`(require '[clojure.zip :as zip])` `(-> (zip/vector-zip [1 2 [3 4]]) zip/down zip/rightmost (zip/edit conj 5) zip/root)` ;; => [1 2 [3 4 5]] `zip/down` focuses the first child, `zip/rightmost` selects `[3 4]`, and `zip/edit` applies `conj` there. `zip/root` returns the complete edited vector. section 8.4.4

(defn custom-zip [root]
  (zip/zipper ; #1
    #(some-> % :node first map?) ; #2
    (comp seq :node) ; #3
    (fn [node children] ; #4
      (assoc node :node (vec children)))
    root)) ; #5

(def czip (custom-zip document)) ; #6
(-> czip zip/down zip/rightmost zip/down zip/node)
;; {:tag :checking, :meta nil, :node [90.11]}

A custom zipper supplies branch detection, child retrieval, and node reconstruction for a map-shaped tree; navigation then uses the same location functions. section 8.4.4

Unlike `clojure.walk`, a zipper does not require a depth-first traversal for every operation: navigate only the portion needed, or use `zip/next` and `zip/prev` for depth-first movement. For a whole-tree transformation, repeatedly process a location and advance with `zip/next` until `zip/end?`, then return `zip/root`. section 8.4.4

How Clojure: The Essential Reference covers it

How deep it goes
Explains constructors, location and data operations, edits, custom zipper callbacks, traversal, and edge cases through executable examples.
Examples
Demonstrates vector, sequence, XML, and custom map trees, including edits and a whole-tree transformation.
What it assumes
Assumes familiarity with Clojure collections and function calls; introduces zipper locations, constructors, and custom callbacks through examples.
What you can do after
Apply it via clojure.zip to navigate selected tree locations, edit nodes without mutation, and retrieve the changed root.
How it connects
Connects zippers to tree traversal, functional updates, clojure.walk, sequences, vectors, and XML.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Clojure: The Essential Reference. The section links point to the parts of the book it draws on.