2

我正在使用 Enlive 编写一些 Clojure 代码来处理一组 XML 文档。它们采用 XML 格式,大量借鉴了 HTML,但添加了一些自定义标签,我的工作是将它们转换为真正的 HTML。现在最困扰我的自定义标签是<tab>,它被用于各种不应该使用的地方。例如,它通常用于制作真正应该用<ol>and制作的列表<li>。这是我遇到的那种事情的一个例子:

<p class="Normal">Some text</p>
<p class="ListWithTabs">(a)<tab />First list item</p>
<p class="ListWithTabs">(b)<tab />Second list item</p>
<p class="ListWithTabs">(c)<tab />Third list item</p>
<p class="Normal">Some more text</p>
<p class="AnotherList">1.<tab />Another list</p>
<p class="AnotherList">2.<tab />Two items this time</p>
<p class="Normal">Some final text</p>

我想把它变成:

<p class="Normal">Some text</p>
<ol type="a">
<li class="ListWithTabs">First list item</li>
<li class="ListWithTabs">Second list item</li>
<li class="ListWithTabs">Third list item</li>
</ol>
<p class="Normal">Some more text</p>
<ol type="1">
<li class="AnotherList">Another list</li>
<li class="AnotherList">Two items this time</li>
</ol>
<p class="Normal">Some final text</p>

为此,我需要获取<p>包含<tab>后代的元素(使用 Enlive 选择器很容易),并根据它们在原始 XML 文档中的自然分组以某种方式对它们进行聚类(要困难得多)。

我查看了文档并确定我不能依赖该class属性:有时这些<p>-that-should-be-<li>元素与它们周围的元素具有相同的类<p>,有时有两组连续的<p>-that-应该<li>是彼此具有相同类的元素(即,好像我发布的示例中的两个集群都具有类ListWithTabs)。我认为我可以依赖的一件事是,如果没有至少一个非列表元素将它们分开,就永远不会有两个不同的列表:换句话说,任何<p>具有属性“至少有一个<tab>元素作为后代”都是同一个列表的一部分。

考虑到这一点,我在 REPL 上做了一些实验,在命名空间下加载了 Enlive e(也就是说,(require '[net.cgrand.enlive-html :as e])应该假设对我的所有其余问题都有效)。编写一个选择器来挑选我想要的元素很容易,但(e/select snippet [(e/has [:tab])])会返回一个包含 5 个元素的列表(嗯,这确实是一个惰性序列)。但我想要的是一个列表列表:第一个包含三个元素,第二个包含两个。像这样模糊的东西(请原谅非标准的缩进):

[
  [{:tag :p, :content (... "First list item" ...)}
   {:tag :p, :content (... "Second list item" ...)}
   {:tag :p, :content (... "Third list item" ...)}
  ] ; 3 items in first list
  [{:tag :p, :content (... "Another list" ...)}
   {:tag :p, :content (... "With just two items" ...)}
  ] ; 2 items in second list
]

我能够创建以下选择器:

(def first-of-tab-group [(e/has [:tab])
                         (e/left (complement (e/has [:tab])))])
(def rest-of-tab-group [(e/has [:tab])
                        (e/left (e/has [:tab]))])

但现在我被困住了。我想做类似的事情(e/select snippet [[(e/start-at first-of-tab-group) (e/take-while rest-of-tab-group)]]),但据我所知,Enlive 没有像start-atand这样的功能take-while

感觉就像我非常接近,但只是错过了最后一个关键步骤。那么我该如何迈出最后一步呢?如何只选择与某些规则匹配的元素“集群”,但忽略其他符合相同规则但不属于第一个“集群”的元素?

4

1 回答 1

0

根据 enlive 文档: {node-selector node-selector} 我们可以使用 {[:p.Normal] [:p.Normal]} 将它们分组,假设这是分隔符。

现在,我的问题是:如何使用 enlive 迭代每个结果组内的结果。

于 2018-11-20T07:00:44.273 回答