1

XSLT2。

こんにちは、私は3つのノードを持つxmlを持っています。これは、Children、Fathers、MothersFathersという「children」の観点から名前が付けられています。父親ノードから始めて、子ノードのIDに基づいて子のMothersFatherノードを見つける必要があります(子ノードは他の2つを結合する中間参照です)。

したがって、各父親が子供たちの個別のMothersFatherを取得するために、これらは人間ではありません。父親は数百人の子供を持つことができますが、関連するMothersFathersは20人程度です:)

XMLの簡略化されたバージョン(実際には、約80のFatherノード、3000のChildノード、および400のMothersFatherノードがあります):

<t>
<Children>
    <Child>
        <ID>1</ID>
        <FathersID>100</FathersID>
        <MothersFatherID>200</MothersFatherID>    
    </Child>
    <Child>
        <ID>2</ID>
        <FathersID>100</FathersID>
        <MothersFatherID>201</MothersFatherID>    
    </Child>
    <Child>
        <ID>3</ID>
        <FathersID>100</FathersID>
        <MothersFatherID>202</MothersFatherID>    
    </Child>
    <Child>
        <ID>4</ID>
        <FathersID>100</FathersID>
        <MothersFatherID>201</MothersFatherID>    
    </Child>
    <Child>
        <ID>5</ID>
        <FathersID>101</FathersID>
        <MothersFatherID>201</MothersFatherID>    
    </Child>
</Children>
<Fathers>
    <Father>
        <ID>100</ID>
    </Father>
    <Father>
        <ID>101</ID>
    </Father>
</Fathers>
<MothersFathers>
    <MothersFather>
        <ID>200</ID>
    </MothersFather>
    <MothersFather>
        <ID>201</ID>
    </MothersFather>
    <MothersFather>
        <ID>202</ID>
    </MothersFather>
</MothersFathers>        
</t>

私のxsltは次のようになります:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="kFathersChildren" match="Child" use="FathersID"/>

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

    <xsl:template match="Fathers">
        <xsl:apply-templates select="Father"></xsl:apply-templates>
    </xsl:template>

    <xsl:template match="Father">
        <xsl:text>&#10;FATHER: ID=</xsl:text><xsl:value-of select="ID"/>
        <!-- Now show all this fathers childrens maternal grandfathers based on the ID in the Child node -->

        <!--TRY 1: this works, as in gets the right nodes, but doesn't do distinct values....--> 
        <xsl:for-each select="key('kFathersChildren', ID)">  <!-- get the fathers children --> 
            <xsl:text>&#10; found child: current MFid=</xsl:text><xsl:value-of select="current()/MothersFatherID"/>
            <xsl:text> ID=</xsl:text><xsl:value-of select="ID"/>
            <xsl:apply-templates select="//MothersFathers/MothersFather[ID=current()/MothersFatherID]"></xsl:apply-templates>
        </xsl:for-each>

        <!-- *** THIS IS WHERE I GET LOST??? - Do the same thing but only get distinct MothersFatherID's... -->

        <!--TRY 2: note- won't compile in current state... -->
        <xsl:for-each select="distinct-values(key('kFathersChildren', ID)[MothersFatherID])">  
            <xsl:text>&#10;  Distinct MothersFatherID ???? - don't know what to select </xsl:text><xsl:value-of select="."/>
            <xsl:apply-templates select="//MothersFathers/MothersFather[ID=??????????"></xsl:apply-templates>
        </xsl:for-each>
    </xsl:template>

    <xsl:template match="//MothersFathers/MothersFather">
        <xsl:text>&#10;      IN MothersFather template... ID=</xsl:text><xsl:value-of select="ID"/>
    </xsl:template>
</xsl:stylesheet>

Try 1では、すべてのノードとMothersFatherIDを取得できます。Try1の出力は次のとおりです。

FATHER: ID=100
 found child: current MFid=200 ID=1
      IN MothersFather template... ID=200
 found child: current MFid=201 ID=2
      IN MothersFather template... ID=201
 found child: current MFid=202 ID=3
      IN MothersFather template... ID=202
 found child: current MFid=201 ID=4
      IN MothersFather template... ID=201
FATHER: ID=101
 found child: current MFid=201 ID=5
      IN MothersFather template... ID=201

'distinct-value'を選択しているTry2では、次のような出力が必要です。

FATHER: ID=100
      IN MothersFather template... ID=201
      IN MothersFather template... ID=200
      IN MothersFather template... ID=202
FATHER: ID=101
      IN MothersFather template... ID=201

(実際の出力ではありません-適切なノードを参照できることを示すデバッグ用のものだけです)。

しかし、「apply-templates」呼び出しに渡すために一意のMothersFatherIDを参照するために何を使用するのか理解できません。

