【问题标题】:Is there Clojure module equivalent to Python's lxml?是否有与 Python 的 lxml 等效的 Clojure 模块?
【发布时间】:2012-06-28 13:43:21
【问题描述】:

对于同一主题的第二个问题,我深表歉意,但我很困惑。是否有遵循 lxml 的 Clojure 模块,甚至是松散的,或者关于如何使用 Clojure 遍历 XML 文件的操作文档?

在 Python 中,我可以使用 lxml 模块打开一个 XML 文件;通过数据解析我的方式;查找<DeviceID>, <TamperName>, <SecheduledDateTime> 之类的标签,然后根据其中一个标签的值执行操作。

在 Clojure 中,我得到了关于如何使用 data.xml 解析然后通过提取 :content 标记的 val 并将信息放入树序列来进一步减少 data.xml 解析的信息的出色答案。

但是,即使结果数据也嵌入了其他地图标签,这些标签显然不会响应键和 vals 函数。

我可以获取这些数据并使用正则表达式搜索,但我觉得我遗漏了一些更简单的东西。

data.xml/parse 中的数据(调用ret-xml-data)看起来像这样,在 REPL 中使用各种(首先解析的 xml)和其他命令:

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

一如既往的感谢。

编辑: 添加更多测试。

如果我使用类似 doseq 的函数遍历树序列结构,结果数据现在可能可以通过所采取的操作进行解析。

【问题讨论】:

  • “嵌入的其他地图标签”到底是什么意思?
  • 我无法在文本编辑器中轻松看到树形结构,因此元素看起来是相互嵌入的。基本上,我想要给我时间/日期、endpointid 和任何其他嵌入信息的标签。我通过过滤掉 :content 到达了我想去的地方。这给了我一张更简单的地图。
  • 您是否尝试过使用clojure.pprint/pprint(我想我没记错)。它会自动缩进所有内容。

标签: clojure lxml


【解决方案1】:

首先,很难准确地说出您要做什么。在解决编程问题时,它可以帮助您和其他人帮助您拥有一个“小案例”,您可以在解决更大的问题之前提出和解决。

听起来,您正试图从某些元素中提取内容并根据该内容执行操作。

我整理了一个包含一些简单内容的小 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 循环与: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 等对它们起作用,这就是它们的预期使用方式。

如果这不能帮助您获得所需的结果,那么您能否提供一个小样本输出和您想要的样本结果?

【讨论】:

    【解决方案2】:

    经过(非常)简短的了解后,我能想到的最接近 lxml 的 Clojure 库称为 Enlive。它被列为 HTML 模板工具,但我很确定它用于挑选 HTML 元素的技术也可以应用于 XML。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-18
      • 1970-01-01
      • 2011-08-03
      • 2020-11-07
      • 2013-02-04
      • 2012-11-21
      • 2011-07-10
      • 2011-01-21
      相关资源
      最近更新 更多