2012-04-16 7 views
1

I次のマークアップ、1つのまたは2つの子のTDXPath式は、その子に基づいて、兄弟満たす状態まで、ノードの兄弟に合わせて

<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> 
とのTRのミックスを持つテーブルを持っています

は、私は、これはXSLTでネストされたループ、何のXPath式に入れるにアプローチする最良の方法におそらくであるという事実から抽象化

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

にこれを変換するXSLT 1.0を使用しようとしています?次のTR(XXX)まで2つのTD子を有する現在のTR(XXX)のすべてのTR兄弟を選択する。私は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> 

私が持っている「次-兄弟:: TR [子を:: TD [次-兄弟:: TD】」それはすべての終わりにYYYYYと、次の一致する - どのように私はそれだけでそれらを選択しますかXXXの次のTRまでは?

ありがとうございます!

答えて

1

I. XSLT 1.0溶液

<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変換が提供されるXML文書に適用され

<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> 

<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> 

説明key

適切な使用は、直前の単一の子tr要素のgenerate-id()の関数として第2 td子を持つすべてのtrを定義します。


II。 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-groupgroup-starting-with属性とtの適切な使用彼current-group()機能。

+0

本当に徹底的な答えを、そんなにありがとう:

別のアプローチは、条件に一致する最初のノードのためのシーケンスを検索し、その位置までのノードを選択するために、サブシーケンスを()を使用することです! – WojtekD

+0

@WojtekD:どうぞよろしくお願いいたします。 –

0

私はいつもあなたが求めていることを正確に実行するXPath構造を持つことが有用であると考えていました。私はexpr until conditionのような構文を考えました。 saxon:leading()のように、SaxonとEXSLTで高次の拡張機能を提供する試みがあります。残念ながら、仕様には何もありません。 XPath 3.0では、高次関数を使用してかなり容易に行うことができます。

グループ化(xsl:for-each-group)を使用して問題を解決することもできますが、しばしば単純で最もエレガントな方法は、再帰を使用することです。つまり、シーケンスの最初の項目を処理し、何らかの条件が満たされている場合、次のアイテムを処理するために自身を呼び出します。

<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])"/> 
+0

申し訳ありませんが、XSLT 1.0について言及しています。それはあなたの人生をもっと難しくします。 –

関連する問題