我有一个相当复杂的XSL任务。我有一个类似于
的XML文档<authorlist>
<orgs>
<org id="org1" name="Org A"/>
<org id="org2" name="Org B"/>
<org id="org3" name="Org C"/>
</orgs>
<authors>
<auth name="C. Thor">
<affiliations>
<affil id="org2"/>
<affil id="org3"/>
</affiliations>
</auth>
<auth name="A. Thor">
<affiliations>
<affil id="org3"/>
</affiliations>
</auth>
<auth name="B. Thor">
<affiliations>
<affil id="org1"/>
</affiliations>
</auth>
</authors>
</authorlist>
我想写一个XSL转换,它将产生以下(文本)输出
1 Org C
2 Org A
3 Org B
A. Thor ^{1}
B. Thor ^{2}
C. Thor ^{1,3}
也就是说,作者按名称按字母顺序排序。打印每个作者的姓名,以及表明其所属关系的上标。组织按照它们首次出现在作者排序列表中的顺序打印。每位作者可能有多个隶属关系。
以下是我认为我需要做的事情:
我可以使用的XSLT处理器是xsltproc,它实现了XSLT 1.0。如果有一个足够引人注目的案例,我可以考虑制作一个不同的处理器,但我可以使用不同的处理器有点怀疑。
真实案例变得更加复杂,因为有些组织有多个子组织,还有两类组织,成员组织和访客组织,它们打印在单独的列表中并具有独立的订单他们的上标。但是,我认为解决上述问题就足以完成剩下的工作了。
答案 0 :(得分:1)
一种方法:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:variable name="orgIndex">
<xsl:apply-templates select="//authors/auth" mode="orgIdx">
<xsl:sort select="@name" />
</xsl:apply-templates>
</xsl:variable>
<xsl:template match="authorlist">
<xsl:apply-templates select="authors" />
</xsl:template>
<xsl:template match="authors">
<xsl:apply-templates select="auth">
<xsl:sort select="@name" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="auth">
<xsl:value-of select="@name" />
<xsl:text> ^{</xsl:text>
<xsl:apply-templates select="affiliations/affil" mode="orgIdx">
<xsl:sort select="string-length(substring-before($orgIndex, @id))" data-type="number" />
</xsl:apply-templates>
<xsl:text>}</xsl:text>
<xsl:if test="position() < last()">
<xsl:value-of select="'
'" />
</xsl:if>
</xsl:template>
<xsl:template match="affil" mode="orgIdx">
<xsl:variable name="str" select="substring-before($orgIndex, @id)" />
<xsl:variable name="idx" select="string-length($str) - string-length(translate($str, '|', ''))" />
<xsl:value-of select="$idx" />
<xsl:if test="position() < last()">,</xsl:if>
</xsl:template>
<xsl:template match="auth" mode="orgIdx">
<xsl:for-each select="affiliations/affil">
<xsl:value-of select="concat('|', @id)" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
结果
A. Thor ^{1} B. Thor ^{2} C. Thor ^{1,3}
此方法基于以正确的顺序构建affil/@id
的分隔字符串(即auth
按字母顺序排列,并按{1}}按文档顺序排列。
对于您的示例,字符串auth
将为$orgIndex
。
'|org3|org1|org2|org3'
将在该字符串中重复,但这是正确的,因为我们不关心字符串的后部。
现在我们可以使用@id
来确定第一次出现ID之前的分隔符字符数,从而产生您似乎正在寻找的数字索引。