简体   繁体   中英

How can I filter only some values from my nested XML in clojure?

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.

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})
  )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM