Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6806834

Muenchian grouping using xsl:key broken in java 6

      FULL PRODUCT VERSION :
      java version "1.6.0_11"
      Java(TM) SE Runtime Environment (build 1.6.0_11-b03)
      Java HotSpot(TM) Server VM (build 11.0-b16, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Linux X2 2.6.17-1.2187_FC5smp #1 SMP Mon Sep 11 01:32:34 EDT 2006 i686 athlon i386 GNU/Linux


      A DESCRIPTION OF THE PROBLEM :
      I'm using a fairly standard grouping technique for stylesheets. I recently upgraded to Java 6 and it no longer works. I've spent all weekend on it and can't figure out why, I only know that my xsl:for-each with my key() call is being called multiple times for the same key and shouldn't be.

      This behavior works in jdk 1.4.2_05 and 1.5.0_06 on the same machine configuration.

      I have been unsuccessful in trying alternatives based on generate-id() as well.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile the Xslt class file (mine was compiled under 1.4.2).

      Then run the class on the provided xml and xsl test files.

      java -classpath . Xslt /tmp/foo.xml /tmp/foo.xsl

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      This transformed output should occur only ONCE, but appears twice in java 6.

      ...
        Subsystem Class1_Product1
          Promote developerUser_20090215123204-0500_Product1:ws1_cset1
          Promote developerUser_20090215123229-0500_Product1:ws2_cset9
      ...

      ACTUAL -
      ...
      Subsystem Class1_Product1
          Promote developerUser_20090215123204-0500_Product1:ws1_cset1
          Promote developerUser_20090215123229-0500_Product1:ws2_cset9
        Subsystem Class1_Product1
          Promote developerUser_20090215123204-0500_Product1:ws1_cset1
          Promote developerUser_20090215123229-0500_Product1:ws2_cset9
      ...

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      No error message, just incorrect output because this for-each statement is resulting in too many nodes:

          <xsl:template match="cr:Cancellations">
            <xsl:text>The following pending cset operations </xsl:text>
            <xsl:value-of select="$verb"/>
            <xsl:text> be cancelled:&#10;</xsl:text>
            <!-- For each Action, grouped by subsystem -->
            <xsl:for-each select="cr:Action[count(. | key('cancel-actions-by-subsystem-name', @subsystemName)[1]) = 1]">
              <xsl:sort select="@subsytemName"/>
      <xsl:text> Subsystem </xsl:text>

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      Here is the Xslt.java file:

      import java.io.* ;
      import javax.xml.transform.* ; // Transformer, TransformerFactory, Source, Result, Templates
      import javax.xml.transform.dom.* ; // DOMSource, DOMResult
      import javax.xml.transform.stream.* ; // StreamSource, StreamResult

      /**
       * Do XSL translations using JDK1.4 tools (instead of xalan)
       */

      public class Xslt
      {
        /**
         * @param args[0] input xml file to transform
         * @param args[1] input xslt file describing transformations
         */

        public static void main(String[] args) {
          if (args.length != 2) {
            System.err.println("Usage: java Xslt xmlFile xsltFile") ;
            return ;
          }

          try {
            File xmlFile = new File(args[0]) ;
            File xsltFile = new File(args[1]) ;
            StreamSource xmlSource = new StreamSource(xmlFile) ;
            StreamSource xsltSource = new StreamSource(xsltFile) ;
            StreamResult stdoutResult = new StreamResult(System.out) ;
            TransformerFactory tf = TransformerFactory.newInstance() ;
            Templates templates = tf.newTemplates(xsltSource) ;
            Transformer transformer = templates.newTransformer() ;
            transformer.transform(xmlSource, stdoutResult) ;
            System.out.flush() ;
          }
          catch (Exception e) {
            System.err.println(e.toString()) ;
          }
        }
      } // class Xslt


      Here is the 'foo.xml' input data for the test run:

      <?xml version="1.0" encoding="UTF-8" standalone="no"?><WorkspaceUpdateReportPseudoResponse xmlns="QuantumChangeResponse" reportMode="1"><VpbUpdateResponse><Cancellations><Action csetName="developerUser_20090215123204-0500_Product1:ws1_cset1" direction="PROMOTE" subsystemName="Class1_Product1"/><Action csetName="developerUser_20090215123229-0500_Product1:ws2_cset9" direction="PROMOTE" subsystemName="Class1_Product1"/></Cancellations></VpbUpdateResponse><Remove>cls1/src/file5.txt</Remove><Remove>cls1/file3.txt</Remove><Remove>cls1/file2.sh</Remove><Remove>cls1/file1.txt</Remove><SubsystemRemove><WsRelPath>cls1</WsRelPath><SubsystemName>Class1_Product1</SubsystemName></SubsystemRemove><SubsystemAdd><WsRelPath>cls1</WsRelPath><SubsystemName>Class1_Product10</SubsystemName></SubsystemAdd><SubsystemAdd><WsRelPath>cls2-subdir-override</WsRelPath><SubsystemName>Class2_Product1</SubsystemName></SubsystemAdd><SubsystemAdd><WsRelPath>cls3</WsRelPath><SubsystemName>Class3_Product1</SubsystemName></SubsystemAdd></WorkspaceUpdateReportPseudoResponse>

      Here is the stylesheet that fails in java 6,
      the case you're interested in is the template for "cr:Cancellations":

      <xsl:stylesheet version="1.0"
           xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
           xmlns:cr="QuantumChangeResponse">

          <xsl:output method="text"/>

          <!-- This groups Actions by subsystem names accessible by named keys -->
          <xsl:key name="cancel-actions-by-subsystem-name" match="cr:Cancellations/cr:Action"
      use="@subsystemName"/>
          <xsl:key name="baseline-actions-by-subsystem-name" match="cr:BaselineChanges/cr:Action"
      use="@subsystemName"/>

          <!-- Set a variable so we can use "will" or "would" as the verb tense depending on report mode -->
          <xsl:variable name="reportMode" select="cr:WorkspaceUpdateReportPseudoResponse/@reportMode"/>
          <xsl:variable name="verb">
            <xsl:choose>
      <xsl:when test="$reportMode = 'true' or $reportMode = '1'">would</xsl:when>
      <xsl:otherwise>will</xsl:otherwise>
            </xsl:choose>
          </xsl:variable>

          <xsl:template match="/cr:WorkspaceUpdateReportPseudoResponse">
            <xsl:choose>
      <xsl:when test="count(cr:*) = 0">
      <!-- Say nothing if it technically a baseline update but NOT a workspace physical update -->
      <xsl:if test="not(boolean(@netZero))">
         <xsl:text>The workspace is up to date.&#10;</xsl:text>
      </xsl:if>
      </xsl:when>
      <xsl:otherwise>
      <!-- Subsystem actions -->
      <xsl:if test="count(cr:SubsystemRemove | cr:SubsystemAdd | cr:SubsystemRelpathRename) > 0">
      <xsl:text>The following subsystem actions </xsl:text>
      <xsl:value-of select="$verb"/>
      <xsl:text> be performed:&#10;</xsl:text>
      </xsl:if>
      <xsl:apply-templates select="cr:SubsystemRemove"/> <!-- 0-N instances -->
      <xsl:apply-templates select="cr:SubsystemAdd"/> <!-- 0-N instances -->
      <xsl:apply-templates select="cr:SubsystemRelpathRename"/> <!-- 0-N instances -->
      <!-- VPB cancellations and baseline change information -->
      <xsl:apply-templates select="cr:VpbUpdateResponse"/> <!-- 0-1 instances -->
      <!-- File actions -->
      <xsl:if test="count(cr:Remove | cr:Add | cr:Rename | cr:Update | cr:Merge | cr:Conflict) > 0">
      <xsl:text>The following file actions </xsl:text>
      <xsl:value-of select="$verb"/>
      <xsl:text> be performed:&#10;</xsl:text>
      </xsl:if>
      <xsl:apply-templates select="cr:Remove"/> <!-- 0-N instances -->
      <xsl:apply-templates select="cr:Add"/> <!-- 0-N instances -->
      <xsl:apply-templates select="cr:Rename"/> <!-- 0-N instances -->
      <xsl:apply-templates select="cr:Executable"/> <!-- 0-N instances -->
      <xsl:apply-templates select="cr:Update"/> <!-- 0-N instances -->
      <xsl:apply-templates select="cr:Merge"/> <!-- 0-N instances -->
      <xsl:apply-templates select="cr:Conflict"/> <!-- 0-N instances -->
      </xsl:otherwise>
            </xsl:choose>
          </xsl:template>

          <!--
               BranchUpdate information from the VpbUpdateResponse.
      Has VPB cset cancellations and/or baseline cset update information.
      See RequestAgentMasterChange-text.xsl for in depth comments xslt
               grouping by subsystem.
          -->

          <xsl:template match="cr:VpbUpdateResponse">
            <xsl:apply-templates select="cr:BaselineChanges"/> <!-- 0 or 1 instances -->
            <xsl:apply-templates select="cr:Cancellations"/> <!-- 0 or 1 instances -->
          </xsl:template>

          <xsl:template match="cr:BaselineChanges">
            <xsl:text>The following baseline cset changes apply:&#10;</xsl:text>
            <!-- For each Action, grouped by subsystem -->
            <xsl:for-each select="cr:Action[count(. | key('baseline-actions-by-subsystem-name', @subsystemName)[1]) = 1]">
              <xsl:sort select="@subsytemName"/>
      <xsl:text> Subsystem </xsl:text>
      <xsl:value-of select="@subsystemName"/>
      <xsl:text>&#10;</xsl:text>
      <!-- For each cr:Action with the currently considered subsystem name in the outer loop -->
      <xsl:for-each select="key('baseline-actions-by-subsystem-name', @subsystemName)">
      <!-- Sort subsystem activity by cset name within promotion/demotion group -->
      <xsl:sort select="@direction"/>
      <xsl:sort select="@csetName"/>
      <xsl:apply-templates select="."/>
      </xsl:for-each>
            </xsl:for-each>
          </xsl:template>

          <xsl:template match="cr:Cancellations">
            <xsl:text>The following pending cset operations </xsl:text>
            <xsl:value-of select="$verb"/>
            <xsl:text> be cancelled:&#10;</xsl:text>
            <!-- For each Action, grouped by subsystem -->
            <xsl:for-each select="cr:Action[count(. | key('cancel-actions-by-subsystem-name', @subsystemName)[1]) = 1]">
              <xsl:sort select="@subsytemName"/>
      <xsl:text> Subsystem </xsl:text>
      <xsl:value-of select="@subsystemName"/>
      <xsl:text>&#10;</xsl:text>
      <!-- For each cr:Action with the currently considered subsystem name in the outer loop -->
      <xsl:for-each select="key('cancel-actions-by-subsystem-name', @subsystemName)">
      <!-- Sort subsystem activity by cset name within promotion/demotion group -->
      <xsl:sort select="@direction"/>
      <xsl:sort select="@csetName"/>
      <xsl:apply-templates select="."/>
      </xsl:for-each>
            </xsl:for-each>
          </xsl:template>

          <!-- Assumes grouping by subsystem name by caller -->
          <xsl:template match="cr:Action">
            <xsl:choose>
      <xsl:when test="@direction = 'PROMOTE'">
      <xsl:text> Promote </xsl:text>
      </xsl:when>
      <xsl:when test="@direction = 'DEMOTE'">
      <xsl:text> Demote </xsl:text>
      </xsl:when>
      <xsl:otherwise>
         <xsl:text>RequestAgentWorkspaceUpdate-text.xsl translation error:&#10;</xsl:text>
      <xsl:text>Unanticipated Action[@direction] value &quot;</xsl:text>
      <xsl:value-of select="@direction"/>
      <xsl:text>&quot;&#10;</xsl:text>
      </xsl:otherwise>
            </xsl:choose>
            <xsl:value-of select="@csetName"/>
            <xsl:text>&#10;</xsl:text>
          </xsl:template>

          <!--
               FILE ACTIONS
          -->

          <xsl:template match="cr:Remove">
            <xsl:text> Removal of &quot;</xsl:text>
            <xsl:value-of select="."/>
            <xsl:text>&quot;&#10;</xsl:text>
          </xsl:template>
          
          <xsl:template match="cr:Add">
            <xsl:text> Addition of &quot;</xsl:text>
            <xsl:value-of select="."/>
            <xsl:text>&quot;&#10;</xsl:text>
          </xsl:template>
          
          <xsl:template match="cr:Executable">
            <xsl:text> Executable status change of &quot;</xsl:text>
            <xsl:value-of select="."/>
            <xsl:text>&quot;&#10;</xsl:text>
          </xsl:template>
          
          <xsl:template match="cr:Update">
            <xsl:text> Update of &quot;</xsl:text>
            <xsl:value-of select="."/>
            <xsl:text>&quot;&#10;</xsl:text>
          </xsl:template>
          
          <xsl:template match="cr:Merge">
            <xsl:text> Merge of &quot;</xsl:text>
            <xsl:value-of select="."/>
            <xsl:text>&quot;&#10;</xsl:text>
          </xsl:template>
          
          <xsl:template match="cr:Conflict">
            <xsl:text> Merge of &quot;</xsl:text>
            <xsl:value-of select="."/>
            <xsl:text>&quot; with conflicts&#10;</xsl:text>
          </xsl:template>
          
          <xsl:template match="cr:Rename">
            <xsl:text> Rename of &quot;</xsl:text>
            <xsl:value-of select="@oldName"/>
            <xsl:text>&quot; to &quot;</xsl:text>
            <xsl:value-of select="@newName"/>
            <xsl:text>&quot;&#10;</xsl:text>
          </xsl:template>


          <!--
                SUBSYSTEM ACTIONS
          -->

          <!-- Not currently sorted, at mercy of XML generator -->
          <xsl:template match="cr:SubsystemRemove">
            <xsl:text> Removal of subsystem </xsl:text>
            <xsl:value-of select="cr:SubsystemName"/>
            <xsl:text> in directory &quot;</xsl:text>
            <xsl:value-of select="cr:WsRelPath"/>
            <xsl:text>&quot;&#10;</xsl:text>
          </xsl:template>
          
          <xsl:template match="cr:SubsystemAdd">
            <xsl:text> Addition of subsystem </xsl:text>
            <xsl:value-of select="cr:SubsystemName"/>
            <xsl:text> in directory &quot;</xsl:text>
            <xsl:value-of select="cr:WsRelPath"/>
            <xsl:text>&quot;&#10;</xsl:text>
          </xsl:template>
          
          <xsl:template match="cr:SubsystemRelpathRename">
            <xsl:text> Rename of subsystem path for </xsl:text>
            <xsl:value-of select="cr:SubsystemName"/>
            <xsl:text>&#10; from &quot;</xsl:text>
            <xsl:value-of select="cr:OldName"/>
            <xsl:text>&quot; to &quot;</xsl:text>
            <xsl:value-of select="cr:NewName"/>
            <xsl:text>&quot;&#10;</xsl:text>
          </xsl:template>

          <!-- Shouldn't hit this unless we've screwed up namespaces or something -->
          <xsl:template match="*">
            <xsl:text> **** RequestAgentWorkspaceUpdate.xsl UNEXPECTED MATCH **** </xsl:text>
            <xsl:value-of select="name()"/>
          </xsl:template>

      </xsl:stylesheet>


      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      I have no workaround. I tested many variants, looked long and hard in the sun database and on the web for possible known issues and solutions, and found none. (There was one bug
      in the sun database on xslt transforms and predicates on xsl:key directives, but I don't have a predicate on my xsl:key directive).

      I've concluded that most people who use Muenchian grouping aren't having problems.
      Perhaps it's something to do with namespaces, or sorts. However removing my sort
      operations didn't alter the misbehavior, so I don't think it's sorts. I tried other path references
      in the xsl:key 'matches' directive, and alternative 'use' specifications as well. No luck.

      Worst case I guess I need to use java5, or process my xml input in some other fashion.

      I can't conclusively say it isn't some bug in my stylesheet, I'm not an xslt expert,
      but I've been unable to get my xsl:for-each to yield only one context node
      in the outer loop with java 6.

      Release Regression From : 6u11
      The above release value was the last known release where this
      bug was not reproducible. Since then there has been a regression.

            joehw Joe Wang
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: