Thursday, June 7, 2012

The Mess of XLST 1.0 / 2.0, JDEV and OSB

I ran into some mess with XSLT 1.0 / 2.0, JDEV and OSB. Oh, boy, I just have to blog it.

Let me sum up the lesson I learned before I dive into the details:
  • If you crafted your XSLT in JDEV, you tested it, and  it worked fine in JDEV.  Then you port it to OSB, the same XSLT code may blow up!
I have to admit that I didn't just do a "normal" XSLT and ported it OSB. I did something "smart" with XSLT. At first, I was proud of what I did. Then I spent hours to realize there is such a thing as being "too smart".

In JDEV,  the default version of XSLT is "1.0". You can change it to "2.0", so you can take advantage of some of the 2.0 features. I did that in the past. It worked well.

Here is what I did this time:

<xsl:stylesheet version="2.0"
                xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20"
...
  <xsl:template match="/">

  <!-- this only works with 2.0 -->
    <xsl:variable name="v">
      <var name="v1">legal</var>
      <var name="v2">preferred</var>
    </xsl:variable>
     <ns2:employeeElem>
      <ns2:id>
        <xsl:value-of select="/wd:Report_Data/wd:Report_Entry/wd:Employee_ID"/>
      </ns2:id>

      <xsl:for-each select="$v/var">
        <xsl:choose>
          <xsl:when test=".='legal'">
            <ns2:name>
              <ns2:firstName>        
                <xsl:value-of select="/wd:Report_Data/wd:Report_Entry/wd:Legal_First_Name"/>
              </ns2:firstName>
            </ns2:name>
          </xsl:when>
         <xsl:when test=".='preferred'">
            <ns2:name>
              <ns2:firstName>
                <xsl:value-of select="/wd:Report_Data/wd:Report_Entry/wd:Preferred_First_Name"/>
              </ns2:firstName>
            </ns2:name>
          </xsl:when>

        </xsl:choose>
      </xsl:for-each>
    </ns2:employeeElem>
  </xsl:template>
</xsl:stylesheet>

I created an array variable, so I can control a for-each loop to run precisely twice. I call this "smart", because it is packed with two complicated tricks. We know that XSLT doesn't have index-incremented loop. If you change the size of this array, then you can actually emulate an index-incremented loop!

Another trick I am playing is to create the result with multiple <name> elements. If you don't use for-each, and hard code two <name> elements, then you can't edit your XSLT in design view anymore. It complains that you mapped the <name> multiple times. But if you use above for-each loop , you can still use design view!

Well, more traps here, if you manually change your XSLT version to 2.0, and you use design view to make any changes, whenever you save, it switches version back to 1.0. So you have to remember to manually change it to 2.0 again. 

Sounds messy enough?

Anyway, after I finished my 2.0 trick, and tested in JDEV, it worked beautifully. Then I ported it OSB, it blew up. It took me hours to find out that OSB doesn't like that "smart" 2,0 feature. 

Now I have to bite the bullet and manually edit the whoel XSLT script.