Hi Peter, The library clojure.contrib.zip-filter is pretty good at this sort of thing. For example:
(require '[clojure.xml :as xml]) (require '[clojure.contrib.zip-filter.xml :as zx]) (require '[clojure.zip :as zip]) (defn get-mods-for-iva "Returns the <mods> node if one exists under a <version> node whose inner-ver-attrib matches test-iva. Otherwise, returns nil." [x-zip test-iva] (zx/xml1-> x-zip (zx/tag= :version) (zx/attr= :inner-ver-attrib test-iva) (zx/tag= :type) (zx/tag= :mods))) (defn get-replacement-values "Returns a seq of <mods> nodes if available in x-file for versions 1.4 and 1.6 respectively." [x-file] (let [x-zip (zip/xml-zip (xml/parse x-file)) test-ivas ["1.4" "1.6"]] (map (partial get-mods-for-iva x-zip) test-ivas))) ``clojure.contrib.zip-filter.xml/xml1->'' filters an xml-zip tree using predicates on tags, attributes or text values of nodes. You can chain predicates together (like in ``clojure.core/->'') to navigate trees conditionally. If a predicate returns false or nil, the whole form returns nil, so you know there is no complete match. In the ``get-mods-for-iva'' function above, we start with the complete tree ``x-zip'', and filter for <version>, then <version inner-ver-attrib=test-iva>, then <type>, and finally <mods>. In ``get-replacement-values'', we parse the XML file and derive an xml-zip tree from it. We then call ``get-mods-for-iva'' for each of the pre-defined versions, and return a seq of their results. This may not be the best solution, and I may have misinterpreted your exact XML structure, but the code shows a simple, functional style. We try to avoid do* forms and side effects (printing during calculation) where possible, collecting results of function calls instead. I hope it helps! On Wed, Sep 1, 2010 at 7:10 AM, Peter <buckmeist...@gmail.com> wrote: > Hi- > > I'm brand new to Clojure and FP, reading a bunch and working on my > first programming task (reading in values from an xml file and a text > file and then creating a new text file with some lines/sections of the > original text file replaced based on the content of the xml). > > I found some helpful info here: > http://www.chrisumbel.com/article/clojure_xml_parsing_xml-seq > on reading the xml file, but I'm a couple more levels deep than that > article. I don't know much about Clojure yet, but I have a feeling I'm > not doing it the right/idiomatic/best way. I've basically got three > nested calls to doseq, and I think it is mostly due to my own > unfamiliarity with Clojure and the better options I would have to do > this in FP. > > I'm getting the ver tag in the xml then checking one of its attribs to > make sure I'm pulling from the version I want, and then I get the > content of the mods tag. I've tried to somewhat simplify this case so > the following isn't tested after being extracted from my sandbox. > > TIA! > > (defn- dig-through-struct > "Hides a pair of nested doseq calls from my main function" > [xml-as-struct] > (doseq [y (:content xml-as-struct) > :when (= :type (:tag y))] > (doseq [z (:content y) > :when (= :mods (:tag z))] > (println "The content I want" (:content z))))) > > (defn- get-replacement-values > "Pulls from xml values we want to replace/update/add" > [x-file] > (let [xml-file (File. x-file)] > (xml-seq (parse xml-file)) > (for [testing-ver `("1.4" "1.6")] > (doseq [x (xml-seq (parse xml-file)) > :when (= :ver (:tag x))] > (let [iva (:inner-ver-attrib (:attrs x))] > (if (= testing-ver iva) > (dig-through-struct x testing-ver iva) > (println "Did not match the ver we want" testing-ver iva))))))) > > And this is my xml: > > <proj > bunch of attribs > ...> > > <ver > inner-ver-attrib=1.4 (or 1.6 etc, this is a tag I'm interested in > conditionally checking) > bunch of attribs > ...> > > <type > bunch of attribs > ...> > > <mods> > <remove> > <entry-name>files</entry-name> > <entry>path_old\foo_old.c</entry> > <entry>path_old1\foo_old.h</entry> > </remove> > <add> > <entry-name>files</entry-name> > <entry>path\foo.c</entry> > <entry>path1\foo.h</entry> > </add> > <change> > <entry-name>opts</entry-name> > <from>-bar=1</from> > <to>-bar=2</to> > </change> > </mods> > </type></version</project> > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com<clojure%2bunsubscr...@googlegroups.com> > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en -- Abhishek Reddy http://abhishek.geek.nz -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en