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 <[email protected]> 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 [email protected]
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> [email protected]<clojure%[email protected]>
> 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 [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en