5

次のようなマークアップを指定します。

<p>
  <code>foo</code><code>bar</code>
  <code>jim</code> and then <code>jam</code>
</p>

最初の3つを選択する必要がありますが<code>、最後は選択しません。ロジックは、「空白以外のコンテンツを含むテキストノードが1つ以上存在しない限りcode、前後の兄弟要素がであるすべての要素を選択します。code

Nokogiri(libxml2を使用)を使用している場合、XPath1.0式のみを使用できます。

トリッキーなXPath式が望まれますが、Nokogiriドキュメントで同じことを実行するためのRubyコード/反復も許容されます。

CSS隣接兄弟セレクターは非要素ノードを無視するため、選択するnokodoc.css('code + code')と最後の<code>ブロックが誤って選択されることに注意してください。

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

編集:明確にするために、より多くのテストケース:

<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…&lt;/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>

上記のすべてYを選択する必要があります。いずれNも選択しないでください。の内容は、<code>どちらを選択するかを示すためにのみ使用されます。要素を選択するかどうかを決定するために内容を使用することはできません。

表示されるコンテキスト要素<code>は関係ありません。それらはに表示される場合があり<li>、に表示される<p>場合があり、他の何かに表示される場合があります。

<code>の連続したすべての実行を一度に選択したい。のセットの1つの中央にスペース文字があることは間違いではありませんY

4

3 に答える 3

4

使用

//code
     [preceding-sibling::node()[1][self::code]
    or
      preceding-sibling::node()[1]
         [self::text()[not(normalize-space())]]
     and
      preceding-sibling::node()[2][self::code]
    or
     following-sibling::node()[1][self::code]
    or
      following-sibling::node()[1]
         [self::text()[not(normalize-space())]]
     and
      following-sibling::node()[2][self::code]
     ]

XSLTベースの検証

<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>

     <xsl:template match="/">
      <xsl:copy-of select=
       "//code
             [preceding-sibling::node()[1][self::code]
            or
              preceding-sibling::node()[1]
                 [self::text()[not(normalize-space())]]
             and
              preceding-sibling::node()[2][self::code]
            or
             following-sibling::node()[1][self::code]
            or
              following-sibling::node()[1]
                 [self::text()[not(normalize-space())]]
             and
              following-sibling::node()[2][self::code]
             ]"/>
     </xsl:template>
</xsl:stylesheet>

この変換が提供されたXMLドキュメントに適用される場合:

<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…&lt;/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>

含まれているXPath式が評価され、選択したノードが出力にコピーされます。

<code>Y</code>
<code>Y</code>
<code>Y</code>
<code>Y</code>
<code>Y</code>
<code>Y</code>
于 2012-06-26T04:07:42.400 に答える
3
//code[
  (
    following-sibling::node()[1][self::code]
    or (
      following-sibling::node()[1][self::text() and normalize-space() = ""]
      and
      following-sibling::node()[2][self::code]
    )
  )
  or (
    preceding-sibling::node()[1][self::code]
    or (
      preceding-sibling::node()[1][self::text() and normalize-space() = ""]
      and
      preceding-sibling::node()[2][self::code]
    )
  )
]

あなたが実際にそれを使いたいとは言いませんが、これはあなたが望むことをするだろうと思います。

テキストノードは常にマージされ、2つが隣接しないようになっていると思います。これは一般的に当てはまると思いますが、事前にDOM操作を行っている場合はそうではない可能性があります。codeまた、要素間に他の要素がないこと、または要素がある場合は空白以外のテキストのように選択できないことも想定しています。

于 2012-06-26T00:24:04.840 に答える
1

私はこれがあなたが望むものだと思います:

/p/code[not(preceding-sibling::text()[not(normalize-space(.)="")])]
于 2012-06-25T23:46:43.263 に答える