I'm working with an XSLT that someone else designed. Back in that time the xml structure was like this:
<errata_section id="i875" errata_type="bug">
<title>Title</title>
<description>
<para> Following a warm Reset </para>
</description>
<devices_impacted>
<device_name>VAZER</device_name>
</devices_impacted>
<devices_impacted>
<device_name>VAZER2</device_name>
</devices_impacted>
<devices_impacted>
<device_name>VAZER3</device_name>
</devices_impacted>
<module_impacted>Boot</module_impacted>
</errata_section>
The existing transform defines a key as follows:
<xsl:key name="module-index" match="errata_section" use="module_impacted"/>
And they have used the following Muenchian Method algorithm to go through all the unique module_impacted
elements.
<xsl:element name="article">
<xsl:attribute name="id">errata_module_impacted</xsl:attribute>
<xsl:attribute name="arch"><xsl:value-of select='$device_to_output'/></xsl:attribute>
<title>Modules Impacted</title>
<xsl:for-each select="//errata_section[generate-id(.)=generate-id(key('module-index', module_impacted)[1])]">
<xsl:sort select="module_impacted"/>
<xsl:variable name="current_module"><xsl:value-of select="module_impacted"/></xsl:variable>
<!-- The is an ugly kludge: we check each section that applies to current chip and update the "is_module_in_device"
variable if we find it impacts the current module. In the end we have either an empty variable (module is not in
current device) or a variable containing lots of "o" concatenated (module is in current device) -->
<xsl:variable name="is_module_in_device">
<xsl:for-each select="//errata_section/devices_impacted[device_name=$device_to_output]">
<xsl:choose>
<!-- Start Patch part 1(removing modules having and arch attribute containing a different than the current device) -->
<xsl:when test='../module_impacted[@arch!=$device_to_output]'>
<xsl:if test='../module_impacted/text()[.=$current_module]'>
<xsl:text></xsl:text>
</xsl:if>
</xsl:when>
<!-- End Patch part 1 -->
<xsl:otherwise>
<xsl:if test='../module_impacted/text()[.=$current_module]'><xsl:text>o</xsl:text></xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
<!-- Start Patch part 2 -->
<xsl:variable name="removed_modules">
<xsl:for-each select="//errata_section/devices_impacted[device_name=$device_to_output]">
<xsl:choose>
<xsl:when test='../module_impacted[@arch!=$device_to_output]'>
<xsl:if test='../module_impacted/text()[.=$current_module]'>
<xsl:text>r</xsl:text>
</xsl:if>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
<!-- End Patch part 2 -->
<xsl:if test='contains($is_module_in_device, "o")'>
<xsl:variable name="num_of_sections">
<!-- Start Patch part 3 -->
<xsl:value-of select="string-length($is_module_in_device) + string-length($removed_modules)"/>
<!-- End Patch part 3 -->
</xsl:variable>
<!-- Do Table processing -->
<table>
<xsl:attribute name="id">
<xsl:value-of select="generate-id(module_impacted)"/>
</xsl:attribute>
<title>
<xsl:text>Module </xsl:text>
<xsl:value-of select="module_impacted"/>
<xsl:text> (</xsl:text><xsl:value-of select="$num_of_sections"/><xsl:text> section</xsl:text>
<!-- a little grammar ! -->
<xsl:if test="$num_of_sections>1"><xsl:text>s</xsl:text></xsl:if><xsl:text>)</xsl:text>
</title>
<xsl:element name="tgroup">
<xsl:attribute name="cols">
<xsl:choose>
<xsl:when test='$show_review="yes"'>3</xsl:when>
<xsl:otherwise>2</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:element name="colspec">
<xsl:attribute name="colwidth">1*</xsl:attribute>
<xsl:attribute name="colname">_1</xsl:attribute>
</xsl:element>
<xsl:choose>
<xsl:when test='$show_review="yes"'>
<xsl:element name="colspec">
<xsl:attribute name="colwidth">6*</xsl:attribute>
<xsl:attribute name="colname">_2</xsl:attribute>
</xsl:element>
<xsl:element name="colspec">
<xsl:attribute name="colwidth">1*</xsl:attribute>
<xsl:attribute name="colname">_3</xsl:attribute>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="colspec">
<xsl:attribute name="colwidth">8*</xsl:attribute>
<xsl:attribute name="colname">_2</xsl:attribute>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
<tbody>
<row>
<xsl:element name="entry">
<xsl:attribute name="morerows"><xsl:value-of select="$num_of_sections"/></xsl:attribute>
<xsl:value-of select="module_impacted"/>
</xsl:element>
<entry>Section</entry>
<xsl:if test='$show_review="yes"'>
<entry>Review status</entry>
</xsl:if>
</row>
<xsl:for-each select="key('module-index', module_impacted)">
<xsl:if test="devices_impacted/device_name/text()[.=$device_to_output]">
<row>
<entry>
<xsl:value-of select="@id" /><xsl:text>: </xsl:text>
<xsl:element name="xref">
<xsl:attribute name="linkend">sect_<xsl:value-of select="@id" />
</xsl:attribute></xsl:element>
</entry>
<xsl:if test='$show_review="yes"'>
<entry>
<xsl:value-of select="review_status" />
</entry>
</xsl:if>
</row>
</xsl:if>
</xsl:for-each>
</tbody>
</xsl:element> <!-- tgroup element -->
</table>
</xsl:if>
</xsl:for-each>
</xsl:element>
Everything worked fine as long as there was only one module_impacted
element per errata_section
. As time has went on, more than one module_impacted
element has been assigned to a given errata_section
, so that you may have errata_section
elements like the following:
<errata_section id="i876" errata_type="bug">
<title>Title</title>
<description>
<para> Following a warm Reset </para>
</description>
<devices_impacted>
<device_name>VAZER</device_name>
</devices_impacted>
<devices_impacted>
<device_name>VAZER2</device_name>
</devices_impacted>
<devices_impacted>
<device_name>VAZER3</device_name>
</devices_impacted>
<module_impacted>Boot</module_impacted>
<module_impacted>Power-On</module_impacted>
<module_impacted>DMA</module_impacted>
</errata_section>
The source xml has close to a thousand of these errata_section
bugs, and they use the Muenchian Method to determine unique module_impacted
nodes, that are then put into a table, pointing back to the relevant errata_section
element. Since we have gone to the multiple module_impacted
elements per errata_section
things have been quirky, and some module_impacted
elements have not been caught.
My question to the XSLT experts out there, is this because as the Muenchian Method is comparing the id of the errata_section
element containing module_impacted
element(s), it may find the first module_impacted
element but not necessarily any sibling module_impacted
elements? What should happen in a situation like this, where you have more than one of a given element that you are comparing id's for?
I'm just trying to get my head around this, and try and find a better solution!
Thanks for any help!
Revision:
I am hesitant to put more of the code that is occurring inside the for-each statement, as it was written by someone else, is quite kludgey, and I'm not really sure what is going on, but i have updated the above code to show more of that! Inside the for-each loop, they are trying, i think, to keep track and determine the number of times a given module_impacted element has occurred. Then, it will generate a table structure that contains the name of the module impacted, how many occurrences, and entry elements containing the relevant errata_section element.
As per Martin's suggestion, I changed my code but am still not getting all the module_impacted groups per a given device_impacted/device_name. The code below is what i currently running:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:param name="show_review">no</xsl:param>
<xsl:key name="module-index" match="errata_section" use="module_impacted"/>
<xsl:key name="group" match="errata_section/module_impacted" use="."/>
<xsl:key name="device-index" match="errata_section" use="devices_impacted/device_name"/>
<xsl:template name="table_of_section_per_module">
<xsl:param name="device_to_output"/>
<xsl:element name="article">
<xsl:attribute name="id">errata_module_impacted</xsl:attribute>
<xsl:attribute name="arch"><xsl:value-of select='$device_to_output'/></xsl:attribute>
<title>Modules Impacted</title>
<xsl:for-each select="//errata_section[devices_impacted/device_name=$device_to_output]/module_impacted[generate-id() = generate-id(key('group', .)[1])]">
<xsl:sort select="."/>
<xsl:variable name="current-group" select="key('module-index', .)"/>
<xsl:variable name="current-grouping-key" select="."/>
<xsl:variable name="num_of_sections" select="count(.)"/>
<xsl:variable name="current_module" select="."/>
<table>
<xsl:attribute name="id">
<xsl:value-of select="generate-id($current-grouping-key)"/>
</xsl:attribute>
<title>
<xsl:text>Module </xsl:text>
<xsl:value-of select="$current_module"/>
<xsl:text> (</xsl:text><xsl:value-of select="$num_of_sections"/><xsl:text> section</xsl:text>
<!-- a little grammar ! -->
<xsl:if test="$num_of_sections>1"><xsl:text>s</xsl:text></xsl:if><xsl:text>)</xsl:text>
</title>
<xsl:element name="tgroup">
<xsl:attribute name="cols">
<xsl:choose>
<xsl:when test='$show_review="yes"'>3</xsl:when>
<xsl:otherwise>2</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:element name="colspec">
<xsl:attribute name="colwidth">1*</xsl:attribute>
<xsl:attribute name="colname">_1</xsl:attribute>
</xsl:element>
<xsl:choose>
<xsl:when test='$show_review="yes"'>
<xsl:element name="colspec">
<xsl:attribute name="colwidth">6*</xsl:attribute>
<xsl:attribute name="colname">_2</xsl:attribute>
</xsl:element>
<xsl:element name="colspec">
<xsl:attribute name="colwidth">1*</xsl:attribute>
<xsl:attribute name="colname">_3</xsl:attribute>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="colspec">
<xsl:attribute name="colwidth">8*</xsl:attribute>
<xsl:attribute name="colname">_2</xsl:attribute>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
<tbody>
<row>
<xsl:element name="entry">
<xsl:attribute name="morerows"> <xsl:value-of select="$num_of_sections"/></xsl:attribute>
<xsl:value-of select="$current_module"/>
</xsl:element>
<entry>Section</entry>
<xsl:if test='$show_review="yes"'>
<entry>Review status</entry>
</xsl:if>
</row>
<xsl:for-each select="$current-group">
<row>
<entry>
<xsl:value-of select="@id" /><xsl:text>: </xsl:text>
<xsl:element name="xref">
<xsl:attribute name="linkend">sect_<xsl:value-of select="@id" />
</xsl:attribute></xsl:element>
</entry>
<xsl:if test='$show_review="yes"'>
<entry>
<xsl:value-of select="review_status" />
</entry>
</xsl:if>
</row>
</xsl:for-each>
</tbody>
</xsl:element> <!-- tgroup element -->
</table>
</xsl:for-each>
</xsl:element>
</xsl:template>
<xsl:template match="/">
<book>
<xsl:call-template name="table_of_section_per_module">
<xsl:with-param name="device_to_output">VAZER</xsl:with-param>
</xsl:call-template>
</book>
</xsl:template>
</xsl:stylesheet>
THANKS for everyone help on this!!! Russ
for-each
at all. – Martin Honnenerrata_section
with the specifiedmodule_impacted
in the whole document. But as Martin Honnen suggests, you should show the further code to let us know what it does exactly. And btw, Muenchian's grouping is a very efficient solution to grouping. – Lingamurthy CS