0

私はこの入力ファイルを持っています:

<root> 
    <library id="L1">
        <shelf1 id="1">
            <book id="1" action="borrow">
                <attributes>
                    <user>John</user>                    
                </attributes>
                <other1>y</other1>
            </book>  
            <book id="1" action="extend">
                <attributes>
                    <user>Woo</user>           
                    <length>3</length>
                </attributes>
                <other2>y</other2>
            </book>  
            <book id="1" action="extend">
                <attributes>
                    <length>2</length>
                    <condition>ok</condition>
                </attributes>
                <other3>y</other3>
            </book>
            <book id="2" action="borrow">...</book>
        </shelf1>
        <shelf2>...</shelf2>
    </library>
</root>

期待される出力:

<root> 
    <library id="L1">
        <shelf1 id="1">
            <book id="1" action="borrow">
                <attributes>
                    <user>Woo</user>           
                    <length>2</length>
                    <condition>ok</condition>
                </attributes>
                <other1>y</other1>
                <other2>y</other2>
                <other3>y</other3>
            </book>
            <book id="2" action="borrow">...</book>
        </shelf1>
        <shelf2>...</shelf2>
    </library>
</root>

私のXSL:

<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="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="library/*/*[1]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <attributes>
                <xsl:for-each-group select="attributes/*" group-by="name()">
                    <xsl:sort select="current-grouping-key()"/>
                    <xsl:apply-templates select="."/>
                </xsl:for-each-group>
            </attributes>
            <xsl:apply-templates select="*[not(self::attributes)]"/>
        </xsl:copy>            
    </xsl:template>

    <xsl:template match=
      "library/*/*
        [@action='extend' and following-sibling::*[1][@action='extend']
       or preceding-sibling::*[@action='borrow']]"/>
</xsl:stylesheet>

すべてのノードに対して、action=borrowその後に1つ以上のノードが続きますaction=extend

  • を使用してノードにマージしますaction=borrow
  • attributes最新の値を持つ兄弟からのすべての一意の属性を持つように、子をマージします。
  • 他の子供は変更しないでください

XSLT2.0を使用してこの変換を修正する方法を教えてください。

どうもありがとう。

よろしく、ジョン

4

1 に答える 1

3

あなたは多くの同様の質問をしました。たぶん、本を買って数日読んで過ごす時間ですか?私があなたからの同様の質問に答えるのはおそらくこれが最後です。同様の質問をする必要がないように、答えから学ぶことができるはずです。学んでいない場合は、「何があなたを妨げているのか」と自問する必要があります。

とにかく、このスタイルシートを見てみましょう。説明では、ポイントをxmlまたはxpathコメント内の数字と呼びます。たとえば、ポイント1は<!-1->で区切られています。または、xpath式の内部にある場合は、(:1:)です。明らかに、本番用のコメントを削除してください。

<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:fn="http://www.w3.org/2005/xpath-functions"
  xmlns:John="http://stackoverflow.com/questions/11463900"
  exclude-result-prefixes="xsl xs fn John">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*" />

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

 <xsl:template match="*[starts-with(local-name(),'shelf')]   (: 1 :)">
  <xsl:copy>
   <xsl:apply-templates select="@*" />

    <!-- 2 -->
   <xsl:apply-templates select="
     book[@action='extend']                                  (: 3 :)
         [not( preceding-sibling::book[@action='borrow'])]   (: 4 :)" />

    <!-- 5 -->
   <xsl:for-each-group
    select="book[@action='borrow']     (: 6 :)
             |                         (: 7 :)
            book[@action='extend']
                [preceding-sibling::book[@action='borrow']]   (: 8 :)"
    group-starting-with="book[@action='borrow']">
     <xsl:for-each select="current-group()[1]">
      <xsl:copy>                                            <!-- 9 -->
       <xsl:apply-templates select="@*" />
        <xsl:call-template name="merge-books-deeply">       <!-- 10 -->
         <xsl:with-param name="books" select="current-group()" />
         <xsl:with-param name="name-path" select="()" />
        </xsl:call-template>
      </xsl:copy>
     </xsl:for-each>     
   </xsl:for-each-group>

   <xsl:apply-templates select="                              (: 11 :)
     node()[ not( self::book[@action=('borrow','extend')])]" />

  </xsl:copy>
 </xsl:template>

