Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get nested nodes using xml-> in clojure.data.zip?

I'm finding the usage of xml-> extremely confusing. I've read the docs and the examples but can't figure out how to get the nested nodes of an xml doc.

Assume the following xml is in a zipper (as from xml-zip):

<html>
 <body>
  <div class='one'>
    <div class='two'></div>
  </div>
 </body>
</html>

I am trying to return the div with class='two'.

I was expecting this to work:

(xml-> z :html :body :div :div)

Or this:

(xml-> z :html :body :div (attr= :class "two"))

Kind of like css selectors.

But it returns only the first level, and it doesn't search down through the tree.

The only way I can make it work is:

(xml-> z :html :body :div children leftmost?)

Is that what I'm supposed to do?

The whole reason I started using xml-> was for convenience and to avoid navigating the zipper up and down and left and right. If xml-> can not get nested nodes then I don't see the value over clojure.zip.

Thanks.

like image 838
Scott Klarenbach Avatar asked Jun 06 '26 11:06

Scott Klarenbach


1 Answers

Two consequitive :div match the same node. You should have come down. And I believe you've forgotten to get the node with zip/node.

(ns reagenttest.sample
    (:require 
              [clojure.zip :as zip]
              [clojure.data.zip.xml :as data-zip]))
(let [s "..."
      doc (xml/parse (java.io.ByteArrayInputStream. (.getBytes s)))]
(prn (data-zip/xml-> (zip/xml-zip doc) :html :body :div zip/down (data-zip/attr= :class "two") zip/node)))

or you could use custom-made abstraction if you are not happy with xml->:

(defn xml->find [loc & path]
    (let [new-path (conj (vec (butlast (interleave path (repeat zip/down)))) zip/node)]
        (apply (partial data-zip/xml-> loc) new-path)))

Now you can do this:

(xml->find z :html :body :div :div)
(xml->find z :html :body :div (data-zip/attr= :class "two"))
like image 55
akond Avatar answered Jun 08 '26 02:06

akond



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!