Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clojure namespace aware xml parser / zipper

Tags:

soap

xml

clojure

Does anyone know of a namespace aware xml parser / zipper?

Rather than having to pull in a whole bunch of axis or similar libs, I was hoping to parse the following:

(ns foo
  (:require [clojure.zip :as zip]
            [clojure.xml :as xml])
  (:use clojure.data.zip.xml))

(def xml "<soap:Envelope xmlns=\"urn:WEBSERVICE-URN\"
                         xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"
                         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">
            <soap:Body>
              <loginResponse>
                 <result>           
                    <sessionKey>SESSION-KEY-HERE</sessionKey>
                 </result>
              </loginResponse>
            </soap:Body>
           </soap:Envelope>")

(def root 
  (zip/xml-zip 
    (xml/parse 
      (java.io.ByteArrayInputStream. (.getBytes xml "UTF-8")))))

(def key (xml1-> root ???? ???? :loginResponse :result :sessionKey text))

I can't seem to navigate the xml elements that have XML namespaces?

like image 667
toolkit Avatar asked Nov 26 '25 06:11

toolkit


1 Answers

I think your problem here might be your use of xml1-> and not the namespaces in the XML. The tag= predicate in the XML zip namespace (which is implied when using keywords with xml1->) defaults to auto-descent mode, meaning that it descends to the children of the current node before trying to match element tags. Since the root element is already a soap:Envelope, you don't need to include that filter in the list with xml1->. The following should give you what you're looking for:

(xml1-> root :soap:Body :loginResponse :result :sessionKey text)

Note that element qnames are used in their unexpanded form as tag names in clojure.xml, and it's perfectly fine to have a keyword whose name contains a colon.

Alternatively, you could say:

(require '[clojure.data.zip :as zf])
(xml1-> (zf/auto false root)
        :soap:Envelope :soap:Body :loginResponse :result :sessionKey text)

If you still require a namespace-aware XML parser, there's one in data.xml, though it simply discards namespace declarations and uses local names only:

(require '[clojure.data.xml :as data-xml])
(def root (-> (java.io.StringReader. xml) data-xml/parse zip/xml-zip)
(xml1-> root :Body :loginResponse :result :sessionKey text)
like image 122
Alex Avatar answered Nov 28 '25 23:11

Alex



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!