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

Reply via email to