在Nokogiri中选择子节点的绝对最便宜的方法是什么?

我知道有几十种方法可以选择Nokogiri的第一个子元素,但哪个最便宜? 我无法使用Node#children,这听起来非常昂贵。 假设有10000个子节点,我不想触及其他9999个…

Node#child是获取第一个子元素的最快方法。

但是,如果您要查找的节点不是第一个节点(例如,第99个节点),则没有更快的方法来选择该节点,而不是调用#children并将其编入索引。

你说的是,如果你只想要第一个孩子,为所有孩子建立一个NodeSet是很昂贵的。

一个限制因素是libxml2(Nokogiri底层的XML库)将节点的子节点存储为链接列表。 因此,您需要遍历列表(O(n))以选择所需的子节点。

编写一个方法来简单地返回第n个子节点是可行的,而不需要为所有其他子节点实例化NodeSet甚至ruby对象。 我的建议是在http://github.com/tenderlove/nokogiri/issues上打开一个function请求,或发送电子邮件到nokogiri邮件列表。

您可以自己尝试并对结果进行基准测试。

我创建了一个快速基准: http : //gist.github.com/283825

$ ruby test.rb Rehearsal --------------------------------------------------- xpath/first() 3.290000 0.030000 3.320000 ( 3.321197) xpath.first 3.360000 0.010000 3.370000 ( 3.381171) at 4.540000 0.020000 4.560000 ( 4.564249) at_xpath 3.420000 0.010000 3.430000 ( 3.430933) children.second 0.220000 0.010000 0.230000 ( 0.233090) ----------------------------------------- total: 14.910000sec user system total real xpath/first() 3.280000 0.000000 3.280000 ( 3.288647) xpath.first 3.350000 0.020000 3.370000 ( 3.374778) at 4.530000 0.040000 4.570000 ( 4.580512) at_xpath 3.410000 0.010000 3.420000 ( 3.421551) children.second 0.220000 0.010000 0.230000 ( 0.226846) 

从我的测试来看, children似乎是最快的方法。

既不使用XPath也不导致解析整个父节点的方法是使用Node#child(),Node#next_sibling()和Node#元素?()

这样的东西……

 def first(node) element = node.child while element if element.element? return element else element = element.next end end nil end