Apakah ada modul Clojure yang setara dengan lxml Python?

Saya minta maaf untuk pertanyaan kedua tentang topik yang sama, tapi saya bingung. Apakah ada modul Clojure yang mengikuti lxml, bahkan secara longgar, atau dokumentasi cara berjalan melalui file XML menggunakan Clojure?

Dengan Python, saya dapat membuka file XML menggunakan modul lxml; menguraikan cara saya melalui data; cari tag seperti <DeviceID>, <TamperName>, <SecheduledDateTime>, lalu lakukan tindakan berdasarkan nilai salah satu tag tersebut.

Di Clojure, saya telah diberikan jawaban yang sangat bagus tentang cara mengurai menggunakan data.xml dan kemudian mengurangi lebih lanjut informasi yang diurai data.xml dengan menarik nilai tag :content dan meletakkan informasi tersebut di tree-seq.

Namun, bahkan data yang dihasilkan tersebut memiliki tag peta lain yang tertanam, yang jelas tidak merespons fungsi kunci dan vals.

Saya dapat mengambil data ini dan menggunakan penelusuran ekspresi reguler, tetapi saya merasa ada sesuatu yang lebih sederhana yang hilang.

Data langsung dari data.xml/parse (memanggil ret-xml-data) terlihat seperti ini, menggunakan berbagai (xml parsing pertama) dan perintah lain di REPL:

[:tag :TamperExport]
[:attrs {}]
:content
#clojure.data.xml.Element{:tag :Header, :attrs {}, :content 
(#clojure.data.xml.Element{:tag :ExportType, :attrs {}, 
:content ("Tamper Export")} 
#clojure.data.xml.Element{:tag :CurrentDateTime, 
:attrs {}, 
:content ("2012-06-26T15:40:22.063")} :attrs {}, 
:content ("{06643D9B-DCD3-459B-86A6-D21B20A03576}")}

Berikut adalah kode Clojure yang saya miliki sejauh ini:

(defn ret-xml-data
    "Returns a map of the supplied xml file, as parsed by data.xml/parse."
    [xml-fnam]

    (let [input-xml (try
                        (java.io.FileInputStream. xml-fnam)
                        (catch Exception e))]

        (if-not (nil? input-xml)
            (xmld/parse input-xml)
            nil)))

(defn gen-xml-content-tree
    "Returns a tree-seq with :content extracted."

    [parsed-xml]
    (map :content (first (tree-seq :content :content (:content parsed-xml)))))

Saya rasa saya mungkin telah menemukan pola berulang pada data yang memungkinkan saya menguraikannya tanpa membuat gado-gado:

xml-lib.core=> (first (second cl1))
#clojure.data.xml.Element{:tag :DeviceId, :attrs {}, :content ("80580608")}
xml-lib.core=> (keys (first (second cl1)))
(:tag :attrs :content)
xml-lib.core=> (vals (first (second cl1)))
(:DeviceId {} ("80580608"))

Terima kasih seperti biasa.

Sunting: Tambahkan beberapa pengujian lagi.

Data yang dihasilkan, jika saya menelusuri struktur tree-seq menggunakan fungsi seperti doseq, mungkin sekarang dapat diuraikan dengan tindakan yang diambil.


person octopusgrabbus    schedule 28.06.2012    source sumber
comment
Apa sebenarnya yang Anda maksud dengan tag peta lain yang disematkan?   -  person deterb    schedule 12.07.2012
comment
Saya tidak dapat dengan mudah melihat struktur pohon di editor teks, sehingga elemen tampak tertanam satu sama lain. Pada dasarnya, saya ingin tag yang memberi saya waktu/tanggal, titik akhir, dan informasi lainnya disematkan. Saya mencapai tujuan yang saya inginkan dengan memfilter :konten. Itu memberi saya peta yang lebih sederhana.   -  person octopusgrabbus    schedule 12.07.2012
comment
Sudahkah Anda mencoba menggunakan clojure.pprint/pprint (saya rasa saya ingat betul). Ini akan secara otomatis membuat indentasi semuanya dengan baik.   -  person deterb    schedule 13.07.2012


Jawaban (2)


Pertama, sulit untuk mengatakan dengan tepat apa yang Anda coba lakukan. Saat mengerjakan masalah pemrograman, ada baiknya Anda dan orang lain membantu Anda memiliki "kasus kecil" yang dapat Anda presentasikan dan selesaikan sebelum mengerjakan masalah yang lebih besar.

Dari kelihatannya, Anda mencoba menarik konten dari elemen tertentu dan melakukan tindakan berdasarkan konten tersebut.

Saya mengumpulkan file XML kecil dengan beberapa konten sederhana untuk dicoba:

<root>
    <someele>
        <item1>data</item1>
        <deeper>
            <item2>else</item2>
        </deeper>
    </someele>
</root>

Saya merancangnya agar menjadi apa yang menurut saya mewakili beberapa tantangan inti dari masalah yang ada - khususnya, mampu melakukan hal-hal pada tingkat yang sewenang-wenang dalam bersarang di XML.

Melihat Clojure Cheatsheet yang menakjubkan, saya menemukan xml-seq, dan mencoba menjalankannya di clojure.data.xml/parsed xml. Urutannya menelusuri masing-masing elemen dan kemudian turunannya, sehingga memudahkan untuk mengulangi XML.

Untuk memilih dan mengerjakan item tertentu secara berurutan, saya suka menggunakan for loop dengan :when. :when memudahkan untuk memasukkan badan perulangan ketika kondisi tertentu benar. Saya juga menggunakan semantik "ditetapkan sebagai fungsi", yang memeriksa apakah ada sesuatu di dalam set.

(for [ele (xml-seq (load-xml))
      :when (#{:item1 :item2} (:tag ele))]
  [(:tag ele) (first (:content ele))])

Ini mengembalikan urutan ([:item1 "data"] [:item2 "else"]) yang kemudian dapat dengan mudah ditindaklanjuti dengan cara lain.

Salah satu hal utama yang perlu dicoba dan diingat tentang Clojure adalah Anda cenderung tidak memerlukan API khusus untuk melakukan sesuatu - bahasa intinya memudahkan Anda melakukan sebagian besar, jika tidak semua, yang perlu Anda lakukan. Catatan (yang Anda lihat dikembalikan) juga merupakan peta misalnya, jadi assoc, dissoc, dan seterusnya mengerjakannya, dan begitulah cara kerjanya.

Jika ini tidak membantu Anda mendapatkan apa yang Anda butuhkan, dapatkah Anda memberikan contoh kecil keluaran dan contoh hasil yang Anda inginkan?

person deterb    schedule 12.07.2012

Pustaka Clojure terdekat yang dapat saya pikirkan untuk lxml setelah melihat (sangat) singkat disebut Enlive. Ini terdaftar sebagai alat templating HTML, tapi saya cukup yakin teknik yang digunakannya untuk memilih elemen HTML juga dapat diterapkan ke XML.

person deterb    schedule 12.07.2012