选择相邻的兄弟元素而不插入非空白文本节点

Phr*_*ogz 5 ruby xml xpath nokogiri

给定标记如:

<p>
  <code>foo</code><code>bar</code>
  <code>jim</code> and then <code>jam</code>
</p>
Run Code Online (Sandbox Code Playgroud)

我需要选择前三个<code>- 但不是最后一个.逻辑是"选择code具有先前或后续兄弟元素的所有元素也是a code,除非存在一个或多个文本节点,它们之间具有非空白内容.

鉴于我正在使用Nokogiri(使用libxml2),我只能使用XPath 1.0表达式.

虽然需要一个棘手的XPath表达式,但是在Nokogiri文档上执行相同操作的Ruby代码/迭代也是可以接受的.

请注意,CSS 相邻兄弟选择器忽略非元素节点,因此选择nokodoc.css('code + code')将错误地选择最后一个<code>块.

Nokogiri.XML('<r><a/><b/> and <c/></r>').css('* + *').map(&:name)
#=> ["b", "c"]
Run Code Online (Sandbox Code Playgroud)

编辑:更多测试用例,为清楚起见:

<section><ul>
  <li>Go to <code>N</code> and
      then <code>Y</code><code>Y</code><code>Y</code>.
  </li>
  <li>If you see <code>N</code> or <code>N</code> then…</li>
</ul>
<p>Elsewhere there might be: <code>N</code></p>
<p><code>N</code> across parents.</p>
<p>Then: <code>Y</code> <code>Y</code><code>Y</code> and <code>N</code>.</p>
<p><code>N</code><br/><code>N</code> elements interrupt, too.</p>
</section>
Run Code Online (Sandbox Code Playgroud)

Y应选择以上所有内容.没有N应该被选中.其内容<code>仅用于指示应选择的内容:您不能使用内容来确定是否选择元素.

出现的上下文元素<code>无关紧要.它们可能出现在<li>,它们可能出现在<p>,它们可能出现在其他东西中.

我想<code>一次选择所有连续运行.在其中一组中间有一个空格字符并不是一个错误Y.

Dim*_*hev 4

使用

\n\n
//code\n     [preceding-sibling::node()[1][self::code]\n    or\n      preceding-sibling::node()[1]\n         [self::text()[not(normalize-space())]]\n     and\n      preceding-sibling::node()[2][self::code]\n    or\n     following-sibling::node()[1][self::code]\n    or\n      following-sibling::node()[1]\n         [self::text()[not(normalize-space())]]\n     and\n      following-sibling::node()[2][self::code]\n     ]\n
Run Code Online (Sandbox Code Playgroud)\n\n

基于 XSLT 的验证

\n\n
<xsl:stylesheet version="1.0"\n     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">\n     <xsl:output omit-xml-declaration="yes" indent="yes"/>\n\n     <xsl:template match="/">\n      <xsl:copy-of select=\n       "//code\n             [preceding-sibling::node()[1][self::code]\n            or\n              preceding-sibling::node()[1]\n                 [self::text()[not(normalize-space())]]\n             and\n              preceding-sibling::node()[2][self::code]\n            or\n             following-sibling::node()[1][self::code]\n            or\n              following-sibling::node()[1]\n                 [self::text()[not(normalize-space())]]\n             and\n              following-sibling::node()[2][self::code]\n             ]"/>\n     </xsl:template>\n</xsl:stylesheet>\n
Run Code Online (Sandbox Code Playgroud)\n\n

当此转换应用于提供的 XML 文档时:

\n\n
<section><ul>\n      <li>Go to <code>N</code> and\n          then <code>Y</code><code>Y</code><code>Y</code>.\n      </li>\n      <li>If you see <code>N</code> or <code>N</code> then\xe2\x80\xa6</li>\n    </ul>\n    <p>Elsewhere there might be: <code>N</code></p>\n    <p><code>N</code> across parents.</p>\n    <p>Then: <code>Y</code> <code>Y</code><code>Y</code> and <code>N</code>.</p>\n    <p><code>N</code><br/><code>N</code> elements interrupt, too.</p>\n</section>\n
Run Code Online (Sandbox Code Playgroud)\n\n

计算包含的 XPath 表达式,并将选定的节点复制到输出:

\n\n
<code>Y</code>\n<code>Y</code>\n<code>Y</code>\n<code>Y</code>\n<code>Y</code>\n<code>Y</code>\n
Run Code Online (Sandbox Code Playgroud)\n