2017-04-03 4 views
3

구문 분석이 완료되기 전에 스트림이 닫히기 때문에 clojure.data.xml으로 XML 파일을 구문 분석하는 예외가 발생합니다. 이해가 안 무엇Clojure XML 스트림 폐쇄 된 예외

은 (this related answer에 의해 제안) with-open가 닫을 전에 doall는 XML 데이터의 평가를 강제되지 않는 이유입니다 :

(file->xml "example.xml") 
;-> XMLStreamException ParseError at [row,col]:[80,1926] 
Message: Stream closed com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.next 
: 예외를 throw

(:require [clojure.java.io :as io] 
      [clojure.data.xml :as xml]) 

(defn file->xml [path] 
    (with-open [rdr (-> path io/resource io/reader)] 
    (doall (xml/parse rdr)))) 

with-open 래퍼를 제거하면 예상대로 XML 데이터가 반환됩니다 (따라서 판독기가 닫혀 있지는 않지만 파일은 유효합니다). 그래서 아마 그이 관련되어

(defn parse 
    "Parses the source, which can be an 
    InputStream or Reader, and returns a lazy tree of Element records. 
    Accepts key pairs with XMLInputFactory options, see http://docs.oracle.com/javase/6/docs/api/javax/xml/stream/XMLInputFactory.html 
    and xml-input-factory-props for more information. 
    Defaults coalescing true." 
    [source & opts] 
    (event-tree (event-seq source opts))) 

,하지만 내가 가지고있는 기능은 clojure.data.xml README의 "왕복"예를 매우 유사합니다 :

나는 (source xml/parse) 게으른 결과를 얻을 수 있음을 참조하십시오.

무엇이 여기에 있습니까?

답변

3

나는이 동작을보고 놀랐다. clojure.data.xml.Element (반환 유형)은 doall의 영향을받지 않는 "지연지도"유형을 구현합니다.

(ns tst.clj.core 
    (:use clj.core clojure.test tupelo.test) 
    (:require 
    [tupelo.core :as t] 
    [clojure.string :as str] 
    [clojure.pprint :refer [pprint]] 
    [clojure.java.io :as io] 
    [clojure.data.xml :as xml] 
    [clojure.walk :refer [postwalk]] 
)) 
(t/refer-tupelo) 

(defn unlazy 
    [coll] 
    (let [unlazy-item (fn [item] 
         (cond 
         (sequential? item) (vec item) 
         (map? item) (into {} item) 
         :else item)) 
     result (postwalk unlazy-item coll) ] 
    result)) 

(defn file->xml [path] 
    (with-open [rdr (-> path io/resource io/reader) ] 
    (let [lazy-vals (xml/parse rdr) 
      eager-vals (unlazy lazy-vals) ] 
     eager-vals))) 
(pprint (file->xml "books.xml")) 

{:tag :catalog, 
:attrs {}, 
:content 
[{:tag :book, 
    :attrs {:id "bk101"}, 
    :content 
    [{:tag :author, :attrs {}, :content ["Gambardella, Matthew"]} 
    {:tag :title, :attrs {}, :content ["XML Developer's Guide"]} 
    {:tag :genre, :attrs {}, :content ["Computer"]} 
    {:tag :price, :attrs {}, :content ["44.95"]} 
    {:tag :publish_date, :attrs {}, :content ["2000-10-01"]} 
    {:tag :description, 
    :attrs {}, 
    :content 
    ["An in-depth look at creating applications\n  with XML."]}]} 
    {:tag :book, 
    :attrs {:id "bk102"}, 
    :content 
    [{:tag :author, :attrs {}, :content ["Ralls, Kim"]} 
    {:tag :title, :attrs {}, :content ["Midnight Rain"]} 
    {:tag :genre, :attrs {}, :content ["Fantasy"]} 
    {:tag :price, :attrs {}, :content ["5.95"]} 
    {:tag :publish_date, :attrs {}, :content ["2000-12-16"]} 
    {:tag :description, 
    :attrs {}, 
    :content 
    ["A former architect battles corporate zombies,\n  an evil sorceress, and her own childhood to become queen\n  of the world."]}]} 
    {:tag :book, 
    :attrs {:id "bk103"}, 
    :content ..... 

clojure.data.xml.Element 이후 구현 clojure.lang.IPersistentMap 사실 (map? item) 복귀하여 다음은

는 노멀 맵에 지연 값을 변환하는 솔루션이다.

clojure.data.xmlclojure.xml 있음을 다른 : 여기

참고하십시오 sample data for books.xml

입니다. 자신의 필요에 가장 잘 맞는 라이브러리를 찾으려면 두 라이브러리를 모두 탐색해야합니다. 필요할 때

또한 API 문서를 찾을 수 crossclj.info를 사용할 수 있습니다

업데이트 :

그냥 일주일 그래서 난 그냥 unlazy 기능을 필요로 이와 같은 XML 파싱 문제로 실행이 질문을 본 후에. 이제 unlazyin the Tupelo library을 (를) 찾을 수 있습니다.

+0

흠. 흥미 롭 군. 무슨 일이 일어나는지 명확히 할 시간을내어 주셔서 감사합니다. – nrako

+0

나는 이것을 "면역"이라고 부르지 않을 것이다. 마치 게으른 시퀀스의 게으른 시퀀스 인 게으른 것들의 또 다른 _level_ 인 것처럼 보입니다. – Svante

+0

소스 코드를 파고 들지는 않았지만, "datomic.query.EntityMap"과 함께 보이는 "게으른 맵"유형의 구조 인 것처럼 보입니다. 문제는''doall''은''게으른 맵 ''이 아닌''게으른 시퀀스 ''만을위한 것이라고 생각합니다. –