如何在Enlive中使用选择器否定(但是...)处理更复杂的HTML片段?

15

我有一个类似于以下HTML代码片段:

<div id="root">
    <div id="A" attrib_2="bar"></div>
    <div id="B" attrib_2="baz">
        <div id="H" attrib_1="gnu">
            <p>
                <div id="F" attrib_2="baz"></div>
            </p>
        </div>
    </div>
    <div id="C" attrib_2="owl"></div>
    <div id="D" attrib_2="uhu"></div>
    <div id="E" attrib_2="boom"></div>
</div>

现在,我想选择所有具有 attrib_2 (*[attrb_2]) 属性的片段,但是要排除那些属于设置了 attrib_1 属性的节点。可能会有任意标签(例如此示例中的 <p>)的更多嵌套级别。使用 Enlive (http://enlive.cgrand.net/),我已经尝试过以下代码:

(select snippet [(but (attr? :attrib_1)) (attr? :attrib_2)])

但是这个方法不起作用,因为否定条件 (but (attr? :attrib_1)) 也会匹配到 <p> 标签。有没有一种方法可以使用给定的选择器谓词(http://enlive.cgrand.net/syntax.html)来表达这个条件,还是我必须自己编写一个条件?

提前致谢。

- Jochen


从语义上讲,内部的attrib_2应该是不同的吗?[编辑:抱歉,我在考虑类,这可能实际上有助于识别不同的作用域,而不是属性。] - Jeremy
这个应用场景是从网页中提取RDFa元素,如http://www.w3.org/TR/rdfa-api/所述。我想搜索具有“typeof”属性的标签中的“property”属性。但只搜索“直接”的后代。带有“typeof”属性的后代会打开一个新的上下文进行评估。 - Jochen Rau
你为什么要给这个CSS打标签?我对Enlive不是很熟悉,但如果你想在纯CSS中实现这个解决方案,是有可能的。 - Wex
我在这里标记了CSS,因为Enlive使用相同的选择器语义。您如何在纯CSS中实现这一点? - Jochen Rau
3个回答

4

您需要编写自己的选择器:

(def parents 
  (zip-pred (fn [loc pred]
              (some pred (take-while identity (iterate zip/up loc))))))

(未经测试)

然后

(select snippet [[(attr? :attrib_2) (but (parents (attr? :attrib_1))]])

应该可以工作。

1
如果您只想遍历父级,则应在谓词定义中使用(iterate zip/up (zip/up loc)) - Aleš Kotnik
请注意,zip-pred现在需要一个一元函数,因此pred应该成为parents的参数。 - Alan Pearce

1
#root #a attrib_2{}
#root #b attrib_2{}
#root #c attrib_2{}
#root #d attrib_2{}
#root #e attrib_2{}

这将选择根div内css中的所有attrib2片段。


1

仅就论点而言,你不能这样做吗:

<div id="whatever" class="attrib_2 bar"></div>

从语义上看,这似乎更好,但我不知道您使用的系统或最终目的是什么。然而,如果您使用类,CSS 将非常简单:

div.attrib.bar {
    something:else;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接