1

次のマークアップがあります。TR と 1 つまたは 2 つの子 TD が混在するテーブルです。

  <table>
    <tr>
      <td>
         <p>XXX</p>
      </td>
    </tr>
    <tr>
      <td>
        <p>YYYYYY</p>
      </td>
      <td>
        <p>YYYYYY</p>
      </td>
    </tr>
    <tr>
      <td>
        <p>YYYYYY</p>
      </td>
      <td>
        <p>YYYYYY</p>
      </td>
    </tr>
    <tr>
      <td>
        <p>YYYYYY</p>
      </td>
      <td>
        <p>YYYYYY</p>
      </td>
    </tr>
    <tr>
      <td>
        <p>XXX</p>
      </td>
    </tr>
    <tr>
      <td>
        <p>YYYYYY</p>
      </td>
      <td>
        <p>YYYYYY</p>
      </td>
    </tr>
    <tr>
      <td>
        <p>YYYYYY</p>
      </td>
      <td>
        <p>YYYYYY</p>
      </td>
    </tr>
    <tr>
      <td>
        <p>XXX</p>
      </td>
    </tr>
    <tr>
      <td>
        <p>YYYYYY</p>
      </td>
      <td>
        <p>YYYYYY</p>
      </td>
    </tr>
    <tr>
      <td>
        <p>YYYYYY</p>
      </td>
      <td>
        <p>YYYYYY</p>
      </td>
    </tr>
  </table>

XSLT 1.0 を使用してこれを変換しようとしています

<AAA>
  XXX
  <BBB>YYYYY</BBB>
  <BBB>YYYYY</BBB>
  ...
</AAA>
<AAA>
  XXX
  <BBB>YYYYY</BBB>
  <BBB>YYYYY</BBB>
  ...
</AAA>
...

これがおそらく XSLT でネストされたループにアプローチする最善の方法であるという事実から抽象化すると、どの XPath 式が ??? に入れられますか? 以下は、2 つの TD 子を持つ現在の TR (XXX) のすべての TR 兄弟を選択しますが、次の TR (XXX) までのみ選択します。XXX と YYYYY を含むノードを、TD の子の数に基づいて区別しています。1 = XXX、2 = YYYYY。

<xsl:for-each select="//table/tr">
   <xsl:if test="count(td) = '1'">
      XXX
   </xsl:if>
   <xsl:for-each select="???">
      all YYYYY up until the next XXX
   </xsl:for-each>
</xsl:for-each>

私は "following-sibling::tr[child::td[following-sibling::td]" を持っていますが、それは最後まで YYYYY を持つ次のすべてに一致します - XXX を持つ次の TR までのものだけを選択するにはどうすればよいですか? ?

ありがとう!

4

2 に答える 2

1

I. 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:strip-space elements="*"/>

 <xsl:key name="kFollowing" match="tr[td[2]]"
  use="generate-id(preceding-sibling::tr
                                  [not(td[2])]
                                     [1]
                   )"/>

 <xsl:template match="/*">
   <xsl:apply-templates select="tr[not(td[2])]"/>
 </xsl:template>

 <xsl:template match="tr[not(td[2])]">
  <AAA>
    <xsl:value-of select="concat('&#xA;', td/p, '&#xA;')"/>

    <xsl:apply-templates select="key('kFollowing', generate-id())"/>
  </AAA>
 </xsl:template>

 <xsl:template match="p">
  <BBB><xsl:value-of select="."/></BBB>
 </xsl:template>
</xsl:stylesheet>

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

<table>
    <tr>
        <td>
            <p>XXX</p>
        </td>
    </tr>
    <tr>
        <td>
            <p>YYYYYY</p>
        </td>
        <td>
            <p>YYYYYY</p>
        </td>
    </tr>
    <tr>
        <td>
            <p>YYYYYY</p>
        </td>
        <td>
            <p>YYYYYY</p>
        </td>
    </tr>
    <tr>
        <td>
            <p>YYYYYY</p>
        </td>
        <td>
            <p>YYYYYY</p>
        </td>
    </tr>
    <tr>
        <td>
            <p>XXX</p>
        </td>
    </tr>
    <tr>
        <td>
            <p>YYYYYY</p>
        </td>
        <td>
            <p>YYYYYY</p>
        </td>
    </tr>
    <tr>
        <td>
            <p>YYYYYY</p>
        </td>
        <td>
            <p>YYYYYY</p>
        </td>
    </tr>
    <tr>
        <td>
            <p>XXX</p>
        </td>
    </tr>
    <tr>
        <td>
            <p>YYYYYY</p>
        </td>
        <td>
            <p>YYYYYY</p>
        </td>
    </tr>
    <tr>
        <td>
            <p>YYYYYY</p>
        </td>
        <td>
            <p>YYYYYY</p>
        </td>
    </tr>
</table>

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

<AAA>
XXX
<BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
</AAA>
<AAA>
XXX
<BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
</AAA>
<AAA>
XXX
<BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
</AAA>

説明:

キーを適切に使用して、直前の単一の子要素の関数としてtr2 番目の子を持つすべてを定義します。tdgenerate-id()tr


Ⅱ.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:strip-space elements="*"/>

 <xsl:template match="/*">
  <xsl:for-each-group group-starting-with="tr[not(td[2])]"
       select="tr">
    <xsl:apply-templates select="current-group()[1]"/>
  </xsl:for-each-group>
 </xsl:template>

 <xsl:template match="tr[not(td[2])]">
  <AAA>
    <xsl:value-of select="concat('&#xA;', td/p, '&#xA;')"/>

    <xsl:apply-templates select="current-group()[position() gt 1]"/>
  </AAA>
 </xsl:template>

 <xsl:template match="p">
  <BBB><xsl:value-of select="."/></BBB>
 </xsl:template>
</xsl:stylesheet>

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

<AAA>
XXX
<BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
</AAA>
<AAA>
XXX
<BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
</AAA>
<AAA>
XXX
<BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
   <BBB>YYYYYY</BBB>
</AAA>

説明:

xsl:for-each-groupwithgroup-starting-with属性とcurrent-group()関数の適切な使用。

于 2012-04-17T01:50:04.427 に答える
0

私は常に、あなたが求めていることを正確に実行する XPath コンストラクトがあると便利だと考えてきました。シーケンス内のすべての項目から、最初に条件に一致する項目まで (および含めたり除外したりします)。などの構文を検討しましたexpr until condition。Saxon と EXSLT では、saxon:leading() などの要件を満たすために高次の拡張関数を提供する試みがあります。残念ながら、仕様には何もありません。ただし、XPath 3.0 では、高階関数を使用してかなり簡単に実行できます。

グループ化 (xsl:for-each-group) を使用して問題を解決できる場合もありますが、多くの場合、最も単純で最も洗練されたアプローチは再帰を使用することです。つまり、シーケンスの最初の項目を処理し、それ自体を呼び出していくつかの条件が真である場合、次のアイテムを処理します。

もう 1 つの方法は、条件に一致する最初のノードのシーケンスを検索し、subsequence() を使用してその位置までのノードを選択することです。

<xsl:variable name="positions" select="
  for $i in 1 to count($seq)
  return if (my:condition($seq[$i])) then $i else ()"/>
<xsl:apply-templates select="subsequence($seq, 1, $positions[1])"/>
于 2012-04-17T07:18:11.413 に答える