Showing posts with label XSLT. Show all posts
Showing posts with label XSLT. Show all posts

Wednesday, December 18, 2013

Unique Request ID in XPath



I had a requirement to generate unique 10 char ids as Request Ids. The Oracle out of the box UID’s are long 32 char ids. The longer it is, the difficult it becomes.
Custom XPath function in java which did the work for me.

  public static String getRandomUniqueId(){
    SecureRandom random = new SecureRandom();
    String id = "";
    while (id.length() !=10)
     id = new BigInteger(50, random).toString(32).toUpperCase();
  return id;
  }

Tuesday, December 4, 2012

Incrementing Logic in XSL for SEQUENCE in multiple for-loops



I had a requirement where there was multiple for-loops and they wanted to increment the sequence value in loop under the inner loop but counter should be unique irrespective of the loop.
I will take the example of ShipmentItem &ShipmentStop. So if there are 2 ShipmentItems and 3 ShipmentStops then it should be incremented from 1 to 6. Since XSL
Doesn’t support out-of-the box increment as it is not a programming logic,I had to look for a work-around.
ShipmentItem records will form the outer loop and ShipmentStop records the inner loop.
So for using the increment logic I used count(preceding-sibling:: NODE) function .

I am attaching the XSL code snippet for easier implementation and understanding.

$SEQ_COUNTER variable will have the unique sequence ID.

  
  <xsl:template match="/">
    <top:testCollection>
      <xsl:for-each select="/eboebo:UpdateShipmentEBM/eboebo:DataArea/eboebo:UpdateShipment/ns5:ShipmentItem">
  <xsl:variable name="LOOP1_COUNTER">
     <xsl:value-of select="count(preceding-sibling::ns5:ShipmentItem)"/>
   </xsl:variable>
  <xsl:variable name="COUNTER">
     <xsl:value-of select="count(../ns5:Custom/ns6:ShipmentStop)"/>
  </xsl:variable>     
     
  <xsl:for-each select="../ns5:Custom/ns6:ShipmentStop">
    
   <!--looping logic for sequence ids  -->
  <xsl:variable name="LOOP2_COUNTER">
    <xsl:value-of select="count(preceding-sibling::ns6:ShipmentStop)+1"/>
  </xsl:variable>
  <xsl:variable name="SEQ_COUNTER">
   <xsl:choose>
   <xsl:when test="$LOOP1_COUNTER='0'">
     <xsl:value-of select="$LOOP2_COUNTER"/>
   </xsl:when>
   <xsl:otherwise>
     <xsl:value-of select="($LOOP1_COUNTER*$COUNTER)+$LOOP2_COUNTER"/>
   </xsl:otherwise>
   </xsl:choose>
    </xsl:variable>
    <top:test1>
    
   <top:ID_counter>
    
     <xsl:value-of select="number($NN) +number($SEQ_COUNTER)"/>
   </top:ID_counter>
     
     ................
     .............
     
   <top:test1>   
   
     </xsl:for-each>
          
        </xsl:for-each>

Friday, November 16, 2012

Convert date times based on TimeZone in XSL

Recently I had a requirement where I had to convert time to different timezones based on the clients different locations. One issue we had was with the table column length which was limited to 20 chars.So we had to format the time to remove the offset as it full timestamp usually has a lenght close to 30 chars.Since we were not able to insert the time directly, we had to come up with a workaround.

I am pasting the XSL code snippet  which can be used to modify the timestamp based on the offset which defines the timezone time difference.

<xsl:variable name="TIMEZONE_DIFF"
                        select="xp20:timezone-from-dateTime(startTime)"/>
          <xsl:variable name="DIFF_SIGN"
                        select="substring($TIMEZONE_DIFF,1.0,1.0)"/>
          <xsl:variable name="DIFF_HOUR"
                        select="substring($TIMEZONE_DIFF,2.0,2.0)"/>
          <xsl:variable name="DIFF_MIN"
                        select="substring($TIMEZONE_DIFF,5.0,2.0)"/>
          <xsl:variable name="DURATION"
                        select='concat("PT",$DIFF_HOUR,"H",$DIFF_MIN,"M")'/>


              <xsl:choose>
                  <xsl:when test="$DIFF_SIGN='+'">                
                    <ns0:StartTime>
                      <xsl:value-of select='xp20:format-dateTime(xp20:add-dayTimeDuration-to-dateTime(startTime,$DURATION),"[M01]-[D01]-[Y0001] [H01]:[m01]:[s01]")'/>
                    </ns0: StartTime >
                  </xsl:when>
                  <xsl:otherwise>
                    <ns0: StartTime >
                      <xsl:value-of select='xp20:format-dateTime(xp20:subtract-dayTimeDuration-from-dateTime(startTime,$DURATION),"[M01]-[D01]-[Y0001] [H01]:[m01]:[s01]")'/>
                    </ns0: StartTime >
                  </xsl:otherwise>
                </xsl:choose>
Hope this helps

Monday, July 18, 2011

JDev11g PS2 - XSLT designer limitations

There will be scenarios when you need to pass a counter variable /any status value into a transformation. Since Jdev 11g design supports multiple source transformation it’s easy to pass multiple variables as input into XSLT. The only issue that developers will encounter is the below error.

"Source parts of variables are either simple type or complex type, thus cannot be used to create mapper file".

1.    If you try to use a variable which is a simple type created in BPEL, it will through up this error.
Workaround
As a workaround you can create an element in XSD which is of complex type
XSD file code snippet

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns="http://www.geo.com/test"
            targetNamespace="http://www.geo.com/test"
            elementFormDefault="qualified">
  <xsd:element name="loopCounter" type="CounterType"/>
  <xsd:complexType name="CounterType">
    <xsd:sequence>
      <xsd:element name="count" type="xsd:int" />
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>

Create a variable in BPEL by using this element. This will work with XSLT designer.

2.    In case you are using a message type and the message type is added in a WSDL file which is not attached to any partner link, then the same error will occur.

WSDL file code snippet
<definitions targetNamespace="http://geo.com/test/"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:tns="http://geo.com/test/"
             xmlns:tns1="http://www.geo.com/test"
             …………………….
/">
  <types>
    <xsd:schema targetNamespace="http://geo.com/test/types"
                elementFormDefault="qualified"/>
        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <xsd:import namespace="http://www.geo.com/test" schemaLocation="xsd/test.xsd"/>
        </xsd:schema>
  </types>
 
  <message name="Counter">
        <part name="body" element="tns1:loopCounter"/>
    </message>

</definitions>

Workaround
 You will have to copy the types and message type definition to the WSDL file which is associated with any of the partner link present in the process. This is not a good practice as we are modifying the end system /interacting system wsdls, for internal use of the process flow.

So the best approach will be to use the first workaround as it is clean and neat and serves the purpose.