มีโมดูล Clojure เทียบเท่ากับ lxml ของ Python หรือไม่

ฉันขอโทษสำหรับคำถามที่สองในหัวข้อเดียวกัน แต่ฉันสับสน มีโมดูล Clojure ที่ตาม lxml แม้จะหลวม ๆ หรือมีเอกสารประกอบวิธีการอธิบายไฟล์ XML โดยใช้ Clojure หรือไม่

ใน Python ฉันสามารถเปิดไฟล์ XML โดยใช้โมดูล lxml แยกวิเคราะห์ข้อมูลของฉัน มองหาแท็ก เช่น <DeviceID>, <TamperName>, <SecheduledDateTime> จากนั้นดำเนินการตามค่าของแท็กใดแท็กหนึ่งเหล่านั้น

ใน Clojure ฉันได้รับคำตอบที่ยอดเยี่ยมเกี่ยวกับวิธีการแยกวิเคราะห์โดยใช้ data.xml แล้วลดข้อมูลที่แยกวิเคราะห์ data.xml เพิ่มเติมโดยการดึง vals ของแท็ก :content ออกมา และใส่ข้อมูลใน tree-seq

อย่างไรก็ตาม แม้ว่าข้อมูลผลลัพธ์นั้นจะมีแท็กแผนที่อื่นๆ ฝังอยู่ ซึ่งเห็นได้ชัดว่าไม่ตอบสนองต่อฟังก์ชันคีย์และ vals

ฉันสามารถนำข้อมูลนี้ไปใช้และใช้การค้นหาด้วยนิพจน์ทั่วไป แต่ฉันรู้สึกว่าฉันขาดสิ่งที่ง่ายกว่านี้ไปมาก

ข้อมูลทันทีที่ data.xml/parse (เรียก ret-xml-data) มีลักษณะเช่นนี้ โดยใช้คำสั่งต่างๆ (first parsed-xml) และคำสั่งอื่นๆ ที่ 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}")}

นี่คือรหัส Clojure ที่ฉันมี:

(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)))))

ฉันคิดว่าฉันอาจพบรูปแบบข้อมูลที่สามารถทำซ้ำได้ซึ่งจะทำให้ฉันสามารถแยกวิเคราะห์สิ่งนี้ได้โดยไม่ต้องสร้างการผสมผสาน:

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"))

ขอบคุณเช่นเคย.

แก้ไข: เพิ่มการทดสอบเพิ่มเติม

ข้อมูลผลลัพธ์ที่ได้หากฉันรันผ่านโครงสร้าง tree-seq โดยใช้ฟังก์ชันเช่น doseq ตอนนี้อาจถูกแยกวิเคราะห์พร้อมการดำเนินการที่ดำเนินการไปแล้ว


person octopusgrabbus    schedule 28.06.2012    source แหล่งที่มา
comment
แท็กแผนที่อื่นๆ ที่ฝังอยู่หมายความว่าอย่างไร   -  person deterb    schedule 12.07.2012
comment
ฉันมองเห็นโครงสร้างแบบต้นไม้ในโปรแกรมแก้ไขข้อความได้ไม่ชัดเจน ดังนั้นองค์ประกอบต่างๆ จึงปรากฏฝังอยู่ด้วยกัน โดยพื้นฐานแล้ว ฉันต้องการให้แท็กที่ระบุเวลา/วันที่, endpointid และข้อมูลอื่นๆ ฝังอยู่ ฉันไปถึงจุดที่ฉันต้องการโดยการกรอง :content นั่นทำให้ฉันมีแผนที่ที่ง่ายกว่า   -  person octopusgrabbus    schedule 12.07.2012
comment
คุณได้ลองใช้ clojure.pprint/pprint แล้วหรือยัง (ฉันคิดว่าฉันจำไม่ผิด) มันจะเยื้องทุกอย่างอย่างสวยงามโดยอัตโนมัติ   -  person deterb    schedule 13.07.2012


คำตอบ (2)


ประการแรก เป็นการยากที่จะบอกว่าคุณกำลังพยายามทำอะไร เมื่อแก้ไขปัญหาด้านการเขียนโปรแกรม จะช่วยให้คุณและคนอื่นๆ มี "กรณีเล็กๆ" ที่คุณสามารถนำเสนอและแก้ไขได้ ก่อนที่จะดำเนินการแก้ไขปัญหาที่ใหญ่กว่า

จากที่ฟังดูเหมือน คุณกำลังพยายามดึงเนื้อหาออกจากองค์ประกอบบางอย่างและดำเนินการตามเนื้อหานั้น

ฉันรวบรวมไฟล์ XML ขนาดเล็กพร้อมเนื้อหาง่ายๆ เพื่อลองใช้:

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

ฉันออกแบบให้เป็นสิ่งที่ฉันคิดว่าเป็นตัวแทนของความท้าทายหลักบางประการที่มีปัญหาอยู่ โดยเฉพาะอย่างยิ่ง ความสามารถในการทำสิ่งต่าง ๆ ในระดับการซ้อนใน XML โดยพลการ

เมื่อดู Clojure Cheatsheet ที่ยอดเยี่ยม ฉันพบ xml-seq และลองเรียกใช้บน clojure.data.xml/parsed xml ลำดับจะผ่านแต่ละองค์ประกอบ จากนั้นจึงตามด้วยองค์ประกอบย่อย ทำให้ง่ายต่อการวนซ้ำ XML

ในการเลือกและทำงานกับรายการใดรายการหนึ่งตามลำดับ ฉันชอบใช้ for loops กับ :when :when ทำให้ง่ายต่อการเข้าสู่เนื้อหาของลูปเมื่อมีเงื่อนไขบางประการเป็นจริง ฉันยังใช้ซีแมนทิกส์ "set as a function" ซึ่งจะตรวจสอบว่ามีอะไรอยู่ในชุดหรือไม่

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

สิ่งนี้จะส่งคืนลำดับของ ([:item1 "data"] [:item2 "else"]) ที่สามารถดำเนินการในรูปแบบอื่นได้อย่างง่ายดาย

สิ่งสำคัญประการหนึ่งที่ควรพยายามและจำไว้เกี่ยวกับ Clojure ก็คือคุณไม่จำเป็นต้องมี API พิเศษใดๆ ในการทำสิ่งต่างๆ - ภาษาหลักทำให้ง่ายต่อการทำส่วนใหญ่หรือทั้งหมดที่คุณต้องทำ บันทึก (ซึ่งเป็นสิ่งที่คุณเห็นว่าถูกส่งคืน) ก็เป็นแผนที่เช่นกัน ดังนั้น assoc, dissoc และอื่นๆ จึงดำเนินการกับสิ่งเหล่านั้น และเป็นวิธีการทำงานที่ตั้งใจไว้

หากวิธีนี้ไม่ช่วยให้คุณได้รับสิ่งที่คุณต้องการ คุณสามารถให้ผลลัพธ์ตัวอย่างเล็กๆ น้อยๆ และผลลัพธ์ตัวอย่างที่คุณต้องการได้หรือไม่

person deterb    schedule 12.07.2012

ไลบรารี Clojure ที่ใกล้เคียงที่สุดที่ฉันนึกถึงสำหรับ lxml หลังจากดูสั้นๆ (มาก) เรียกว่า Enlive มันถูกระบุว่าเป็นเครื่องมือสร้างเทมเพลต HTML แต่ฉันค่อนข้างแน่ใจว่าเทคนิคที่ใช้ในการเลือกองค์ประกอบ HTML สามารถนำไปใช้กับ XML ได้เช่นกัน

person deterb    schedule 12.07.2012