Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure exception handling

I'm having some issues with clojure.data.xml in that when parsing bad XML, the exception thrown is not caught. I've found some issues perhaps with run-time wrappers, but my attempts to unwrap it have been unsuccessful can anyone point out to me why this may be happening?

(defn parse-xml-from-string
  "takes in valid xml as a string and turns it into 
   #clojure.data.xml data, if bad xml returns false"
  [xml]
  (try
    (do (parse (java.io.StringReader. xml)))
    (catch javax.xml.stream.XMLStreamException e false)
    (catch Exception ex
      (cond (isa? (class (.getCause ex)) javax.xml.stream.XMLStreamException) false))))

method call

(viva-api.helpers.validation/parse-xml-from-string "<?xml version=\"1.0\"encoding=\"UTF-8\"?><foo><bar><baz>The baz value</baz></bar></foos>")

output

#clojure.data.xml.Element{:tag :foo, :attrs {}, :content (user=> XMLStreamException  ParseError at [row,col]:[1,84]
Message: The end-tag for element type "foo" must end with a '>' delimiter.  com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.next (XMLStreamReaderImpl.java:598)
like image 384
ChadJPetersen Avatar asked Sep 03 '25 09:09

ChadJPetersen


1 Answers

I think the problem you are seeing is related to the laziness of the value returned by parse. According to its docstring "Parses the source, which can be an InputStream or Reader, and returns a lazy tree of Element records. [...]".

(ns xml
  (:use clojure.data.xml))

(defn parse-xml-from-string
  "takes in valid xml as a string and turns it into 
   #clojure.data.xml data, if bad xml returns false"
  [xml]
  (try
    (parse (java.io.StringReader. xml))
    (catch javax.xml.stream.XMLStreamException ex
      false)))

(parse-xml-from-string "<bla/>") ;= #clojure.data.xml.Element{:tag :bla, :attrs {}, :content ()}

(parse-xml-from-string "<bla") ;= false

(parse-xml-from-string "<bla>") ; throws XMLStreamException

(def x (parse-xml-from-string "<bla>")) ; doesn't throw an exception unless it's evaluated

x ; throws XMLStreamException

EDIT

The value returned from parse is a lazy tree built top-down from an Element record and based on a lazy sequence of Event objects, as mentioned in the docstring for the event-tree function. The laziness lies in the :content field of the record which is realized when the field is accessed. One way I've found to force the realization of the whole tree is using the str function, this feels hacky and looks ugly but anyone who has a better idea can provide a better solution.

(defn parse-xml-from-string
  "takes in valid xml as a string and turns it into 
   #clojure.data.xml data, if bad xml returns false"
  [xml]
  (try
    (let [x (parse-str xml)]
      (str x)
      x)
    (catch javax.xml.stream.XMLStreamException ex
      false)))

This seems like going to great lengths to avoid laziness which is, as I understand it, one of the main reasons to use clojure.data.xml. Since you seem to want your whole XML string parsed at once maybe the clojure.xml/parse function is better suited for your needs.

(defn my-parse-str
  [s]
  (try
    (xml/parse (java.io.ByteArrayInputStream. (.getBytes s)))
    (catch Exception e false)))
like image 145
juan.facorro Avatar answered Sep 05 '25 01:09

juan.facorro