5

これは、XPathが何らかの条件まですべての兄弟を返すという一般的な要求の変形であり、XPath軸でDimitre Novatchevによって特徴的な完全性で応答され、このパターンを使用するまで後続のすべてのノードを取得します。

$x/following-sibling::p
   [1 = count(preceding-sibling::node()[name() = name($x)][1] | $x)]

following-siblingしかし、そのパターンは、との対称性preceding-sibling、軸に沿って両方向を見る能力に依存しています。

軸がである場合、同等のパターンはありancestor-or-selfますか?

例えば:

<t>
  <a xml:base="/news/" >
    <b xml:base="reports/">
      <c xml:base="politics/" />
      <c xml:base="sports/" >
        <d xml:base="reports/" />
        <d xml:base="photos/" >
          <img url="A1.jpg" />
          <img url="A2.jpg" />
        </d>
      </c>
      <c xml:base="entertainment" />
    </b>
  </a>
</t>

簡単な

<xsl:template match="img">

    <xsl:for-each select="ancestor-or-self::*[@xml:base]">
        <xsl:value-of select="@xml:base"/>
    </xsl:for-each>

    <xsl:value-of select="@url"/>

</xsl:template>

戻るだろう

 /news/reports/sports/photos/A1.jpg
 /news/reports/sports/photos/A1.jpg

しかし、

      <c xml:base="sports/" >

代わりに

      <c xml:base="/sports/" >

その先導/で、for-each戻るために停止する必要があります

 /sports/photos/A1.jpg
 /sports/photos/A2.jpg

(XSLT / XPath 1.0では)どのように停止させますか?

4

4 に答える 4

3

このXSLT1.0変換

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

 <xsl:param name="pWanted" select="//img"/>
 <xsl:param name="pWantedAttr" select="'url'"/>

 <xsl:template match="/">
     <xsl:apply-templates select="$pWanted"/>
 </xsl:template>

 <xsl:template match="*[not(starts-with(@xml:base, '/'))]">
  <xsl:apply-templates select="ancestor::*[@xml:base][1]"/>
  <xsl:value-of select="concat(@xml:base,@*[name()=$pWantedAttr])"/>
  <xsl:if test="not(@xml:base)"><xsl:text>&#xA;</xsl:text></xsl:if>
 </xsl:template>

 <xsl:template match="*[starts-with(@xml:base, '/')]">
  <xsl:value-of select="@xml:base"/>
 </xsl:template>
</xsl:stylesheet>

このXMLドキュメントに適用した場合

<t>
  <a xml:base="/news/" >
    <b xml:base="reports/">
      <c xml:base="politics/" />
      <c xml:base="/sports/" >
        <d xml:base="reports/" />
        <d xml:base="photos/" >
          <img url="A1.jpg" />
          <img url="A2.jpg" />
        </d>
      </c>
      <c xml:base="entertainment" />
    </b>
  </a>
</t>

必要な正しい結果を生成します。

/sports/photos/A1.jpg
/sports/photos/A2.jpg

更新-単一のXPath2.0式ソリューション

   for $target in //img,
       $top in $target/ancestor::*[starts-with(@xml:base,'/')][1]
    return
      string-join(
         (
             $top/@xml:base
           , $top/descendant::*
                [@xml:base and . intersect $target/ancestor::*]
                   /@xml:base
           , $target/@url,
           '&#xA;'
        ),
        ''
                )

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="/">
     <xsl:sequence select=
      "for $target in //img,
           $top in $target/ancestor::*[starts-with(@xml:base,'/')][1]
        return
          string-join(
             (
                 $top/@xml:base
               , $top/descendant::*
                    [@xml:base and . intersect $target/ancestor::*]
                       /@xml:base
               , $target/@url,
               '&#xA;'
            ),
            ''
                    )
      "/>
 </xsl:template>
</xsl:stylesheet>

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

<t>
  <a xml:base="/news/" >
    <b xml:base="reports/">
      <c xml:base="politics/" />
      <c xml:base="sports/" >
        <d xml:base="reports/" />
        <d xml:base="photos/" >
          <img url="A1.jpg" />
          <img url="A2.jpg" />
        </d>
      </c>
      <c xml:base="entertainment" />
    </b>
  </a>
</t>

XPath式が評価され、この評価の結果が出力にコピーされます。

/news/reports/sports/photos/A1.jpg
 /news/reports/sports/photos/A2.jpg

変更されたドキュメントの場合

