(def testxml2
"<top>
<group>
<group>
<item>
<number>1</number>
</item>
<item>
<number>2</number>
</item>
<item>
<number>3</number>
</item>
</group>
<item>
<number>0</number>
</item>
</group>
</top>")
(def txml2 (zip-str testxml2))
(defn deep-items [x]
(zip-xml/xml-> x
:top
:group
:group
:item))
(count (deep-items txml2))
;; 1
(zip-xml/text (first (deep-items txml2)))
;; "0"
我试图获取内部:group
的值,但它似乎被外部的一个抓住了。它似乎忽略了第二个:group
。
我尝试解析的实际XML有一个重复的嵌套<TheirTag><TheirTag>Foo</TheirTag></TheirTag>
模式,我需要单独访问每个Foo。 XML来自第三方,因此我无法重构XML以避免这种情况。
答案 0 :(得分:1)
The reason for the bug is here。对于简短版本:版本0.1.2在这方面略有不同,无法通过tag=
函数(:myTag
样式选择器的基础)选择具有相同名称的子条目。这是由于从0.1.1到0.1.2的回归(感谢@bpeter和@shilder)。解决方法是在某个util命名空间中创建一个函数tag=
并直接使用它直到修复回归。
;; util.clj
(defn tag=
"This is a workaround to a regression in 0.1.2. Fixed in upcoming 1.2.0
Returns a query predicate that matches a node when its is a tag
named tagname."
[tagname]
(fn [loc]
(filter #(and (zip/branch? %) (= tagname (:tag (zip/node %))))
(zf/children-auto loc))))
;; project.somefile.clj
(ns project.somefile
(:require [project.util :as u]))
(defn deep-items [x]
(zip-xml/xml-> x
:top
(u/tag= :group)
(u/tag= :group)
:item))
答案 1 :(得分:0)
您可以使用the Tupelo Forest library来解决此问题,以处理树状数据结构。除了显式搜索外,它还可以使用zsh
之类的通配符。 Documentation is ongoing,但这会让你体验到你可以做的事情:
(dotest
(with-forest (new-forest)
(let [xml-str "<top>
<group>
<group>
<item>
<number>1</number>
</item>
<item>
<number>2</number>
</item>
<item>
<number>3</number>
</item>
</group>
<item>
<number>0</number>
</item>
</group>
</top>"
enlive-tree (->> xml-str
java.io.StringReader.
en-html/xml-resource
only)
root-hid (add-tree-enlive enlive-tree)
; Removing whitespace nodes is optional; just done to keep things neat
blank-leaf-hid? (fn fn-blank-leaf-hid? ; whitespace pred fn
[hid]
(let [node (hid->node hid)]
(and (contains-key? node :value)
(ts/whitespace? (grab :value node)))))
blank-leaf-hids (keep-if blank-leaf-hid? (all-leaf-hids)) ; find whitespace nodes
>> (apply remove-hid blank-leaf-hids) ; delete whitespace nodes found
你真正关心的部分就在这里。有两种方法可以搜索嵌套节点。
第二个使用像zsh这样的通配符:**
,匹配零个或多个目录。
; Can search for inner `div` 2 ways
result-1 (find-paths root-hid [:top :group :group]) ; explicit path from root
result-2 (find-paths root-hid [:** :group :item :number]) ; wildcard path that ends in :number
]
对于演员表(1),我们发现我们只找到了第1,2和3项:
; Here we see only the double-nested items 1, 2, 3
(is= (spyx-pretty (format-paths result-1))
[[{:tag :top}
[{:tag :group}
[{:tag :group}
[{:tag :item} [{:tag :number, :value "1"}]]
[{:tag :item} [{:tag :number, :value "2"}]]
[{:tag :item} [{:tag :number, :value "3"}]]]]]] )
对于案例(2),我们不仅发现了双嵌套项,还发现了单嵌套项0
:
; Here we see both the double-nested items & the single-nested item 0
(is= (spyx-pretty (format-paths result-2))
[[{:tag :top}
[{:tag :group} [{:tag :item} [{:tag :number, :value "0"}]]]]
[{:tag :top}
[{:tag :group}
[{:tag :group} [{:tag :item} [{:tag :number, :value "1"}]]]]]
[{:tag :top}
[{:tag :group}
[{:tag :group} [{:tag :item} [{:tag :number, :value "2"}]]]]]
[{:tag :top}
[{:tag :group}
[{:tag :group} [{:tag :item} [{:tag :number, :value "3"}]]]]]])
)))
您没有指定所需的下游处理。 Tupelo.Forest
能够将输出转换为hiccup
和enlive
两种格式,以及它自己的打嗝灵感bush
格式以及一种活跃的tree
格式格式。