3

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

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

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

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

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

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 的函数遍历树序列结构,得到的数据现在可能可以通过所采取的操作进行解析。

4

2 回答 2

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 等在它们上工作,这就是它们的预期使用方式。

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

于 2012-07-12T03:21:38.007 回答
1

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

于 2012-07-12T04:22:43.103 回答