13

次のサンプル 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>

Clojureで解析する方法を知っています

(require '[clojure.xml :as xml])
(def x (xml/parse 'location/of/that/xml'))

これは、xml を記述するネストされたマップを返します。

{:tag :data,
 :attrs nil,
 :content [
     {:tag :products,
      :attrs nil,
      :content [
          {:tag :product,
           :attrs nil,
           :content [] ..

もちろん、この構造は標準の Clojure 関数でトラバースできますが、たとえば XPath でクエリを実行する場合と比較すると、非常に冗長になる可能性があります。そのような構造をトラバースして検索するヘルパーはありますか? たとえば、どうすればよいですか

  • すべてのリストを取得する<product>
  • <images>タグに<image>「img2.jpg」というテキストが含まれている製品のみを取得します
  • section「赤い部分」の商品をゲット

ありがとう

4

5 に答える 5

10

ここでdata.zipからZippersを使用することは、2 番目のユース ケースのソリューションです。

(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")})
于 2012-07-18T14:59:39.223 に答える
5

3 つのユースケースすべてについて、 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")}
于 2014-02-13T13:04:20.453 に答える
3

次のようなライブラリを使用できますclj-xpath

于 2012-07-18T09:17:23.510 に答える
1

多くの場合、スレッド ファースト マクロと clojures マップおよびベクトル セマンティクスは、xml にアクセスするための適切な構文です。xml に固有のもの (xpath ライブラリなど) が必要な場合が多くありますが、多くの場合、既存の言語は依存関係を追加することなくほぼ同じくらい簡潔です。

(pprint (-> (xml/parse "/tmp/xml") 
        :content first :content second :content first :content first))
"Blue Section"  
于 2012-07-18T18:34:22.650 に答える