<t>
  <a xml:base="/news/" >
    <b xml:base="reports/">
      <c xml:base="politics/" />
      <c xml:base="/sports/" >
        <d xml:base="reports/" />
        <d xml:base="photos/" >
          <img url="A1.jpg" />
          <img url="A2.jpg" />
        </d>
      </c>
      <c xml:base="entertainment" />
    </b>
  </a>
</t>

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

/sports/photos/A1.jpg
 /sports/photos/A2.jpg

Update2

OPは、この単純化を提案しています。

元の投稿者によって追加された更新:完全なURLが相対URLに置き換わった完全なアプリケーションに埋め込まれると、Dimitreのアプローチはこの単純なものになりました

<xsl:template match="@url">
    <xsl:attribute name="url">
        <xsl:apply-templates mode="uri" select=".." />
        <xsl:value-of select="."/>
    </xsl:attribute>
</xsl:template>

<xsl:template match="*"  mode="uri">
    <xsl:if test="not(starts-with(@xml:base, '/'))">
        <xsl:apply-templates select="ancestor::*[@xml:base][1]" mode="uri"/>
    </xsl:if>
    <xsl:value-of select="@xml:base"/>
</xsl:template>
于 2013-01-05T02:47:30.803 に答える
2

単一のfor-eachselect式で適切なノードを選択する方法があります。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="img">
    <xsl:for-each select="
      ancestor-or-self::*[
        starts-with(@xml:base, '/')
      ][1]/descendant-or-self::*[
        @xml:base and .//img[generate-id() = generate-id(current())]
      ]">
      <xsl:value-of select="@xml:base"/>
    </xsl:for-each>

    <xsl:value-of select="@url"/>
  </xsl:template>

</xsl:stylesheet>

この入力XMLが与えられた場合:

<t>
  <a xml:base="/news/" >
    <b xml:base="reports/">
      <c xml:base="politics/" />
      <c xml:base="/sports/" >
        <d xml:base="reports/" />
        <d xml:base="photos/" >
          <img url="A1.jpg" />
          <img url="A2.jpg" />
        </d>
      </c>
      <c xml:base="entertainment" />
    </b>
  </a>
</t>

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

/sports/photos/A1.jpg
/sports/photos/A2.jpg

@xml:baseXPath式は、「スラッシュで始まる最も近い祖先から始めて、その祖先と、その子孫の1つとして現在を持っているすべての子孫を選択する」と読み取ることができ<img>ます。

これにより、XMLツリーへの正しいパスが1つだけ効果的に選択されます。

于 2013-01-05T08:47:14.357 に答える
0

私はそれを見つけました: for-eachループに入るに、条件を満たす祖先を数えます。各候補をテストして、条件が一致する祖先の数が同じであるかどうかを確認します。

このスタイルシート

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:template match="img">

        <xsl:variable name="distance" select="count(ancestor-or-self::*[@xml:base][substring(@xml:base,1,1)='/'])" />

        <xsl:for-each select="ancestor-or-self::*[@xml:base][
            count(ancestor-or-self::*[@xml:base][substring(@xml:base,1,1)='/'])=$distance
            ]">
                <xsl:value-of select="@xml:base"/>
        </xsl:for-each>

        <xsl:value-of select="@url"/>

    </xsl:template>

</xsl:stylesheet>

指定されたXMLに適用されます

<t>
    <a xml:base="/news/" >
        <b xml:base="reports/">
            <c xml:base="politics/" />
            <c xml:base="/sports/" >
                <d xml:base="reports/" />
                <d xml:base="photos/" >
                    <img url="A1.jpg" />
                    <img url="A2.jpg" />
                </d>
            </c>
            <c xml:base="entertainment" />
        </b>
    </a>
</t>

目的の結果を返します。

                /sports/photos/A1.jpg
                /sports/photos/A2.jpg

/beforeがないsportsと、for-eachは祖先と一致し/newsます。

                /news/reports/sports/photos/A1.jpg
                /news/reports/sports/photos/A2.jpg
于 2013-01-05T02:51:05.527 に答える
0

元のテンプレートに小さな変更を加えます。

<xsl:template match="img">
    <xsl:for-each select="ancestor-or-self::*[@xml:base][not(.//*[starts-with(@xml:base, '/')])]">
         <xsl:value-of select="@xml:base"/>
    </xsl:for-each>
    <xsl:value-of select="@url"/>
</xsl:template>
于 2013-01-05T09:17:33.323 に答える