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> 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> 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> 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> 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の回答と非常によく似ています。彼の種類は機能しているようですが、ディミトレに何かが欠けていますか?)
よろしく、ブライス。