XSTL转带额外标签的XSLT方法及XSLT1.0分组问题求助
嘿,刚上手XSLT 1.0碰到这种分组问题很正常,你之前顾虑Muenchian方法要求所有节点子标签一致?其实不用怕——Muenchian分组核心是键值的定义,不是标签的统一性,咱们完全可以针对你的XML结构调整逻辑,同时处理你说的两种情况。
先明确你的核心需求:把那些有的带<Parent>、有的不带的<Family>节点,按父-子关系分组,还要处理重复的父级(比如你输入里重复的General psychiatry),同时不能修改原XML。下面直接上可落地的方案:
完整XSLT代码实现
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 键1:把每个Family绑定到它的归属父级 --> <!-- 有<Parent>就用Parent的值,没有就用自己的Description(作为父级) --> <xsl:key name="family-by-parent" match="Family" use="string(Parent | Description[not(../Parent)])"/> <!-- 键2:提取所有唯一的父级名称,避免重复输出同一个父级 --> <xsl:key name="unique-parents" match="Family" use="string(Parent | Description[not(../Parent)])"/> <xsl:template match="/"> <GroupedFamilies> <!-- 遍历所有去重后的父级 --> <xsl:for-each select="Family[string(Parent | Description[not(../Parent)])][generate-id() = generate-id(key('unique-parents', string(Parent | Description[not(../Parent)]))[1])]"> <xsl:variable name="current-parent" select="string(Parent | Description[not(../Parent)])"/> <!-- 生成父级节点,带额外标签 --> <ParentFamily> <ParentName><xsl:value-of select="$current-parent"/></ParentName> <!-- 生成子级列表:只选有Parent且等于当前父级的Family --> <ChildFamilies> <xsl:for-each select="key('family-by-parent', $current-parent)[Parent]"> <ChildFamily> <ChildName><xsl:value-of select="Description"/></ChildName> </ChildFamily> </xsl:for-each> </ChildFamilies> </ParentFamily> </xsl:for-each> </GroupedFamilies> </xsl:template> </xsl:stylesheet>
逻辑拆解,对应你的两种情况
情况1:有明确父-子关系的节点
比如<Family><Description>Liaison Psychiatry</Description><Parent>General psychiatry</Parent></Family>,它会被family-by-parent键绑定到General psychiatry这个父级,在输出时就会出现在General psychiatry的<ChildFamilies>列表里。
情况2:只有父级无对应子级的节点
比如<Family><Description>Old age psychiatry</Description></Family>,因为它没有<Parent>,所以键值就是自己的Description,输出时会作为独立的<ParentFamily>节点,它的<ChildFamilies>会是空的(因为没有节点的<Parent>等于它的名称)。
额外处理:去重重复父级
你输入里有两个<Family><Description>General psychiatry</Description></Family>,通过generate-id() = generate-id(key('unique-parents', ...)[1])这个判断,确保同一个父级只输出一次,不会重复。
输出效果示例
针对你给的输入XML,上面的代码会生成带额外层级标签的XML,结构清晰:
<GroupedFamilies> <ParentFamily> <ParentName>General psychiatry</ParentName> <ChildFamilies> <ChildFamily> <ChildName>Liaison Psychiatry</ChildName> </ChildFamily> <ChildFamily> <ChildName>Liaison</ChildName> </ChildFamily> </ChildFamilies> </ParentFamily> <ParentFamily> <ParentName>Old age psychiatry</ParentName> <ChildFamilies/> </ParentFamily> </GroupedFamilies>
关于你第一个问题的补充
你提到“如何将XSLT重新转换为添加了额外标签的XSLT?”,如果是指把原XML转换成带父-子嵌套标签的结构化XML(比如上面的输出),那上面的代码就直接实现了这个需求——它以你提供的XML为输入,输出带有<ParentFamily>、<ChildFamily>等额外标签的结果。
如果是想修改你现有生成PDF的XSLT,只需要把这个分组逻辑整合进去就行:比如在输出PDF的章节时,先遍历每个<ParentFamily>,输出父级标题,再遍历对应的<ChildFamily>输出子级内容。
内容的提问来源于stack exchange,提问作者Ranjan

