40474


非常に基本的なことなのでしょうけれども掲題の違いがわかりません．例えば次のようなXMLがあったとします．

[code]

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
        <item attr1="val1" attr2="val2">
            <item attr3="val3">
                <item attr4="val4">
                    <item attr5="val5"/>
                </item>
            </item>
        </item>
    </root>
    
[/code]

これに対して次のようなスタイルシートを適用すると

[code]

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="xs"
        version="2.0">
        <xsl:output indent="yes"/>
    
        <xsl:template match="/">
            <root>
                <p1-1>
                    <xsl:copy-of select="//item"/>
                </p1-1>
                <p1-2>
                    <xsl:copy-of select="descendant-or-self::item"/>
                </p1-2>
            </root>
        </xsl:template>
    </xsl:stylesheet>
    
[/code]

p1-1とp1-2には同じ次の内容のノードが選択されます．

[code]

      <item attr1="val1" attr2="val2">
               <item attr3="val3">
                     <item attr4="val4">
                           <item attr5="val5"/>
                     </item>
               </item>
         </item>
      <item attr3="val3">
                  <item attr4="val4">
                        <item attr5="val5"/>
                  </item>
            </item>
      <item attr4="val4">
                     <item attr5="val5"/>
               </item>
      <item attr5="val5"/>
    
[/code]

ところがこれを

[code]

    <xsl:template match="/">
        <root>
            <p1-1>
                <xsl:copy-of select="//item[1]"/>
            </p1-1>
            <p1-2>
                <xsl:copy-of select="descendant-or-self::item[1]"/>
            </p1-2>
        </root>
    </xsl:template>
    
[/code]

と変えると

[code]

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
       <p1-1>
          <item attr1="val1" attr2="val2">
              <item attr3="val3">
                  <item attr4="val4">
                       <item attr5="val5"/>
                  </item>
               </item>
          </item>
          <item attr3="val3">
              <item attr4="val4">
                  <item attr5="val5"/>
              </item>
          </item>
          <item attr4="val4">
              <item attr5="val5"/>
          </item>
          <item attr5="val5"/>
       </p1-1>
       <p1-2>
           <item attr1="val1" attr2="val2">
               <item attr3="val3">
                   <item attr4="val4">
                       <item attr5="val5"/>
                   </item>
               </item>
           </item>
       </p1-2>
    </root>
    
[/code]

という結果となります．predicate（述語）の[1]は異なる結果をもたらします．

XPathの仕様によれば簡略記述の//item[1]は(fn:root(self::node()) treat as document-
node())/descendant-or-self::node()/child::item[1]に等しくなります．

