Clojure异常处理

3

我在使用 clojure.data.xml 时遇到了一些问题,当解析不规范的 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
    (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))))

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

输出

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

你为什么要尝试两次捕获异常?而且,如果只有一个表达式,(do)块是不必要的。 - Leon Grapenthin
修改后的输入/输出:两个catch的原因是为了展示我发现的可能解决方案。 - ChadJPetersen
1个回答

2

我认为你遇到的问题与parse返回值的惰性有关。根据它的文档字符串,它解析源码(可以是InputStream或Reader)并返回一个懒加载的Element记录树。[...]"

(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

编辑

parse返回的值是一个惰性树,从Element记录自上而下构建,并基于Event对象的惰性序列,正如event-tree函数的docstring中所提到的那样。惰性体现在记录的:content字段中,当访问该字段时才会实现。我发现强制实现整个树的一种方法是使用str函数,这感觉很笨拙且难看,但任何有更好想法的人都可以提供更好的解决方案。

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

这似乎是在极力避免懒惰,而使用 clojure.data.xml 的主要原因之一。既然您似乎想要一次解析整个 XML 字符串,那么 clojure.xml/parse 函数可能更适合您的需求。
(defn my-parse-str
  [s]
  (try
    (xml/parse (java.io.ByteArrayInputStream. (.getBytes s)))
    (catch Exception e false)))

在这种情况下,他应该用doall替换他的do。 - Leon Grapenthin
使用doall后,我得到了以下输出:XMLStreamException ParseError at [row,col]:[1,84] Message: 元素类型“foo”的结束标记必须以“>”分隔符结尾。com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.next (XMLStreamReaderImpl.java:598) #clojure.data.xml.Element {:tag :foo,:attrs {},:content(user => - ChadJPetersen
1
@user1944838 我尝试使用doall,但它不起作用,parse返回的数据结构不是一个简单的惰性序列。 - juan.facorro
但它是一棵懒惰树。 - ChadJPetersen
@ChadJPetersen 刚刚编辑了答案,提供了一种可能的解决方法和一些注释。 - juan.facorro
@juan.facorro,当字符串正确时,它仍然有效。但是它无法捕捉到针对格式不正确的XML字符串的异常。 - ChadJPetersen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接