2017-11-20 8 views
0

でノードに到達それまでは私、次のXML構造を持っている:<item>は次のノードの親ではありませんXSLTプロセスのすべてのノードが特定の名前

<?xml version="1.0"?> 
<items> 
    <item/> 
    <desc/> 
    <desc2/> 
    <desc3/> 
    <price1/> 
    <info/> 
    <info/> 
    <info2/> 
    <item/> 
    <desc/> 
    <price1/> 
    <price2/> 
    <price3/> 
    <info1/> 
    <anotheriinfo/> 
    <specialinfo/> 
    <item/> 
    <desc/> 
    <price1/> 
</items> 

。 異なる商品を対応する情報と価格でグループ化する必要があります。 <item>と次のすべてのノードを次の<item>の直前に選択してロギングを適用する方法はありますか?またはグループにそれら

<?xml version="1.0" encoding="UTF-8"?> 
<items> 
    <item> 
    <desc/> 
    <desc2/> 
    <desc3/> 
    <price1/> 
    <info/> 
    <info/> 
    <info2/> 
    </item> 
    <item> 
    <desc/> 
    <price1/> 
    <price2/> 
    <price3/> 
    <info1/> 
    <anotheriinfo/> 
    <specialinfo/> 
    </item> 
    <item> 
    <desc/> 
    <price1/> 
    </item> 
</items> 

ように私はあなたがアップに読んでここに適用したい場合がありますXSLT 1.0

+2

入力構造を明確に示すには、終了タグを追加する必要があります。 XSLT 2または3と ' ' –

+0

を覚えていれば、兄弟要素をグループ化することについてコメント@ MartinHonnen!しかし、私はXSLT 1.0を使用する必要があります。助言がありますか ? – evilsoldier

答えて

1

あります。私は、position()に基づいて全く異なるアプローチ(やはり!!)を追求し、所望の結果をもたらす次の兄弟の数も追求した。これを共有したいだけです:

<xsl:template match="items"> 
    <xsl:copy> 
     <!-- total number of items --> 
     <xsl:variable name="countItems" select="count(item)"/> 
     <!-- edit: copy elements before first item --> 
     <xsl:copy-of select="*[following-sibling::item[$countItems]]"/> 
     <xsl:for-each select="item"> 
      <!-- position of current item --> 
      <xsl:variable name="position" select="position()"/> 
      <xsl:choose> 
       <xsl:when test="following-sibling::item"> 
        <xsl:copy> 
         <!-- get all elements before next item --> 
         <!-- = all elements followed by (total items minus current position) items --> 
         <xsl:apply-templates select="following-sibling::*[following-sibling::item[$countItems - $position]]"/> 
        </xsl:copy> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:copy> 
         <xsl:apply-templates select="following-sibling::*"/> 
        </xsl:copy> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:for-each> 
    </xsl:copy> 
</xsl:template> 

<!-- identity transform --> 
<xsl:template match="@* | node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
</xsl:template> 
+0

とてもエレガントでわかりやすい。ありがとう@friedemann_bach! – evilsoldier

+0

ありがとうございます。私の解決策は "良いxslt理解"の点で疑問に思えるかもしれませんが、個人的には解決策を比較することから多くを学ぶので、私はそれを共有しました。私はそれが何らかの使用のときに感謝します。 –

+0

もう1つの質問:)もし私が最初の* *の上に別のノードを持っていたら、ちょうどそれらを(移動せずに)コピーして、現在のロジックを保持したいと思っていますか?( *ノードそれらの下のすべてのノード)? – evilsoldier

2

3つの手法を使用する必要があります。

  • あなたが望むすべてがitem要素(によって示唆されているように、「またはグループに彼らのような...」)の表示の前に空白行である場合は、それを放出するために、あなたのスタイルシートを書きます。

  • Muenchianグループを読み上げます。グループ化する値は、itemという名前の先行する兄弟の数(itemというノード自体ではない)またはitemという名前の先行する兄弟の数+1(item要素の場合)です。

  • テンプレートの呼び出しを子どもに対して最初に行い、次にすぐ右の兄弟に対して行うことによって、ツリートラバーサルを実行する方法を学びます。この場合、基本パターンは、私はMuenchianグルーピングとSperberg-McQueens溶液を好き

    <xsl:template match="items"> 
        <xsl:apply-templates match="item"/> 
    </ 
    
    <xsl:template match="item"> 
        <xsl:copy> 
        <!-- handle descendants, if your current items have any ... --> 
        <xsl:apply-templates match="@*|node()"/> 
        <!-- bring right siblings into the content ... --> 
        <xsl:apply-templates match="following-sibling::*[1]" 
         mode="group-nodes"/> 
        </ 
    </ 
    
    <xsl:template match="*" mode="group-nodes" priority="1"> 
        <!-- 1 handle this element --> 
        <!-- modify next line if items elements can nest ... --> 
        <xsl:copy-of select="."/> 
    
        <!-- 2 handle next sibling --> 
        <xsl:apply-templates match="following-sibling::*[1]" 
         mode="group-nodes"/> 
        </ 
    </ 
    
    <xsl:template match="item" mode="group-nodes" priority="10"/> 
    
関連する問題