如何解析CSS(CSS3)选择器并使用它(以类似于jQuery的方式)收集HTML元素而不是从DOM(从树结构)而是从流(例如SAX),即使用基于顺序访问事件的解析器收集HTML元素?
顺便说一句,是否有需要访问DOM的CSS选择器(或其组合)(Wikipedia SAX页面说XPath选择器“需要能够随时访问已解析的XML树中的任何节点”)?
我对实现选择器组合器最感兴趣,例如'A B'后代选择器。
我更喜欢描述算法的解决方案,或者在Perl中(对于HTML::Zoom)。
最佳答案
我会用正则表达式来做到这一点。
首先,将选择器转换为正则表达式,该正则表达式与代表给定解析器堆栈状态的简单的开头标签的从上到下列表匹配。为了说明,这里有一些简单的选择器及其对应的正则表达式:
A
变成/<A[^>]*>$/
A#someid
变成/<A[^>]*id="someid"[^>]*>$/
A.someclass
变成/<A[^>]*class="[^"]*(?<= |")someclass(?= |")[^"]*"[^>]*>$/
A > B
变成/<A[^>]*><B[^>]*>$/
A B
变成/<A[^>]*>(?:<[^>]*>)*<B[^>]*>$/
等等。请注意,所有正则表达式均以$结尾,但不以^开头;这与CSS选择器不必从文档根部进行匹配的方式相对应。还要注意,在类匹配代码中有一些先行查找和提前查找的内容,这是必要的,这样当您想要截然不同的类“someclass”时,就不会意外地与“someclass-super-duper”进行匹配。
如果您需要更多示例,请告诉我。
构造选择器正则表达式后,就可以开始解析了。解析时,维护一堆当前适用的标签;每当您下降或上升时都更新此堆栈。要检查选择器是否匹配,请将该堆栈转换为可以匹配正则表达式的标记列表。例如,考虑以下文档:
<x><a>Stuff goes here</a><y id="boo"><z class="bar">Content here</z></y></x>
输入每个元素时,堆栈状态字符串将依次经过以下值:
<x>
<x><a>
<x><y id="boo">
<x><y id="boo"><z class="bar">
匹配过程很简单:只要解析器进入一个新元素,就更新状态字符串并检查其是否与选择器regex相匹配。如果正则表达式匹配,则选择器匹配该元素!
要注意的问题:
a#someid.someclass
时,期望<a id="someid" class="someclass">
的选择器<a class="someclass" id="someid">
的正则表达式失败。 A:first-child
和A + B
)需要额外的魔术。您可以通过在标签上添加一个特殊属性来实现这些目的,该属性应包含紧接其前的标签名称,如果该标签是第一个子标签,则可以添加“”。还有一个通用的同级选择器A ~ B
;我不太确定该如何处理。 编辑:如果您不喜欢正则表达式黑客,仍然可以使用此方法来解决问题,仅使用您自己的状态机而不是正则表达式引擎。具体来说,CSS选择器可以实现为nondeterministic finite state machine,这是一个令人生畏的术语,但实际上意味着以下含义:
几乎所有令人赞叹的正则表达式背后的 secret 都在于它使用这种状态机的风格。
关于html - 使用CSS选择器从流解析器(例如SAX流)收集HTML元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4656975/