1
<div n="a">
  . . . 
    . . .
      <spec>red</spec>
      <div n="d">
          . . . 
      </div>
      <spec>green</spec>
      . . .
         <div n="b">
            . . .
              <spec>blue</spec>
            . . .
         </div>
         <div n="c">
           <spec>yellow</spec>
         </div>
      . . .
    . . .
  . . .
</div>

[ショーンが気付いたあいまいさを取り除くために編集されました。 - ありがとう]

現在の要素が の場合<div n="a">、青と黄色の要素ではなく、赤と緑の要素を返す XPATH 式が必要.//specです。

現在の要素が の<div n="b">場合、同じ式で青色の要素を返す必要があります。の場合<div n="c">、黄色の要素。

何かのようなもの.//spec[but no deeper than another div if there is one]

4

2 に答える 2

3

XSLT 1.0 では、現在のノードが であると仮定しますdiv

.//spec[generate-id(current())=generate-id(ancestor::div[1])]

XSLT 2.0 では、同じ仮定の下で:

.//spec[ancestor::div[1] is current()]

そして、純粋な XPath 2.0 式:

for $this in .
     return
        $this//spec[ancestor::div[1] is $this]

完全な XSLT 1.0 変換:

<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="div">
  <div n="{@n}"/>
  <xsl:copy-of select=
   ".//spec[generate-id(current())=generate-id(ancestor::div[1])]"/>
==============
  <xsl:apply-templates/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

提供された XML ドキュメントに適用した場合:

<div n="a">
  . . .
    . . .
      <spec>red</spec>
      <spec>green</spec>
      . . .
         <div n="b">
            . . .
              <spec>blue</spec>
            . . .
         </div>
         <div n="c">
           <spec>yellow</spec>
         </div>
      . . .
    . . .
  . . .
</div>

必要な正しい結果が生成されます。

<div n="a"/>
<spec>red</spec>
<spec>green</spec>
==============
  <div n="b"/>
<spec>blue</spec>
==============
  <div n="c"/>
<spec>yellow</spec>
==============

完全な XSLT 2.0 変換:

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

 <xsl:template match="div">

  <div n="{@n}"/>
  <xsl:sequence select=".//spec[ancestor::div[1] is current()]"/>
===================================
  <xsl:apply-templates/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

同じ XML ドキュメント (上記) に適用すると、同じ正しい結果が生成されます。

<div n="a"/>
<spec>red</spec>
<spec>green</spec>
===================================
  <div n="b"/>
<spec>blue</spec>
===================================
  <div n="c"/>
<spec>yellow</spec>
===================================

純粋な XPath 2.0 を使用する (no current()):

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

 <xsl:template match="div">

  <div n="{@n}"/>
  <xsl:sequence select="
    for $this in .
     return
        $this//spec[ancestor::div[1] is $this]"/>
===================================
  <xsl:apply-templates/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

同じ正しい結果が生成されます

<div n="a"/>
<spec>red</spec>
<spec>green</spec>
===================================
  <div n="b"/>
<spec>blue</spec>
===================================
  <div n="c"/>
<spec>yellow</spec>
===================================
于 2012-10-15T03:05:12.437 に答える
1

XSLT 1.0 を使用していて、'spec' の子、すべての子を選択し、目的の 'current' ノードを XSLT フォーカス ノードとして選択すると仮定すると、次の変数を設定します...

<xsl:variable name="divs" select="*//div" />

これで、この XPath 式を使用しspecて、子孫が前にないすべての子孫を選択できます...div

//spec[not((preceding::div|ancestor::div)[count(. | $divs) = count($divs)])]

警告

これはうまくいくはずですが、私はそれをテストしていません。この注意を払って、OP がテストするための演習として残します。

ノート

追加の変数を宣言する必要のない XPath 式がどうしても必要であり、幸運にも現在のノードをノードセット ($ref と呼びましょう) に保持している場合は、このかなり非効率的な XPath 式...

$ref//spec[not((preceding::div|ancestor::div)[count(. | $ref/*//div) =
                                              count(    $ref/*//div)  ])]

補遺

これは、コメント ストリームを参照している可能性のあるテスト ケースです。

テスト ケース 1 入力:

<div n="a">
      <spec>red</spec>
      <div n="x"/>
      <spec>green</spec>
      <div n="b">
        <spec>blue</spec>
      </div>
      <div n="c">
        <spec>yellow</spec>
      </div>
</div>

テスト ケース 1 期待される出力:

  • ただあるべきred
于 2012-10-15T03:05:10.923 に答える