何を試しても、次のようなエラーのバリエーションがあります 。Required item type of first operand of '/' is node(); supplied value has item type xs:anyAtomicTypeまたはAxis step child::element('':MothersFatherID) cannot be used here: the context item is an atomic value。文字列値が使用されているノードを選択しようとしている、またはその逆のことを意味していると思います。distinct-value()関数の使用が完全に間違っているのではないでしょうか。

誰かがこれを行う方法に光を当てることができますか?(私は、この種のことにとらわれないときに、このxsltが悟りの禅の瞬間を持つことを望んでいます)。

さらに、それができたら、MothersFatherを各Fatherに対してソートされた順序で配置する必要があります-実際のxmlには、各'ID'に関連付けられた'Name'があります-うまくいけば、for-each'sort'ステートメントは次のようになります上記の問題を修正するものへの同様の参照?

御時間ありがとうございます。ブライス。

編集:

わお!!答えてくれてありがとうディミトレ。私はそれを調べました、そして私がそれを完全に理解していないのであなたが私のためにそれを少し分解することができるかもしれないことを望んでいましたか?答えは:

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

 <xsl:key name="kMFByFId" match="MothersFatherID"
          use="../FathersID"/>

 <xsl:key name="kMFById" match="MothersFather" use="ID"/>

 <xsl:key name="ChildByFIdAndMFId" match="Child"
  use="concat(FathersID, '+', MothersFatherID)"/>

 <xsl:template match="Children|MothersFathers|text()"/>

 <xsl:template match="Father">
   Father ID=<xsl:value-of select="ID"/>
  <xsl:apply-templates select=
   "key('kMFById',
         key('kMFByFId', ID)
          [generate-id(..)
          =
           generate-id(key('ChildByFIdAndMFId',
                            concat(../FathersID,'+',.)
                          )[1]
                       )
          ]
        )">
     <xsl:sort select="ID" data-type="number"/>
   </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="MothersFather">
      MothersFather ID=<xsl:value-of select="ID"/>
 </xsl:template>
</xsl:stylesheet>

関係するキーを使用します。

ライン<xsl:template match="Children|MothersFathers|text()"/>-このラインはどのように機能していますか?デバッガーをステップスルーすると、この行をまっすぐ通過します。コメントすると、ソースがわからない余分な出力がたくさんあります。

そして、MothersFatherノードを与えるapply-templates行 -私はこれを紙の上で分解して魔法を見ようとしましたが、それを完全に理解することはできませんでした。これは 、生成されたID'(ドットドット)'が現在のFather IDによって一致するMothersFatherノードを取得することを意味するようなものです-親ノードと関係がありますか?どれ?ChildByFIdAndMFIdキーに基づいて生成されたIDと等しい-この1は、一致する生成されたIDの最初の出現のみを取得し、それによって私の明確な値を与えますか?<xsl:apply-templates select= "key('kMFById', key('kMFByFId', ID)[generate-id(..) =
generate-id(key('ChildByFIdAndMFId', concat(../FathersID,'+',.))[1] ) ] )">
key('kMFById', key('kMFByFId', ID)[generate-id(..)[1]

(ディミトレによるこの回答も、JLRishieの回答と非常によく似ています。彼の種類は機能しているようですが、ディミトレに何かが欠けていますか?)

よろしく、ブライス。

4

2 に答える 2

2

私はこれがあなたがやろうとしていることをするはずだと信じています:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" />
  <xsl:key name="kFathersChildren" match="Child" 
           use="concat(FathersID, ' - ', MothersFatherID)"/>
  <xsl:key name="kChildByFatherId" match="Child" use="FathersID"/>
  <xsl:key name="kMothersFatherById" match="MothersFather" use="ID" />

  <xsl:template match="text() | Children | MothersFathers" />

  <xsl:template match="Father">
    <xsl:value-of select="concat('&#10;FATHER: ID=', ID)" />

    <xsl:apply-templates 
      select="key('kMothersFatherById', 
                 key('kChildByFatherId', ID)
                   [generate-id() = 
                     generate-id(
                       key('kFathersChildren', 
                          concat(FathersID, ' - ', MothersFatherID)
                           )[1])
                   ]/MothersFatherID)">
      <xsl:sort select="ID" data-type="number" />
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="MothersFather">
    <xsl:value-of select="concat('&#10;      IN MothersFather template... ID=', ID)"/>
  </xsl:template>
</xsl:stylesheet>

サンプル入力で実行すると、次のようになります。

FATHER: ID=100
      IN MothersFather template... ID=200
      IN MothersFather template... ID=201
      IN MothersFather template... ID=202
FATHER: ID=101
      IN MothersFather template... ID=201
于 2013-01-25T04:54:03.323 に答える
1

この変換-より短く、適切にフォーマットされ、水平/垂直スクロールなしで読みやすくなります。また、他の回答とは異なり、正しく並べ替えを適用します

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

 <xsl:key name="kMFByFId" match="MothersFatherID"
          use="../FathersID"/>

 <xsl:key name="kMFById" match="MothersFather" use="ID"/>

 <xsl:key name="ChildByFIdAndMFId" match="Child"
  use="concat(FathersID, '+', MothersFatherID)"/>

 <xsl:template match="Children|MothersFathers|text()"/>

 <xsl:template match="Father">
   Father ID=<xsl:value-of select="ID"/>
  <xsl:apply-templates select=
   "key('kMFById',
         key('kMFByFId', ID)
          [generate-id(..)
          =
           generate-id(key('ChildByFIdAndMFId',
                            concat(../FathersID,'+',.)
                          )[1]
                       )
          ]
        )">
     <xsl:sort select="ID" data-type="number"/>
   </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="MothersFather">
      MothersFather ID=<xsl:value-of select="ID"/>
 </xsl:template>
