Skip to content

Instantly share code, notes, and snippets.

@bouzuya
Created January 27, 2013 13:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bouzuya/4648350 to your computer and use it in GitHub Desktop.
Save bouzuya/4648350 to your computer and use it in GitHub Desktop.
(ns google-reader.xml-test
(:require [clojure.xml :as xml]
[clojure.zip :as zip]
[clojure.data.zip.xml :as dzx])
(:use clojure.test))
(def xml-str-1
(str "<root id='1'>"
" <parent id='2'>"
" <child id='3'/>"
" </parent>"
" <parent id='4'>"
" <child id='5'/>"
" <child id='6'/>"
" </parent>"
"</root>"))
;; Atom Feed example.
;; http://ja.wikipedia.org/wiki/Atom
(def xml-str-2
(str
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
"<feed xmlns=\"http://www.w3.org/2005/Atom\">"
" <title>Example Feed</title>"
" <link href=\"http://example.org/\"/>"
" <updated>2003-12-13T18:30:02Z</updated>"
" <author>"
" <name>John Doe</name>"
" </author>"
" <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>"
" <entry>"
" <title>Atom-Powered Robots Run Amok</title>"
" <link href=\"http://example.org/2003/12/13/atom03\"/>"
" <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>"
" <updated>2003-12-13T18:30:02Z</updated>"
" <summary>Some text.</summary>"
" </entry>"
"</feed>"))
(def xml-str-3
(str
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
"<feed xmlns=\"http://www.w3.org/2005/Atom\">"
" <title>Example Feed</title>"
" <link href=\"http://example.org/\"/>"
" <updated>2003-12-13T18:30:02Z</updated>"
" <author>"
" <name>John Doe</name>"
" </author>"
" <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>"
" <entry>"
" <title>Atom-Powered Robots Run Amok</title>"
" <link href=\"http://example.org/2003/12/13/atom03\"/>"
" <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>"
" <updated>2003-12-13T18:30:02Z</updated>"
" <summary>Some text.</summary>"
" </entry>"
" <entry>"
" <title>entry title 2</title>"
" <id>urn:uuid:aedc9760-6790-11e2-bcfd-0800200c9a66</id>"
" <updated>2003-12-13T18:30:02Z</updated>"
" </entry>"
"</feed>"))
(with-test
(defn parse-str
[xml]
(->
xml
(java.io.StringReader.)
(org.xml.sax.InputSource.)
(xml/parse)))
(is (= (parse-str xml-str-1)
{:tag :root,
:attrs {:id "1"},
:content
[{:tag :parent,
:attrs {:id "2"},
:content [{:tag :child, :attrs {:id "3"}, :content nil}]}
{:tag :parent,
:attrs {:id "4"},
:content
[{:tag :child, :attrs {:id "5"}, :content nil}
{:tag :child, :attrs {:id "6"}, :content nil}]}]})))
; [clojure.zip :as zip]
(with-test
(defn zip-xml
[xml]
(zip/xml-zip xml))
(is (= (->
(parse-str xml-str-1)
zip-xml
(dzx/xml-> :parent :child (dzx/attr :id)))
["3" "5" "6"])))
; use [clojure.data.zip.xml :as dzx]
(with-test
(defn zip-xml-str
[xml-str]
(->
xml-str
parse-str
zip-xml))
(is (= (->
(zip-xml-str xml-str-2)
(dzx/xml-> :entry :title dzx/text)
first)
"Atom-Powered Robots Run Amok"))
(is (= (->
(zip-xml-str xml-str-2)
(dzx/xml1-> :entry :title dzx/text))
"Atom-Powered Robots Run Amok"))
(is (= (->
(zip-xml-str xml-str-2)
(dzx/xml-> :entry :title dzx/text)
first)
(->
(zip-xml-str xml-str-2)
(dzx/xml1-> :entry :title dzx/text))))
(is (= (->
(zip-xml-str xml-str-3)
(dzx/xml-> :entry :title dzx/text))
["Atom-Powered Robots Run Amok" "entry title 2"]))
(is (= (->
(zip-xml-str xml-str-3)
(dzx/xml->
:entry
(fn [loc]
{:title (dzx/xml1-> loc :title dzx/text)
:link (dzx/xml1-> loc :link (dzx/attr :href))})))
[{:title "Atom-Powered Robots Run Amok"
:link "http://example.org/2003/12/13/atom03"}
{:title "entry title 2"
:link nil}])))
@bouzuya
Copy link
Author

bouzuya commented Jan 27, 2013

Clojure で XML を走査する例。 clojure.data.zip.xml を使った。

処理の流れは次の通り。

  1. clojure.xml/parseStringMap ( Clojure 内で XML を扱う際の標準的な形式 ) に変換し、
  2. clojure.zip/xml-zipMap ( XML ) を zipper に食わせて、
  3. clojure.data.zip.xml/xml-> ないし clojure.data.zip.xml/xml1-> で zipper を処理する。

xml1->xml->first を返す。

xml-> は 検索する要素名をキーワードで渡す。最後に指定した関数の結果のシーケンスが返される。clojure.data.zip.xml/textclojure.data.zip.xml/attr などを与えると良い。

最後の例のように独自の関数を渡してやることもできる。

Clojure のテンプレートエンジン enlive は、こういった CSS selector のような機能をさらに強めている。興味があれば、あわせて調べてみてほしい。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment