0

I have some code, that parses out soap data with the use of zippers. When I format it like so it works as expected for me

(defn parse-data
 [raw-data]
 (let [soap-data (:body raw-data)
        soap-envelope (zip/xml-zip
                    (xml/parse
                      (java.io.ByteArrayInputStream. (.getBytes (str soap-data) "UTF-8"))))]
      (pprint (xml-z/xml-> soap-envelope :soap:Envelope :soap:Body :Tag1 :Tag2))))

It prints out the expected result. But when I move the XML parsing to the let statement it fails to compile, with the following error (I've triple checked my brackets match up)

RuntimeException EOF while reading, starting at line 3  clojure.lang.Util.runtimeException (Util.java:221)
jcode.oc-drift.aquisition=>       (pprint result-data)))

CompilerException java.lang.RuntimeException: Unable to resolve symbol: result-data in this context, compiling:(/tmp/form-init6714472131112461091.clj:1:1) 
RuntimeException Unmatched delimiter: )  clojure.lang.Util.runtimeException (Util.java:221)

RuntimeException Unmatched delimiter: )  clojure.lang.Util.runtimeException (Util.java:221)
jcode.oc-drift.aquisition=> 

The code was changed to put the xml-z/xml-> call into the let statement, as follows

(defn parse-data
 [raw-data]
 (let [soap-data (:body raw-data)
        soap-envelope (zip/xml-zip
                    (xml/parse
                      (java.io.ByteArrayInputStream. (.getBytes (str soap-data) "UTF-8"))))
        result-data (xml-z/xml-> soap-envelope :soap:Envelope :soap:Body :GetNextTripsForStopResponse :GetNextTripsForStopResult)]
      (pprint result-data)))

Is this a bug with the let form, or am I missing something about the behaviour of xml-> functionality?

The full code file with the non-working function call:

src/hello/core.clj:

(ns hello.core
 (:require [clj-http.client :as http-client]
            [clojure.zip :as zip]
            [clojure.xml :as xml]
            [clojure.data.xml :as xml-data]
            [clojure.data.zip.xml :as xml-z]))

