莊周夢蝶

          生活、程序、未來
             :: 首頁 ::  ::  :: 聚合  :: 管理

          Clojure世界:XML處理

          Posted on 2012-02-18 12:21 dennis 閱讀(4874) 評論(0)  編輯  收藏 所屬分類: Clojure
              XML處理也是個常見的編程工作,雖然說在Clojure里你很少使用XML做配置文件,但是跟遺留系統(tǒng)集成或者處理和其他系統(tǒng)通訊,可能都需要處理XML。

              Clojure的標準庫clojure.xml就是用來干這個事情的。一個簡單的例子如下,首先我們要解析的是下面這個簡單的XML:
          <?xml version="1.0" encoding="UTF-8"?>
          <books>
            
          <book>
              
          <title>The joy of clojure</title>
              
          <author>Michael Fogus / Chris House</author>
            
          </book>
            
          <book>
              
          <title>Programming clojure</title>
              
          <author>Stuart Halloway</author>
            
          </book>
            
          <book>
              
          <title>Practical clojure</title>
              
          <author>Luke Van der Hart</author>
            
          </book>
          </books>

              解析xml用clojure.xml/parse方法即可,該方法返回一個clojure.xml/element這個struct-map組成的一棵樹:
          user=> (use '[clojure.xml])
          nil
          user
          => (parse "test.xml")
          {:tag :books, :attrs nil, :content
           [{:tag :book, :attrs nil, :content [{:tag :title, :attrs nil, :content [
          "The joy of clojure"]} {:tag :author, :attrs nil, :content ["Michael Fogus / Chris House"]}]}
           {:tag :book, :attrs nil, :content [{:tag :title, :attrs nil, :content [
          "Programming clojure"]} {:tag :author, :attrs nil, :content ["Stuart Halloway"]}]}
           {:tag :book, :attrs nil, :content [{:tag :title, :attrs nil, :content [
          "Practical clojure"]} {:tag :author, :attrs nil, :content ["Luke Van der Hart"]}]}]}

          這是一個嵌套的數(shù)據(jù)結(jié)構(gòu),每個節(jié)點都是clojure.xml/element結(jié)構(gòu),element包括:
          (defstruct element :tag :attrs :content)
             tag、attrs和content屬性,tag就是該節(jié)點的標簽,attrs是一個屬性的map,而content是它的內(nèi)容或者子節(jié)點。element是一個struct map,它也定義了三個方法來分別獲取這三個屬性:
          user=> (def x (parse "test.xml"))
          #'user/x
          user=> (tag x)
          :books
          user
          => (attrs x)
          nil
          user
          => (content x)
          [{:tag :book, :attrs nil, :content [{:tag :title, :attrs nil, :content [
          "The joy of clojure"]} {:tag :author, :attrs nil, :content ["Michael Fogus / Chris House"]}]}
          {:tag :book, :attrs nil, :content [{:tag :title, :attrs nil, :content [
          "Programming clojure"]} {:tag :author, :attrs nil, :content ["Stuart Halloway"]}]}
          {:tag :book, :attrs nil, :content [{:tag :title, :attrs nil, :content [
          "Practical clojure"]} {:tag :author, :attrs nil, :content ["Luke Van der Hart"]}]}]
             books節(jié)點是root node,它的content就是三個book子節(jié)點,子節(jié)點組織成一個vector,我們可以隨意操作:
          user=> (tag (first (content x)))
          :book
          user
          => (content (first (content x)))
          [{:tag :title, :attrs nil, :content [
          "The joy of clojure"]} {:tag :author, :attrs nil, :content ["Michael Fogus / Chris House"]}]
          user
          => (content (first (content (first (content x)))))
          [
          "The joy of clojure"]

               額外提下,clojure.xml是利用SAX API做解析的。同樣它還有個方法,可以將解析出來的結(jié)構(gòu)還原成xml,通過emit:
          user=> (emit x)

          <?xml version='1.0' encoding='UTF-8'?>
          <books>
          <book>
          <title>
          The joy of clojure
          </title>
          <author>
          Michael Fogus / Chris House
          </author>
          </book>
          <book>

               如果你要按照深度優(yōu)先的順序遍歷xml,可以利用xml-seq將解析出來的樹構(gòu)成一個按照深度優(yōu)先順序排列節(jié)點的LazySeq,接下來就可以按照seq的方式處理,比如利用for來過濾節(jié)點:
          user=> (for [node (xml-seq x)
                            :when (= :author (:tag node))]
                      (first (:content node)))
          ("Michael Fogus / Chris House" "Stuart Halloway" "Luke Van der Hart")

              通過:when指定了條件,要求節(jié)點的tag是author,這樣就可以查找出所有的author節(jié)點的content,是不是很方便?就像寫英語描述一樣。

              更進一步,如果你想操作parse解析出來的這棵樹,你還可以利用clojure.zip這個標準庫,它有xml-zip函數(shù)將xml轉(zhuǎn)換成zipper結(jié)構(gòu),并提供一系列方法來操作這棵樹:
          user=>(def xz (xml-zip x))
          #'user/xz
          user=> (node (down xz))
          {:tag :book, :attrs nil, :content [{:tag :title, :attrs nil, :content [
          "The joy of clojure"]} {:tag :author, :attrs nil, :content ["Michael Fogus / Chris House"]}]}
          user
          => (-> xz down right node)
          {:tag :book, :attrs nil, :content [{:tag :title, :attrs nil, :content [
          "Programming clojure"]} {:tag :author, :attrs nil, :content ["Stuart Halloway"]}]}
          user
          => (-> xz down right right node)
          {:tag :book, :attrs nil, :content [{:tag :title, :attrs nil, :content [
          "Practical clojure"]} {:tag :author, :attrs nil, :content ["Luke Van der Hart"]}]}
          user
          => (-> xz down right right lefts)
          ({:tag :book, :attrs nil, :content [{:tag :title, :attrs nil, :content [
          "The joy of clojure"]} {:tag :author, :attrs nil, :content ["Michael Fogus / Chris House"]}]}
           {:tag :book, :attrs nil, :content [{:tag :title, :attrs nil, :content [
          "Programming clojure"]} {:tag :author, :attrs nil, :content ["Stuart Halloway"]}]})

            是不是酷得一塌糊涂?可以通過up,down,left,right,lefts,rights,來查找節(jié)點的鄰近節(jié)點,可以通過node來得到節(jié)點本身。一切顯得那么自然。更進一步,你還可以“編輯“這棵樹,比如刪除The joy of clojure這本書:
          user=>  (def loc-in-new-tree (remove (down xz)))
          #'user/loc-in-new-tree
          user=> (root loc-in-new-tree)
          {:tag :books, :attrs nil, :content
          [{:tag :book, :attrs nil, :content [{:tag :title, :attrs nil, :content [
          "Programming clojure"]} {:tag :author, :attrs nil, :content ["Stuart Halloway"]}]}
          {:tag :book, :attrs nil, :content [{:tag :title, :attrs nil, :content [
          "Practical clojure"]} {:tag :author, :attrs nil, :content ["Luke Van der Hart"]}]}]}

             ok,只剩下兩本書了,更多方法還包括replace做替換,edit更改節(jié)點等。因此編輯XML并重新生成,你一般可以利用clojure.zip來更改樹,最后利用clojure.xml/emit將更改還原為xml。

              生成xml除了emit方法,還有一個contrib庫,也就是prxml,這個庫的clojure 1.3版本有人維護了一個分支,在這里。主要方法就是prxml,它可以將clojure的數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換成xml:
          user=>(prxml [:p [:raw! "<i>here & gone</i>"]])
          <p><i>here & gone</i></p>
              顯然,它也可以用于生成HTML。

              xpath的支持可以使用clj-xpath這個開源庫,遺憾的是它目前僅支持clojure 1.2。

              轉(zhuǎn)載請注明出處:http://www.aygfsteel.com/killme2008/archive/2012/02/18/370233.html   
          主站蜘蛛池模板: 邳州市| 丘北县| 福海县| 瑞昌市| 宁陕县| 锦州市| 阳东县| 炉霍县| 泾川县| 金秀| 呼图壁县| 容城县| 武清区| 大安市| 正蓝旗| 雅安市| 南召县| 平遥县| 日喀则市| 桂阳县| 准格尔旗| 修文县| 敦化市| 报价| 萍乡市| 波密县| 准格尔旗| 莱芜市| 砚山县| 买车| 九台市| 邹平县| 阳春市| 施秉县| 永寿县| 金川县| 黄石市| 海丰县| 胶南市| 法库县| 昌图县|