2

次のようなXMLフラグメントがあります

<main>
    <sub1>
        <element>
            <sub2>
                <element>
                    <sub3/>
                </element>
            </sub2>
        </element>
    </sub1>
    <sub4>
        <sub5>
            <element>
                <sub6>
                    <element>
                        <sub7/>
                    </element>
                </sub6>
            </element>
        </sub5>
    </sub4>
    <sub8>
        <element/>
    </sub8>
</main>

main が現在のノードの場合、次のようにすべての要素ノードを選択できます。

select=".//element"

これにより、この例では 5 つの一致が得られます。しかし、階層内の最初の要素ノードのみを選択するにはどうすればよいのでしょうか? 元のメインノードとの間に別の要素があるすべての要素を無視する必要があります。

中間のサブノードの数は、上記の例のように 1 つまたは 2 つを超える場合があり、この例のメイン ノードは、上記の別の要素ノードの一部である場合があります。

ありがとうK

4

3 に答える 3

2

可能な式は次のようになります

.//element[not(ancestor::element)]

つまり、別の「要素」要素によって(どのレベルでも)囲まれていないすべての「要素」要素を検索します。

編集

前述のように、現在の(main)要素自体が「要素」で囲まれている場合、この式はそのままでは機能しません。XSLTを使用していて、関数にアクセスcurrent()できる場合は、次のようなトリックを使用できます。

.//element[count(ancestor::element) = count(current()/ancestor::element)]

これは、現在の「メイン」要素と同じ数の「要素」要素を含む要素を選択します(ゼロの場合もあります)。プロセッサによっては、変数を使用する方が効率的および/または明確な場合があります

<xsl:variable name="depth" select="count(ancestor::element)" />
<xsl:apply-templates select=".//element[count(ancestor::element) = $depth]"/>
于 2012-09-03T21:58:03.777 に答える
1

この回答は、問題の一部として指定されていない「メイン」という名前の他の要素が存在しないことを想定していないため、ディミトレの回答よりも少し厳密だと思います。

for $this in . return .//element[empty(ancestor::element[.>>$this])]

XSLT を使用している場合は、$this の代わりに current() を使用できます。

于 2012-09-04T07:46:44.327 に答える
1

使用:

.//element[(ancestor::main|ancestor::element)[last()][self::main]]

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:for-each select=
   ".//element
       [(ancestor::main|ancestor::element)
                          [last()][self::main]
       ]">
   <xsl:copy-of select="."/>
==================
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

この変換が提供された XML ドキュメントに適用されると、次のようになります。

<main>
    <sub1>
        <element>
            <sub2>
                <element>
                    <sub3/>
                </element>
            </sub2>
        </element>
    </sub1>
    <sub4>
        <sub5>
            <element>
                <sub6>
                    <element>
                        <sub7/>
                    </element>
                </sub6>
            </element>
        </sub5>
    </sub4>
    <sub8>
        <element/>
    </sub8>
</main>

Xpath 式は、現在のノードをドキュメントの最上位ノードとして評価され、この評価の結果は、便利な区切り文字列を使用して出力にコピーされます。

<element>

   <sub2>

      <element>

         <sub3/>

      </element>

   </sub2>

</element>
==================
  <element>

   <sub6>

      <element>

         <sub7/>

      </element>

   </sub6>

</element>
==================
  <element/>
==================

説明:

表現:

    .//element
       [(ancestor::main|ancestor::element)
                                     [last()]
                                        [self::main]
       ]

現在のノードのすべての子孫element要素を選択し、2 つの可能な祖先 (上向き)mainまたはelementisの最初のものを選択しますmain

つまりelement、selected の祖先であり、祖先のelement前に (上に向かって) 発生する はありませんmain

last()が だけでなく述語として使用される理由を理解する[1]には、2 つの先祖の中で最も近いものが文書順で最後であることを覚えておく必要があります。

注意してください:

この XPath 式は、現在のノード自体が先祖elementを持つ場合でも、必要なすべての要素を正しく選択します。element

Ian Roberts による回答で提案されたような表現:

.//element[not(ancestor::element)] 

この場合、何も選択しません


更新

Michael Kay が指摘したように、この問題をさらに一般化し、他のmain要素をドキュメントのどこにでも表示できるようにすると、この回答で提案されている表現は「誤検知」を選択する可能性があります。

current()以下は、この状況でも正しいカウントを生成する更新された式 (XSLT 関数を使用するため、純粋な/スタンドアロンの XPath 式ではなくなりました)です。

.//element
   [(ancestor::main|ancestor::element)
                      [last()][self::main]
  and
    count(current()|ancestor::main[1]) = 1
   ]"/>
于 2012-09-03T21:56:48.727 に答える