I have a Problem in grouping xml entrys via attributes using XSLT.
Here is my source xml:
<chron>
<chronEntry type="education" order="1" blockorder="1">
<foo>bar</foo>
</chronEntry>
<chronEntry type="education" order="2" blockorder="1">
<foo>bar</foo>
</chronEntry>
<chronEntry type="education" order="3" blockorder="1">
<foo>bar</foo>
</chronEntry>
<chronEntry type="communityservice" order="1" blockorder="2">
<foo>bar</foo>
</chronEntry>
<chronEntry type="experience" order="1" blockorder="3">
<foo>bar</foo>
</chronEntry>
<chronEntry type="experience" order="2" blockorder="3">
<foo>bar</foo>
</chronEntry>
<chronEntry type="experience" order="3" blockorder="3">
<foo>bar</foo>
</chronEntry>
<chronEntry type="experience" order="4" blockorder="3">
<foo>bar</foo>
</chronEntry>
</chron>
What i want to get is a list of all available values of the attribute "type". In this case it should be: - education - communityservice - experience
I tryed it like this:
<xsl:for-each select="/foobar/chron/chronEntry">
<xsl:sort select="@blockorder"/>
<xsl:if test ="@blockorder != preceding-sibling::chronEntry[1]/@blockorder">
<fo:table-row>
<fo:table-cell>
<fo:block><xsl:value-of select="@type"/></fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:if>
</xsl:for-each>
what I get is: - communityservice - experience
I'm missing "education" (the first one)
What can I do to get it?
Thaks for your help!
Greetz
Dave
The problem is that although you are creating a sorted node-list, the preceding-sibling::
(or any axis) only can be used to express relations between nodes in a document (not in a node-list).
Therefore, preceding-sibling::
chronEntry[1] selects the first preceding sibling
chronEntry` of the context node in the current document -- not in the sorted node-list.
Solution :
In XSLT 1.0 capture the result of the xsl:for-each
in a variable. As this is of the infamous RTF type, you have to convert it to a regular tree, using an xxx:node-set()
extension function supported by the XSLT 1.0 processor in use. Then, within this regular tree, the axes, including preceding-sibling::
, have the wanted meaning.
Recommended solution. Use Muenchian grouping:
like this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kType" match="@type" use="."/>
<xsl:template match=
"chronEntry
[generate-id(@type)
=
generate-id(key('kType', @type)[1])
]">
<xsl:value-of select="concat(@type, ' ')"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
when this transformation is applied on the provided XML document :
<chron>
<chronEntry type="education" order="1" blockorder="1">
<foo>bar</foo>
</chronEntry>
<chronEntry type="education" order="2" blockorder="1">
<foo>bar</foo>
</chronEntry>
<chronEntry type="education" order="3" blockorder="1">
<foo>bar</foo>
</chronEntry>
<chronEntry type="communityservice" order="1" blockorder="2">
<foo>bar</foo>
</chronEntry>
<chronEntry type="experience" order="1" blockorder="3">
<foo>bar</foo>
</chronEntry>
<chronEntry type="experience" order="2" blockorder="3">
<foo>bar</foo>
</chronEntry>
<chronEntry type="experience" order="3" blockorder="3">
<foo>bar</foo>
</chronEntry>
<chronEntry type="experience" order="4" blockorder="3">
<foo>bar</foo>
</chronEntry>
</chron>
the wanted, correct result is produced :
education communityservice experience
Do you realy need the xsl:sort? or did you use it for grouping? if it is so, you can just delete the xsl:sort and correct your xsl:if-test:
<xsl:for-each select="/foobar/chron/chronEntry">
<xsl:if test ="not(@blockorder = preceding-sibling::chronEntry/@blockorder)">
<fo:table-row>
<fo:table-cell>
<fo:block><xsl:value-of select="@type"/></fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:if>
</xsl:for-each>
If you need the xsl:sort, you can use this:
<xsl:variable name="types" select="/foobar/chron/chronEntry[not(preceding-sibling::*/@blockorder=@blockorder)]"/>
<xsl:for-each select="$types">
<xsl:sort select="@blockorder"/>
<fo:table-row>
<fo:table-cell>
<fo:block>
<xsl:value-of select="@type"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.