2

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 つ欠けているだけです。では、最後の一歩を踏み出すにはどうすればよいでしょうか。特定のルールに一致する要素の「クラスター」のみを選択し、同じルールに一致するがその最初の「クラスター」の一部ではない他の要素を除外するにはどうすればよいですか?

4

1 に答える 1