</xsl:stylesheet>

このXMLドキュメントに適用した場合(提供されていますが、正しい並べ替えをテストするために少しシャッフルされています):

<t>
<Children>
    <Child>
        <ID>2</ID>
        <FathersID>100</FathersID>
        <MothersFatherID>201</MothersFatherID>
    </Child>
    <Child>
        <ID>1</ID>
        <FathersID>100</FathersID>
        <MothersFatherID>200</MothersFatherID>
    </Child>
    <Child>
        <ID>3</ID>
        <FathersID>100</FathersID>
        <MothersFatherID>202</MothersFatherID>
    </Child>
    <Child>
        <ID>4</ID>
        <FathersID>100</FathersID>
        <MothersFatherID>201</MothersFatherID>
    </Child>
    <Child>
        <ID>5</ID>
        <FathersID>101</FathersID>
        <MothersFatherID>201</MothersFatherID>
    </Child>
</Children>
<Fathers>
    <Father>
        <ID>100</ID>
    </Father>
    <Father>
        <ID>101</ID>
    </Father>
</Fathers>
<MothersFathers>
    <MothersFather>
        <ID>200</ID>
    </MothersFather>
    <MothersFather>
        <ID>201</ID>
    </MothersFather>
    <MothersFather>
        <ID>202</ID>
    </MothersFather>
</MothersFathers>
</t>

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

   Father ID=100
      MothersFather ID=200
      MothersFather ID=201
      MothersFather ID=202
   Father ID=101
      MothersFather ID=201

注意してください

変換は、XSLT1.0とXSLT2.0プロセッサの両方で正しく実行されます。


更新

OPは質問を編集し、このソリューションについていくつか質問しました。

関係するキーを使用します。

ライン<xsl:template match="Children|MothersFathers|text()"/>-このラインはどのように機能していますか?デバッガーをステップスルーすると、この行をまっすぐ通過します。コメントすると、ソースがわからない余分な出力がたくさんあります。

本体が空のこのテンプレートが何をしているのかを発見しました。これにより、余分な出力が書き込まれるのを防ぎます。XSLTプロセッサには、特定のノードを処理するときに実行するために選択される多数の組み込みテンプレートがあります。XSLT変換で、このノードに一致するテンプレートが指定されていない場合に備えて。

任意の要素の組み込みテンプレートは、そのすべてのtext-node-descendantsの文字列値の連結を出力します。これは、まさに不要な出力と見なされるものです。

これを回避するために、thode要素に一致するテンプレートを提供しました。これにより、組み込みのテンプレートがオーバーライド(抑制)されます。このタンプレートには本体がないため、出力は生成されません。

MothersFatherそして、ノード を与えるapply-templates行<xsl:apply-templates select= "key('kMFById', key('kMFByFId', ID)[generate-id(..) = generate-id(key('ChildByFIdAndMFId', concat(../FathersID,'+',.))[1] ) ] )">-私はこれを紙の上で分解して魔法を見ようとしましたが、それを完全に理解することはできませんでした。これは、現在の場所で key('kMFById', key('kMFByFId', ID)一致するMothersFatherノードを取得する手段のようなものです-親ノードと関係がありますか?どれ?に基づいて生成されたIDに等しい -これは、一致する生成されたIDの最初の出現のみを取得し、それによって私の明確な値を与えますか?Father ID[generate-id(..) the generated id of '(dot dot)'ChildByFIdAndMFId key [1]1

あなたの質問はこのコードフラグメントについてです:

  <xsl:apply-templates select=
   "key('kMFById',
         key('kMFByFId', ID)
          [generate-id(..)
          =
           generate-id(key('ChildByFIdAndMFId',
                            concat(../FathersID,'+',.)
                          )[1]
                       )
          ]
        )">
     <xsl:sort select="ID" data-type="number"/>
   </xsl:apply-templates>

ここで何が起こっているのかを理解するには、ミュンヒアンのグループ化方法に精通する必要があります。

本質的に上記のコードフラグメントが言っていることは

現在の()ノードのと同じ値を持つのMothersFather兄弟である最初のそのような要素であるすべての要素を処理します。FathersIDIDFather

于 2013-01-25T05:17:33.043 に答える