xml - Complex Grouping using XSLT 1.0 -
i've revised data file , added grouping column. not figure out logic grouping otherwise.
the data contains information stamp collection.
here sample xml:
<?xml version="1.0" encoding="utf-8"?> <stamps> <stamp> <group>25</group> <scott>3133</scott> <title>32¢ thornton wilder</title> <series>literary arts</series> </stamp> <stamp> <group>26</group> <scott>3134</scott> <title>32¢ charlie chaplin</title> </stamp> <stamp> <group>26</group> <scott>3135</scott> <title>32¢ raoul wallenberg</title> </stamp> <stamp> <group>27</group> <scott>3136</scott> <title>sheet of 15</title> <issue>the world of dinosaurs</issue> </stamp> <stamp> <group>27</group> <scott>3136</scott> <minor>a</minor> <title>32¢ ceratosaurus</title> <issue>the world of dinosaurs</issue> </stamp> <stamp> <group>27</group> <scott>3136</scott> <minor>b</minor> <title>32¢ camptosaurus</title> <issue>the world of dinosaurs</issue> </stamp> <stamp> <group>27</group> <scott>3136</scott> <minor>c</minor> <title>32¢ camarasaurus</title> <issue>the world of dinosaurs</issue> </stamp></stamps>
here xslt put together:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:output method="xml" indent="yes"/> <xsl:key name="stampgroup" match="stamp" use="group"/> <xsl:key name="scottgroup" match="stamp" use="concat(group, '|', scott)"/> <xsl:template match="/*"> <xsl:copy> <xsl:apply-templates select="stamp[generate-id() = generate-id(key('stampgroup', group)[1])]" mode="stampgroup" /> </xsl:copy> </xsl:template> <xsl:template match="stamp" mode="stampgroup"> <stampgroup id="{group}"> <xsl:apply-templates select="key('stampgroup', group)[generate-id() = generate-id(key('scottgroup', concat(group, '|', scott))[1])]" mode="scottgroup" /> </stampgroup> </xsl:template> <xsl:template match="stamp" mode="scottgroup"> <stamp> <scott><xsl:value-of select="scott"/></scott> <title><xsl:value-of select="title"/></title> <minor><xsl:value-of select="minor"/></minor> </stamp> </xsl:template> </xsl:stylesheet>
here resulting xml:
<?xml version="1.0" encoding="utf-8"?> <stamps> <stampgroup id="25"> <stamp> <scott>3133</scott> <title>32¢ thornton wilder</title> <minor/> </stamp> </stampgroup> <stampgroup id="26"> <stamp> <scott>3134</scott> <title>32¢ charlie chaplin</title> <minor/> </stamp> <stamp> <scott>3135</scott> <title>32¢ raoul wallenberg</title> <minor/> </stamp> <stamp> <scott>3136</scott> <title>sheet of 15</title> <minor/> </stamp> </stampgroup> </stamps>
it's working. it's pulling groups. it's pulling unique <scott>
items, it's not picking <minor>
subitems.
i've never used type of xslt structure before. how repeat items in for-each?
group 27 has 4 items in it. have same <scott>
number different <minor>
fields.
do need create third key?
sorry, forgot add desired result:
<?xml version="1.0" encoding="utf-8"?> <stamps> <stampgroup id="25"> <stamp> <scott>3133</scott> <title>32¢ thornton wilder</title> <minor/> </stamp> </stampgroup> <stampgroup id="26"> <stamp> <scott>3134</scott> <title>32¢ charlie chaplin</title> <minor/> </stamp> <stamp> <scott>3135</scott> <title>32¢ raoul wallenberg</title> <minor/> </stamp> </stampgroup> <stampgroup id="27"> <stamp> <scott>3136</scott> <title>sheet of 15</title> <minor/> </stamp> <stamp> <scott>3136</scott> <title>32¢ ceratosaurus</title> <minor>a</minor> </stamp> <stamp> <scott>3136</scott> <title>32¢ camptosaurus</title> <minor>b</minor> </stamp> <stamp> <scott>3136</scott> <title>32¢ camarasaurus</title> <minor>c</minor> </stamp> </stampgroup> </stamps>
if want have unique scott
values within each group
, , unique minor
values within each scott
subgroup, yes, need 3 keys.
and if values want subgroup not unique each parent group, keys have concatenated in order narrow key down matching items current parent group only.
xslt 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:key name="stamp-by-group" match="stamp" use="group" /> <xsl:key name="stamp-by-scott" match="stamp" use="concat(group, '|', scott)" /> <xsl:key name="stamp-by-minor" match="stamp" use="concat(group, '|', scott, '|', minor)" /> <xsl:template match="/stamps"> <xsl:copy> <xsl:for-each select="stamp[count(. | key('stamp-by-group', group)[1]) = 1]"> <stampgroup id="{group}"> <xsl:for-each select="key('stamp-by-group', group)[count(. | key('stamp-by-scott', concat(group, '|', scott))[1]) = 1]"> <xsl:apply-templates select="key('stamp-by-scott', concat(group, '|', scott))[count(. | key('stamp-by-minor', concat(group, '|', scott, '|', minor))[1]) = 1]"/> </xsl:for-each> </stampgroup> </xsl:for-each> </xsl:copy> </xsl:template> <xsl:template match="stamp"> <xsl:copy> <xsl:copy-of select="scott | title"/> <minor><xsl:value-of select="minor" /></minor> </xsl:copy> </xsl:template> </xsl:stylesheet>
edit:
if you're not creating group scott
, can skip secondary grouping , associated key, , go directly tertiary grouping:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:key name="stamp-by-group" match="stamp" use="group" /> <xsl:key name="stamp-by-minor" match="stamp" use="concat(group, '|', scott, '|', minor)" /> <xsl:template match="/stamps"> <xsl:copy> <xsl:for-each select="stamp[count(. | key('stamp-by-group', group)[1]) = 1]"> <stampgroup id="{group}"> <xsl:apply-templates select="key('stamp-by-group', group)[count(. | key('stamp-by-minor', concat(group, '|', scott, '|', minor))[1]) = 1]"/> </stampgroup> </xsl:for-each> </xsl:copy> </xsl:template> <xsl:template match="stamp"> <xsl:copy> <xsl:copy-of select="scott | title"/> <minor><xsl:value-of select="minor" /></minor> </xsl:copy> </xsl:template> </xsl:stylesheet>
Comments
Post a Comment