Reputation: 171
I have input XML which I have converted to clojure-map and can see all the values in one clojure map like this
But how can I filter certain values(mnAmountReceived) out of nested detail_D1 tags XML structure.
My XML is something like this, truncated for brevity:
<svResponse category="EVENT" environment="ENV910" pwd="asdfas"
responseCreator="XAPI" role="ALL" session="7370710" token="asdfasf"
type="realTimeEvent" user="sv"
xmlns:rte="http://www.schemas.e1.oracle.com">
<event>
<header>
<eventVersion>1.0</eventVersion>
<type>EVENTOUT</type>
<user>sv</user>
<role>*ALL</role>
</header>
<body elementCount="3">
<detail_D1>
<szNextStatus>999</szNextStatus>
<mnOrderLineNumber>1.000</mnOrderLineNumber>
<mnAmountReceived>100</mnAmountReceived>
</detail_D1>
<detail_D1>
<szNextStatus>999</szNextStatus>
<mnOrderLineNumber>2.000</mnOrderLineNumber>
<mnAmountReceived>200</mnAmountReceived>
</detail_D1>
<detail_D1>
<szNextStatus>999</szNextStatus>
<mnOrderLineNumber>3.000</mnOrderLineNumber>
<mnAmountReceived>300</mnAmountReceived>
</detail_D1>
</body>
</event>
</svResponse>
For eg: I want to filter mnAmountReceived and assign them to separate keys based on what the mnOrderLineNumber is under the tag.
I am getting an xml which I convert to clojure map using the below functions
(xml/parse-str xml-str))
(defn clojurify-xml-map
[clj-xml]
(->> clj-xml
get-body
(map xml->map)
group-and-flattened-source-data))
I am trying to filter out the mnOrderLineNumber using the value 1.0 for eg so that I can get it's corresponding mnAmountReceived value
(defn filter-price-line [coll]
(filter #(#{1.0} (-> % :mnOrderLineNumber read-string)) coll)
)
I want to filter out mnAmountReceived and know with which mnOrderLineNumber it comes along with so that I can map it out in my response to proper fields for downstream systems.
Upvotes: 3
Views: 739
Reputation: 98
It seems that you want to parse the XML and be able to treat each detail_D1
as a map so that you can have line number and amount received together. If that is the case one approach might be to use zippers to parse the data to Clojure data structures and then filter
. Here is an example:
(ns so
(:require [clojure.data.xml :as x]
[clojure.data.zip.xml :as z]
[clojure.zip :as zip]
[clojure.java.io :as io]))
(defn parse
[file]
(letfn [(parse-detail [z]
{:next-status (Integer/parseInt (z/xml1-> z :szNextStatus z/text))
:line-number (Double/parseDouble (z/xml1-> z :mnOrderLineNumber z/text))
:amount-received (Integer/parseInt (z/xml1-> z :mnAmountReceived z/text))})]
(with-open [r (io/reader file)]
(let [zipper (->> r x/parse zip/xml-zip)]
(z/xml-> zipper :svResponse :event :body :detail_D1 parse-detail)))))
(comment
(parse "input.xml") =>
({:next-status 999 :line-number 1.0 :amount-received 100}
{:next-status 999 :line-number 2.0 :amount-received 200}
{:next-status 999 :line-number 3.0 :amount-received 300})
(filter (comp #{1.0} :line-number) (parse "input.xml")) =>
({:next-status 999 :line-number 1.0 :amount-received 100})
)
Upvotes: 5