XSLT not() function in second predicate in a row does not always work correctly

XMLWordPrintable

      ADDITIONAL SYSTEM INFORMATION :
      Does not matter, the bug is reproduced under windows and linux, in jdk 11 and in jdk21

      A DESCRIPTION OF THE PROBLEM :
      An xpath expression involving multiple predicates after a nodetest may match unexpectedly if the first predicate is a condition that involves or and the second predicate uses not() function.

      It looks like the bug is in the code that originally comes from xalan. It can also be reproduced with xalan when "org.apache.xalan.xsltc.trax.TransformerFactoryImpl" is used as a parameter to TransformerFactory.newInstance().

      When org.apache.xalan.processor.TransformerFactoryImpl is used, the problem is not reproduced with xalan.

      JDK does not include org.apache.xalan.processor.TransformerFactoryImpl equivalent, so it always fails.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      See test case code.
      Note that the two xslt templates are functionally equivalent, so they have to produce the same result.

      1. Run it without parameters to see the expected output (java RunIt).
      2. Run it with  a single parameter 'bug' to see the bug reproduced (java RunIt bug).

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      java.version property: XXX
      Transformer class: com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl
      XSLT transformation result:
      <?xml version="1.0" encoding="UTF-8"?><r>
      1
      2
      </r>
      ACTUAL -
      java.version property: XXX
      Transformer class: com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl
      XSLT transformation result:
      <?xml version="1.0" encoding="UTF-8"?><r>
      <x>2</x>
      <x>3</x>
      </r>

      CUSTOMER SUBMITTED WORKAROUND :
      In this case the right side of 'or' is useless, it can be removed. But it is not always the case.
      Alternatively, both predicates can be merged in a single predicate.

      FREQUENCY :
      ALWAYS

      ---------- BEGIN SOURCE ----------
      import java.io.StringReader;
      import java.io.StringWriter;

      import javax.xml.transform.Source;
      import javax.xml.transform.Transformer;
      import javax.xml.transform.TransformerFactory;
      import javax.xml.transform.stream.StreamResult;
      import javax.xml.transform.stream.StreamSource;

      public class RunIt {

        public static void main(String[] args) throws Exception {
          Source xmlSource = new StreamSource(new StringReader(INPXML));
          Source xsltSource = new StreamSource(new StringReader(args.length > 0 && args[0].equals("bug") ? XSLT1 : XSLT2));
          TransformerFactory tf = TransformerFactory.newInstance();
          Transformer tr = tf.newTransformer(xsltSource);

          StringWriter sw = new StringWriter();
          StreamResult result = new StreamResult(sw);

          tr.transform(xmlSource, result);
          System.out.println("java.version property: " + System.getProperty("java.version"));
          System.out.println("Transformer class: " + tr.getClass().getName());
          System.out.println("XSLT transformation result:\n" + sw.toString());
        }

        private static final String XSLT1 =
          "<?xml version='1.0' encoding='UTF-8'?>\n" +
          "<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform&#39; >\n" +
          "<xsl:template match='/'>\n" +
          "<r><xsl:apply-templates select='@*|node()'/></r>\n" +
          "</xsl:template>\n" +
          "<xsl:template match='//a[1 > 0 or 10 > 20][not(1 > 0)]'>\n" +
          "<x><xsl:value-of select='. + 1'/></x>\n" +
          "</xsl:template>\n" +
          "</xsl:stylesheet>";

        private static final String XSLT2 =
          "<?xml version='1.0' encoding='UTF-8'?>\n" +
          "<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform&#39;>\n" +
          "<xsl:template match='/'>\n" +
          "<r><xsl:apply-templates select='@*|node()'/></r>\n" +
          "</xsl:template>\n" +
          "<xsl:template match='//a[1 > 0][not(1 > 0)]'>\n" +
          "<x><xsl:value-of select='. + 1'/></x>\n" +
          "</xsl:template>\n" +
          "</xsl:stylesheet>";

        private static final String INPXML =
          "<k>\n" +
          "<a>1</a>\n" +
          "<a>2</a>\n" +
          "</k>";
      }
      ---------- END SOURCE ----------

            Assignee:
            Joe Wang
            Reporter:
            Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: