2

Clojureデータ構造をXMLにシリアル化する必要がありますが、コレクションを発行する方法に出くわしています。これをより具体的にするために、次のようにClojureマップがあると仮定します。

    (def parking-lot {:parking-lot #{
                         {:car {:color "red", :make "nissan", :year 2003}}
                         {:car {:color "blue", :make "toyota", :year 2001}}
                         {:car {:color "black", :make "honda", :year 2010}}}})

これは、値が「車」アイテムのセットである1つの要素を持つ単なるマップです。ここで、このマップをシリアル化して次のXMLを生成するとします。

    <? xml version="1.0" ?>
    <parking-lot>
      <car color="red" make="nissan" year="2003" />
      <car color="blue" make="toyota" year="2001" />
      <car color="black" make="black" year="2010" />
    </parking-lot>

ClojureでXMLを最適に解析/出力する方法に関するドキュメントをWebで検索すると、clojure.data.xmlライブラリが表示されたので、それを使用しています。

clojure.data.xmlを使用してXMLを出力する方法の簡単な例を次に示します。

    REPL> (use 'clojure.data.xml)

        => nil
    REPL> (emit-str (element :parking-lot {}))

        => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
            <parking-lot></parking-lot>"

もう少し複雑な例:

    REPL> (emit-str (element :parking-lot {}
              (element :car {:color "yellow" :make "ford" :year "2000"})
              (element :car {:color "purple" :make "chevrolet" :year "1977"})))

        => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
            <parking-lot>
                <car color=\"yellow\" year=\"2000\" make=\"ford\"></car>
                <car color=\"purple\" year=\"1977\" make=\"chevrolet\"></car>
            </parking-lot>"

ここで、「element」関数の3番目の引数は、実際には「element」への可変数の呼び出しである可能性があることがわかります。'element'関数のドキュメントを詳しく調べずに、'element'がオーバーロードされて、一連の要素アイテムも3番目の引数として使用されると思いました。そのため、ドキュメントを見ずに、先に進んで、それを実行するコードの小さなブロックを作成しました。

    REPL> (emit-str (element :parking-lot {}
              (map (fn [car] (let [carattrs (:car car)]
                       (element :car {:color (:color carattrs),
                                      :make (:make carattrs),
                                      :year (:year carattrs)}))) 
                   (:parking-lot parking-lot))))

私はこれがうまくいくことを望んでいましたが、残念ながらそうではありません。問題は、「element」関数の3番目の引数をシーケンス自体にすることはできないということです。

ですから、この時点で私は何をすべきかについて少し困惑しています。私はまだLispとClojureに比較的慣れていないので、次の考えがモロニックであるなら、私を楽にしてください。だから私の考えは、これはマクロのユースケースでしょうか?つまり、車のセット(またはそのことについては任意のcoll)を入力として受け取り、そのアイテムを個々のs式として出力するマクロを作成する必要がありますか?たとえば、次のように動作するマクロを頭の中で考えています。

    REPL> (defmacro flatten-as-elements [coll-of-cars] ...)
    REPL> (flatten-as-elements #{ {:color "blue" :model "honda" year "2000"}
                                  {:color "yellow" :model "ford" year "2011"}})
        => (element :car {:color "blue" :model "honda" year "2000"})
           (element :car {:color "yellow" :model "ford" year "2011"})

少なくとも私の考えでは、そのようなマクロの出力は、「要素」関数の3番目の引数として適合し、私の目的の目標を生成します。もちろん、私の心配は、私が見落としている完全に明白な解決策がいくつかあり、ここでマクロを使用することは誤った方向に進んでいることです。SOコミュニティからの助けは大歓迎です!前もって感謝します!

-ポール

4

2 に答える 2

6

何が属性であり、何がサブ要素であるかについての「隠された」情報を持っているので、あなたが要求した変換は一般的に不可能です。このカスタムの要素としてのフラット化関数またはそれが何であれ、作成できます。その後、プロセス全体にドメイン固有の知識を大量に挿入すると、シリアル化できるようになります。

しかし実際には、clojureでXMLの2つの一般的な「表現」のいずれかを使用する必要があります。データを次のように記述します。

{:tag :parking-lot
 :content [{:tag :car :attrs {:color "red", :make "nissan", :year 2003}}
           {:tag :car :attrs {:color "blue", :make "toyota", :year 2001}}
           {:tag :car :attrs {:color "black", :make "honda", :year 2010}}]}

これは、data.xmlがかなり単純に出力できると思います。または、タグのベクトルと複数の要素のリストを使用して、はるかに簡潔なヒカップスタイルを使用することもできます。

[:parking-lot (list [:car {:color "red", :make "nissan", :year 2003}]
                    [:car {:color "blue", :make "toyota", :year 2001}]
                    [:car {:color "black", :make "honda", :year 2010}])]

で印刷できます(emit (sexp-as-element [...]))

于 2012-05-15T06:50:42.473 に答える
5

apply引数を関数呼び出しにスプライスするために使用できます。

(emit-str
 (apply element :parking-lot {}
        (map (fn [car] (let [carattrs (:car car)]
                         (element :car {:color (:color carattrs),
                                        :make (:make carattrs),
                                        :year (:year carattrs)}))) 
                           (:parking-lot parking-lot))))
于 2012-05-15T07:04:21.380 に答える