Enlive を使用して一連の XML ドキュメントを処理する Clojure コードを作成しています。これらは、HTML を大幅に借用した XML 形式ですが、いくつかのカスタム タグが追加されています。私の仕事は、それらを実際の 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 -sho-be-要素は、周囲<li>
の要素と同じクラスを持つ場合があり、2 つの連続する-that-のグループがある場合もあります。お互いに同じクラスを持つ要素であるべきです(つまり、私が投稿した例に、クラスを持つ両方のクラスターがあるかのように)。私が信頼できると思うことの 1 つは、少なくとも 1 つのリスト以外の要素がそれらを分離することなく、2 つの異なるリストが存在することは決してないということです。つまり、すべての要素が「少なくとも 1 つの要素を子孫」はすべて同じリストの一部です。<p>
<p>
<li>
ListWithTabs
<p>
<tab>
そのことを念頭に置いて、名前空間の下に Enlive をロードして、REPL でいくつかの実験を行いましたe
(つまり(require '[net.cgrand.enlive-html :as e])
、私の質問の残りのすべてで有効であると想定する必要があります)。必要な要素を選択するセレクターを作成するのは簡単(e/select snippet [(e/has [:tab])])
でしたが、5 つの要素のリスト (実際には遅延シーケンスです) を返します。しかし、私が欲しいのはリストのリストです。1 つ目は 3 つの要素を持ち、2 つ目は 2 つの要素を持ちます。このような漠然としたもの(非標準のインデントを許してください):
[
[{: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-at
やのような機能はありませんtake-while
。
非常に近づいているように感じますが、最後の重要なステップが 1 つ欠けているだけです。では、最後の一歩を踏み出すにはどうすればよいでしょうか。特定のルールに一致する要素の「クラスター」のみを選択し、同じルールに一致するがその最初の「クラスター」の一部ではない他の要素を除外するにはどうすればよいですか?