(use 'clojure.pprint)

(def app-id "redacted")
(def api-key "redacted")
(def post-data {:apiKey api-key :appID app-id})

(defn get-data
 [post-data function]
 "function is a string with the api function to be called"
  (let [url (str "redacted" function)]
   (http-client/post url {:form-params post-data})))

(defn parse-data
 [raw-data]
 (let [soap-data (:body raw-data)
        soap-envelope (zip/xml-zip
                    (xml/parse
                      (java.io.ByteArrayInputStream. (.getBytes (str soap-data) "UTF-8"))))
        result-data (xml-z/xml-> soap-envelope :soap:Envelope :soap:Body :GetNextTripsForStopResponse :GetNextTripsForStopResult)]
      (pprint result-data)))

project.clj:

(defproject hello "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :main hello.core
  :dependencies [[org.clojure/clojure "1.7.0"]                 
                 [org.clojure/data.xml "0.0.8"]
                 [org.clojure/data.zip "0.1.2"]
                 [clj-http "2.2.0"]])
Arthur Ulfeldt
  • 90,827
  • 27
  • 201
  • 284
  • Where is `xml-z/xml->` from? – Alan Thompson Aug 16 '16 at 21:21
  • *nod* -- I was just about to request a `ns` header and any other edits necessary to make this a [MCVE](http://stackoverflow.com/help/mcve) / [SSCCE](http://sscce.org/). – Charles Duffy Aug 16 '16 at 21:21
  • To be clear -- for an ideal MCVE, code should be complete enough that someone else can start a REPL, paste directly from your problem, and see the same exception with no other effort/preparation needed. Library dependencies can make this ideal a little hard to reach, but [lein-try](https://github.com/rkneufeld/lein-try) and similar bring it closer to reason. – Charles Duffy Aug 16 '16 at 22:02
  • 1
    @CharlesDuffy [Boot](http://boot-clj.com/) makes [that sort of thing](https://github.com/zk/clojuredocs/issues/144#issue-171085909) trivial. – Sam Estep Aug 16 '16 at 22:12
  • 1
    I added a project.clj with the dependencies as well, though I still can't make it fail. – Arthur Ulfeldt Aug 16 '16 at 22:26
  • You will still need to add your sample data and explicit function calls. – Alan Thompson Aug 16 '16 at 22:32
  • @AlanThompson it's not a question though of does this code logically work, it's a question of why it won't compile when I place result-data in the let statement, but if the logic of the result-data binding is outside of the let statement it will compile. So no functions are being called, so I'm not sure of the relevance of the sample data. – Jacob Rahme Aug 16 '16 at 22:42
  • 1
    @JacobRahme, ...if you create a project with the base project.clj given, and the single namespace given (both copied/pasted from the question, not from your own code), *can you make it fail*? – Charles Duffy Aug 16 '16 at 22:43
  • ...all I can get is some reflection warnings from `lein check` -- not a compile-time failure in sight. – Charles Duffy Aug 16 '16 at 22:46

2 Answers2

1

the code you pasted is correct, and does not have the problem pasted in that stacktrace.

specifically the error shows Unable to resolve symbol: result-data and from the line above that it looks like it closed the expression before it got to the line with

 (pprint result-data)))

This sounds like a case where there is a syntax error higher in the buffer. For instance if higher up in the program there was an unbalanced [ or ( .

because the extra opening paren would match this one and end the expression early. The two errors after that add evidence to this leading me to think that it's interpreting the `(pprint result-data)))`` as the start of a new expression with two extra parens on the end.

try:

  • clear the buffer (in cider press , then type clear) and try it again.
  • try restarting nrepl (in cider press , then typre restart) and try again.

running your code works correct both when run in a repl and when evaluated from a file (these are exactly the same opperation)

hello.core> (defn parse-data
              [raw-data]
              (let [soap-data (:body raw-data)
                    soap-envelope (zip/xml-zip
                                   (xml/parse
                                    (java.io.ByteArrayInputStream. (.getBytes (str soap-data) "UTF-8"))))]
                (pprint (xml-z/xml-> soap-envelope :soap:Envelope :soap:Body :Tag1 :Tag2))))
#'hello.core/parse-data
hello.core> (defn parse-data
              [raw-data]
              (let [soap-data (:body raw-data)
                    soap-envelope (zip/xml-zip
                                   (xml/parse
                                    (java.io.ByteArrayInputStream. (.getBytes (str soap-data) "UTF-8"))))
                    result-data (xml-z/xml-> soap-envelope :soap:Envelope :soap:Body :GetNextTripsForStopResponse :GetNextTripsForStopResult)]
                (pprint result-data)))
#'hello.core/parse-data

so this really looks like an environment problem. Here are some more things to check:

  • the repl is in the correct namespace
  • no extra characters are being added or changed in the cut-and-paste process
  • paredit-mode is not auto-closing expressions as they are pasted in.
  • no "smart quotes" have been inserted by clipboard managers.
  • the code works if you run lean repl and paste the lines in
  • lein check loads the file without complaints (other than reflection warnings)
Sam Estep
  • 12,974
  • 2
  • 37
  • 75
Arthur Ulfeldt
  • 90,827
  • 27
  • 201
  • 284
  • I cleared out the repl (I'm not using Emacs, so I simply killed my existing lein repl, and did lein do clean, repl then pasted in the code with both the working and non working parse-data function, and got the same result. I've updated the question with the full name space – Jacob Rahme Aug 16 '16 at 22:03
  • I double checked the name space and it is correct. I cannot find any extra characters that differ in the copy and past (as well the code snippet without the xml-z/xml-> call in the let works) I'm not using emacs so no paraedit-mode No smart quotes are added in when reviewed in the repl lein check gives me a success (aside from the reflection warnings) and the non let code works in a repl when pasted, but the code with the call in a let does not. – Jacob Rahme Aug 16 '16 at 22:56
  • Perhaps doing the same, though starting from a completely blank project and only include code copied from this question you will then find a difference between the working version from this question and the non-working one in your project. This is a rather tedious approach, though it has a good chance of finding the problem. – Arthur Ulfeldt Aug 16 '16 at 23:00
1

The code you pasted is working for me. I think the problem must be related to the repl you are using, the editor/repl combo, or something else. Create a new project and paste in the following:

> lein new app hello

Then edit the 2 files:

project.clj

(defproject hello 
  "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :main hello.core
  :dependencies [[org.clojure/clojure "1.7.0"]                 
                 [org.clojure/data.xml "0.0.8"]
                 [org.clojure/data.zip "0.1.2"]
                 [clj-http "2.2.0"]] )

src/hello/core.clj

(ns hello.core
  (:require [clj-http.client :as http-client]
            [clojure.zip :as zip]
            [clojure.xml :as xml]
            [clojure.data.xml :as xml-data]
            [clojure.data.zip.xml :as xml-z]))

(use 'clojure.pprint)

(def app-id "redacted")
(def api-key "redacted")
(def post-data {:apiKey api-key :appID app-id})

(defn get-data
 [post-data function]
 "function is a string with the api function to be called"
  (let [url (str "redacted" function)]
   (http-client/post url {:form-params post-data})))

(defn parse-data
 [raw-data]
 (let [soap-data (:body raw-data)
        soap-envelope (zip/xml-zip
                    (xml/parse
                      (java.io.ByteArrayInputStream. (.getBytes (str soap-data) "UTF-8"))))
        result-data (xml-z/xml-> soap-envelope :soap:Envelope :soap:Body :GetNextTripsForStopResponse :GetNextTripsForStopResult)]
      (pprint result-data)))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (println "Hello, World!"))

Then run it from the command line

> lein run    
Hello, World!

No compiler errors (of course, without test data, we didn't actually call any of your functions, either).

It looks like the problem is somewhere in your environment. If you clean everything out and start fresh in a new project you should see the same results.

Alan Thompson
  • 29,276
  • 6
  • 41
  • 48