<xsl:function name="John:children-on-path" as="element()*">
 <xsl:param name="base" as="element()*" />     <!-- 12 -->
 <xsl:param name="path" as="xs:string*" />     <!-- 13 -->
 <xsl:choose>
  <xsl:when test="fn:empty($base)">
   <xsl:sequence select="()" />
  </xsl:when>
  <xsl:when test="fn:empty($path)">
   <xsl:copy-of select="$base/*" />           <!-- 14 -->
  </xsl:when>
  <xsl:otherwise>
   <xsl:sequence select="John:children-on-path(
     $base/*[name()=$path[1]],                      (: 15 :)
     $path[position() ne 1])" /> 
  </xsl:otherwise>  
 </xsl:choose>
</xsl:function>

<xsl:template name="merge-books-deeply">
 <xsl:param name="books" as="element()*" />
 <xsl:param name="name-path" as="xs:string*" />
  <xsl:for-each-group
      select="John:children-on-path($books,$name-path)"
      group-by="name()">                                <!-- 16 -->                 
   <xsl:for-each select="current-group()[last()]" >     <!-- 17 -->
    <xsl:copy>
     <xsl:apply-templates select="@*" />
        <xsl:call-template name="merge-books-deeply">   <!-- 18 -->
         <xsl:with-param name="books" select="$books" />
         <xsl:with-param name="name-path" select="$name-path,name()" />
        </xsl:call-template>
     <xsl:apply-templates select="text()" />        
    </xsl:copy>
   </xsl:for-each>
  </xsl:for-each-group>
</xsl:template>

</xsl:stylesheet>

説明

  1. シェルフノードのテンプレートから始めます。シェルフノード名を一定にしただけではないのは残念です。その場合、一致式がはるかに単純になります。シェルフノードとすべての属性をコピーします。
  2. これで、いくつかのルールに従って本がマージされます。つまり、一緒にマージされる本はグループです。あなたが述べたマージルールによれば、本のグループは、借りた本で始まり、次の拡張された本を含むすべての本です。これを達成するための自然な候補は、借りた本と拡張された本に関するxsl:for-each-group命令であり、@ group-starting-withは、借りた本の先頭に設定されます(ポイント5から8)。xsl:for-each-groupにはわずかな問題があります。孤立した本がある場合、つまり、借用した本の前に拡張された本がない場合、これらが最初のグループになります。マージルールに適合しないため、これは望ましくありません。したがって、最初にそれらをグループ化から除外し(ポイント8を参照)、ポイント2で孤立した本を通常どおり処理します。
  3. ここでの述語は、拡張された本を選択します。
  4. ...そしてこれは孤立した本を選択します
  5. 次に、棚の本をマージ可能なグループにグループ化します
  6. 間違いなく本を借りた場合、それはグループに属します(実際にはグループの長になります)
  7. また、次の拡張書籍を含める必要があります
  8. しかし、孤児を除外します
  9. この時点でcurrent-group()は、マージ可能なブックのグループを選択します。このシーケンスの先頭であるcurrent-group()[1]は、グループを開始する借用した本です。それを選択し、それとその属性をコピーします。
  10. さあ、マージの楽しみのために!サンプルデータから、「other1」という名前のノードと「attributes」という名前のノードの子という2つのレベルでマージしているように見えます。これがどこまで進むかについてのあなたの意図は明確ではありませんが、私は最も寛大な解釈を採用しました。つまり、すべての子の要素を再帰的に無限の深さまでマージする必要があるということです。これを行うには、名前付きテンプレートが必要になり、再帰的に呼び出します。merge-books-deeplyの仕事は、いくつかの要素パス($ name-path)に沿って一連の本($ books)をマージすることです。$name-pathは空で始まります。その場合、('attributes')、('attributes'、'user')、('other1')のような値になります。
  11. この時点で、私たちはまだ棚にいますが、本のマージは完了しています。本以外の子供や、マージに参加しなかったその他の奇妙なことがあるかもしれません。それらには価値があるかもしれないので、ここにコピーします。
  12. ここで、シェルフからの特定の相対パスにあるマージグループのすべてのマージ可能なノードを見つけるためのサポート関数が必要です。これはJohn:children-on-path()です。2つのパラメータを取ります。$ baseは、マージされるノードであり、
  13. $ pathは、それらから下に移動するためのパスです。この関数は、$pathの子孫である$baseの子であるノードのシーケンスを返します。たとえば、$baseが/rootで、$ pathが('library')の場合、John:children-on-path()はshelf1とshelf2を返す必要があります。関数は再帰的に定義されます。最初に些細なケースを処理し、次に、些細なことではない場合は、パスを1ステップ下に移動し、次のパスから行ったステップを削除して、パス全体をトラバースするまで続行を呼び出します。
  14. グループ内でマージ可能なノードが見つかったら、新しいグループ化を行います。それらを名前でグループ化します。たとえば、すべてのユーザーノードが1つのグループであり、すべての長さのノードが別のグループです。
  15. グループ、たとえばすべてのユーザーを取得したら、それらすべてをコピーすることはできません。つまり、マージの全体的なポイントです。したがって、グループ全体の値として優先するものを1つ選択します。サンプルデータでは、OPが最後の値を選択しています。それが私たちの仕事です。その要素を選択し、それとその属性をコピーします。
  16. そして今、私たちは別のレベルで再びマージする必要があるかもしれません。そのため、同じテンプレートに戻りますが、パスを拡張して、今実行した新しいステップを含めます。

ジョンのための研究

  1. Google for xsl:for-each-groupといくつかのreaingを行います。ここにいくつかの良いものがあります。
  2. XSLTの本を購入して読んでください。選択できるものはたくさんあります。
于 2012-07-13T09:11:21.450 に答える