XSLT 2。
嗨,我有一个 xml,它有 3 个节点,从名为“孩子”的角度命名:孩子、父亲和母亲父亲。从父亲节点开始,我需要根据子节点中的 ID 找到一个子母亲 MothersFather 节点(子节点是连接其他两个节点的中间参考。)
因此,对于每个父亲来说,他的孩子都有不同的MothersFather - 这些不是人类,一个父亲可能有数百个孩子,但只有大约 20 个相关的 MothersFathers :)
XML 的简化版本(在现实生活中大约有 80 个父亲节点、3000 个子节点和 400 个母亲父亲节点):
<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
在我选择“不同值”的 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
(不是真正的输出 - 只是调试显示我可以引用正确节点的东西)。
但我不知道我打算用什么来引用唯一的 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 对每个父亲进行排序 - 在真正的 xml 中,每个“ID”都有一个“名称” - 希望每个“排序”语句将是类似参考什么解决了上述问题?
谢谢你的时间。布莱斯。
编辑:
哇!!谢谢你的回答迪米特。我已经检查过了,希望你能帮我把它分解一下,因为我没有完全理解它?答案是:
<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 获取匹配的 MothersFather 节点,其中生成的 id 为“(dot dot)” - 与父节点有关吗?哪一个?等于基于 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]
(Dimitre 的这个答案也与 JLRishie 的答案非常相似。他的那种似乎很有效,我在 Dimitre 那里遗漏了什么吗?)
问候,布莱斯。