我有以下示例xml:
<data>
<products>
<product>
<section>Red Section</section>
<images>
<image>img.jpg</image>
<image>img2.jpg</image>
</images>
</product>
<product>
<section>Blue Section</section>
<images>
<image>img.jpg</image>
<image>img3.jpg</image>
</images>
</product>
<product>
<section>Green Section</section>
<images>
<image>img.jpg</image>
<image>img2.jpg</image>
</images>
</product>
</products>
</data>
Run Code Online (Sandbox Code Playgroud)
我知道如何在Clojure中解析它
(require '[clojure.xml :as xml])
(def x (xml/parse 'location/of/that/xml'))
Run Code Online (Sandbox Code Playgroud)
这将返回描述xml的嵌套映射
{:tag :data,
:attrs nil,
:content [
{:tag :products,
:attrs nil,
:content [
{:tag :product,
:attrs nil,
:content [] ..
Run Code Online (Sandbox Code Playgroud)
这个结构当然可以用标准的Clojure函数遍历,但它可能会变得非常冗长,特别是与例如用XPath查询它时相比.是否有任何助手可以遍历和搜索这样的结构?例如,我怎么能
<product><images>标签包含<image>文本"img2.jpg"的产品section"红色部分"的产品谢谢
在data.zip中使用Zippers是第二个用例的解决方案:
(ns core
(:use clojure.data.zip.xml)
(:require [clojure.zip :as zip]
[clojure.xml :as xml]))
(def data (zip/xml-zip (xml/parse PATH)))
(def products (xml-> data :products :product))
(for [product products :let [image (xml-> product :images :image)]
:when (some (text= "img2.jpg") image)]
{:section (xml1-> product :section text)
:images (map text image)})
=> ({:section "Red Section", :images ("img.jpg" "img2.jpg")}
{:section "Green Section", :images ("img.jpg" "img2.jpg")})
Run Code Online (Sandbox Code Playgroud)
小智 5
这是使用data.zip的替代版本,适用于所有三个用例。我发现了这一点,xml->并且xml1->内置了非常强大的导航,在向量中带有子查询。
;; [org.clojure/data.zip "0.1.1"]
(ns example.core
(:require
[clojure.zip :as zip]
[clojure.xml :as xml]
[clojure.data.zip.xml :refer [text xml-> xml1->]]))
(def data (zip/xml-zip (xml/parse "/tmp/products.xml")))
(let [all-products (xml-> data :products :product)
red-section (xml1-> data :products :product [:section "Red Section"])
img2 (xml-> data :products :product [:images [:image "img2.jpg"]])]
{:all-products (map (fn [product] (xml1-> product :section text)) all-products)
:red-section (xml1-> red-section :section text)
:img2 (map (fn [product] (xml1-> product :section text)) img2)})
=> {:all-products ("Red Section" "Blue Section" "Green Section"),
:red-section "Red Section",
:img2 ("Red Section" "Green Section")}
Run Code Online (Sandbox Code Playgroud)