[3.2 Path Expressions](https://www.w3.org/TR/xpath20/#doc-xpath-PathExpr)

> A "//" at the beginning of a path expression is an abbreviation for the
> initial steps (fn:root(self::node()) treat as document-node())/descendant-
> or-self::node()/ (however, "//" by itself is not a valid path expression
> [err:XPST0003].)

すこしややこしいですが、簡単に言えばドキュメントノードの位置から見てdescendant-or-
self::node()/child::item[1]とdescendant-or-self::item[1]はどう違うのか？

ということになるでしょうか？なぜ両者が異なる結果となるのかがよくわかりません．

説明いただける方おられましたらよろしくお願いいたします．

［追記］  
ちなみに仕様には違う結果になると書いてあります．

[3.3.5 Abbreviated Syntax](https://www.w3.org/TR/xpath-31/#abbrev)

> Note:The path expression //para[1] does not mean the same as the path
> expression /descendant::para[1]. The latter selects the first descendant
> para element; the former selects all descendant para elements that are the
> first para children of their respective parents.


CC BY-SA 3.0
2017-12-21T12:25:44.047
40447
2017-12-22T06:28:28.753
2017-12-22T05:08:21.900
9503
9503
question
xml xpath xsl
XPathの//item[1]とdescendant-or-self::item[1]の違い


`descendant-or-self::node()/child::item[1]` を２段階に分けるとすると、

「まず `descendant-or-self::node()/child::item` を選んで、次にそこから `[1]` を選ぶ」ではありません。  
「まず `descendant-or-self::node()` を選んで、次にそこから `child::item[1]` を選ぶ」です。

つまり、

[code]

    <xsl:copy-of select="//item[1]"/>
    
[/code]

が行っていることは

[code]

    <xsl:variable as="element(item)*" name="items" select="descendant-or-self::node()/child::item" />
    <xsl:copy-of select="$items[1]" />
    
[/code]

のようなものではありません。むしろ

[code]

    <xsl:for-each select="descendant-or-self::node()">
        <xsl:copy-of select="child::item[1]" />
    </xsl:for-each>
    
[/code]

のようなものです。

* * *

要は、記号の優先順位に従って式を分割し、順に考えるだけです。

### `descendant-or-self::item[1]` について考えると

context node から descendant-or-self 方向に見える 1 番目の `item` element を探します。  
質問文の例では、`/root/item` が見つかります。それをピックアップして終了です。

### `descendant-or-self::node()/child::item[1]` について考えると

`/` は `[]` より弱いので、全体の式はおよそ `descendant-or-self::node()`, `/`, `child::item[1]`
に分割されます。これを順に考えていきます。

まず、`descendant-or-self::node()` で、context node から `descendant-or-self::node()`
に該当する node すべて（`/root`, `/root/item`, `/root/item/item`,
`/root/item/item/item` …など）を抽出します。

次に、`/` で、抽出した node 一つ一つに視点の出発点を移します。

最後に、`child::item[1]` で、各視点から、child 方向に見える 1 番目の `item` element を探します。  
`/root` から見て child 方向に見える 1 番目の `item` element をピックアップする。  
`/root/item` から見て child 方向に見える 1 番目の `item` element もピックアップする。  
`/root/item/item` から見て child 方向に見える 1 番目の `item` element もまたピックアップする…。  
`/root/item/item/item` から見て child 方向に見える 1 番目の `item` element もまたまたピックアップする…。  
これを最初の `descendant-or-self::node()` で抽出した node すべてに対して行います。


CC BY-SA 3.0
2017-12-21T15:15:45.783
40459
2017-12-22T06:28:28.753
2017-12-22T06:28:28.753
26271
26271
40447
answer


> descendant-or-
> self::node()/child::item[1]は、子要素中のp‌​ositionなので常にprecedin‌​g-siblingで先頭から何番目か？d‌​‌​escendant-
> or-self:‌​:i‌​tem[1]は、コンテキストは各‌​子孫のitemなので、ともかくd‌​es‌​cendant-or-
> self::i‌​‌​temの１番目、preceding-si‌​blingなんて関係ない．という解釈でし‌​ょうか？

でいいと思います。一言で言えば、「述語`[1]`の付くのがグループかどうか？」となりそうです。

`//item[1]` = `descendant-or-self::node()/child::item[1]`

すでに @SOTH さんが述べてますが、`descendant-or-self::node()/child::item[1]`は、「まず
descendant-or-self::node() を選んで、次にそこから child::item[1]
を選ぶ」なので、各兄弟要素中で最初に出現する`item`要素がすべて選択されます。長子要素の集合が結果になり、サンプルでも複数の`item`要素が選択されています。

* * *

`descendant-or-self::item[1]` = `(descendant-or-self::item)[1]` =
`(//item)[1]` = `(descendant-or-self::node()/child::item)[1]`

対して`descendant-or-self::item[1]`は、「まず `descendant-or-self::item`
を選んでその結果グループの中から先頭の要素を述語`[1]`で選ぶ」です。グループの中から常に1個の要素を選ぶ訳ですから、サンプルでも1個の`item`要素‌​のみ選択されています。

* * *

まとめると、以下のようになります。

  * `//item[1]`と`(//item)[1]`は述語の付く対象が異なる 
    * `//item[1]`は任意の`item[1]`を選択
    * `(//item)[1]`は`item`グループの先頭を選択


CC BY-SA 3.0
2017-12-22T06:18:03.100
40474
2017-12-22T06:18:03.100
46
40447
answer