Monday 22 November 2021

xslt padding with characters call template for left pad and right pad

 

Could a call-template be written that took two parameters ?

 

a string, and a  number) return the string with empty spaces appended to the 

end so that it  occupied the number of spaces specified by the number  parameter? 

   

So long as you know the number of spaces will never exceed say 100, write

<xsl:template name="pad">

<xsl:param name="s"/>

<xsl:param name="len"/>

<xsl:variable name="spaces">         ...                   </xsl:variable>

<xsl:value-of select="substring(concat($s, $spaces), 1, $len)"/>

</xsl:template>

 

A more elegant solution, which handles any number of spaces, is

for the template to append

one space to the string and then call itself to add another "len-1", until len reaches zero.

You should check out XPath's string-handling functions.

Something like

<xsl:value-of

     select="substring(concat($string, '            '), 1, 12))"/>

Always gives you a string twelve characters long, either the first twelve

characters of $string, or $string padded out with spaces. Variables can be also be

 useful to make things easier to read, reuse and maintain -- for example

<xsl:variable name="spacex12" select="'            '"/>

and then

<xsl:value-of select="substring(concat($string, $spacex12), 1, 12))"/>

 

Example

Just as a challenge, I took it a little further. The following outputs the

color values in this document

  <test>

  <color>red</color>

  <color>blue</color>

  <color>yellow</color>

  </test>

at 12 characters each, right aligned:

  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 

  version="1.0">

    <xsl:variable name="fieldWidth">12</xsl:variable>

 

    <xsl:template match="color">

      <xsl:variable name="valueLength"

           select="string-length(normalize-space(.))"/>

      <xsl:variable name="padding"

           select="$fieldWidth - $valueLength"/>

 

      <xsl:text>[</xsl:text>

      <xsl:value-of select="substring('                  ',1,$padding)"/>

      <xsl:value-of select="."/>

      <xsl:text>]</xsl:text>

    </xsl:template>

 

  </xsl:stylesheet>

giving this output:

  <?xml version="1.0" encoding="utf-8"?>

  [         red]

  [        blue]

  [      yellow]

for Fixed-length String Output

Here are the string padding functions that I use frequently:

 

 

 

  <xsl:template name="prepend-pad">   

  <!-- recursive template to right justify and prepend-->

  <!-- the value with whatever padChar is passed in   -->

    <xsl:param name="padChar"> </xsl:param>

    <xsl:param name="padVar"/>

    <xsl:param name="length"/>

    <xsl:choose>

      <xsl:when test="string-length($padVar) &lt; $length">

        <xsl:call-template name="prepend-pad">

          <xsl:with-param name="padChar" select="$padChar"/>

          <xsl:with-param name="padVar" select="concat($padChar,$padVar)"/>

          <xsl:with-param name="length" select="$length"/>

        </xsl:call-template>

      </xsl:when>

      <xsl:otherwise>

        <xsl:value-of select="substring($padVar,string-length($padVar) -

$length + 1)"/>

      </xsl:otherwise>

    </xsl:choose>

  </xsl:template>

 

 

  <xsl:template name="append-pad">   

  <!-- recursive template to left justify and append  -->

  <!-- the value with whatever padChar is passed in   -->

    <xsl:param name="padChar"> </xsl:param>

    <xsl:param name="padVar"/>

    <xsl:param name="length"/>

    <xsl:choose>

      <xsl:when test="string-length($padVar) &lt; $length">

        <xsl:call-template name="append-pad">

          <xsl:with-param name="padChar" select="$padChar"/>

          <xsl:with-param name="padVar" select="concat($padVar,$padChar)"/>

          <xsl:with-param name="length" select="$length"/>

        </xsl:call-template>

      </xsl:when>

      <xsl:otherwise>

        <xsl:value-of select="substring($padVar,1,$length)"/>

      </xsl:otherwise>

    </xsl:choose>

  </xsl:template>

 

 

Eg: to call the template from xsl variable or element

 

<ns39:elementname>

                                      <xsl:call-template name="prepend-padzero">

                                            <xsl:with-param name="padChar" select="0"/>

                                            <xsl:with-param name="padVar" select="nsmpr5:InvoiceNumber"/>

                                            <xsl:with-param name="length" select="6"/>

                                      </xsl:call-template>

                                      <!--  <xsl:value-of xml:id="id_754" select="concat (&quot;AUT&quot;,nsmpr5:InvoiceNumber)"/> -->

                                </ns39: elementname >

 

 

 

 

 

These will both ensure that the string ends up to be whatever length you pass

in (ie. if the string is longer than expected it will also truncate).

Pete Forman adds an option for left padding

Here's an example of padding on the left using a similar technique.

It prints my size attribute to a width of 4.

<xsl:value-of select="substring(concat('    ', @size),

                       string-length(@size) + 1, 4)"/>

 

This is clearly not as versatile as some of the solutions but it suffices for simple cases.

 

How to pad space to a text node to make it have specific length

 

These are the templates I use to pad on the left or right with any character passed in:

  <xsl:template name="prepend-pad">   

  <!-- recursive template to right justify and prepend-->

  <!-- the value with whatever padChar is passed in   -->

    <xsl:param name="padChar"> </xsl:param>

    <xsl:param name="padVar"/>

    <xsl:param name="length"/>

    <xsl:choose>

      <xsl:when test="string-length($padVar) &lt; $length">

        <xsl:call-template name="prepend-pad">

          <xsl:with-param name="padChar" select="$padChar"/>

          <xsl:with-param name="padVar" select="concat($padChar,$padVar)"/>

          <xsl:with-param name="length" select="$length"/>

        </xsl:call-template>

      </xsl:when>

      <xsl:otherwise>

        <xsl:value-of

                 select="substring($padVar,string-length($padVar) -

                 $length + 1)"/>

      </xsl:otherwise>

    </xsl:choose>

  </xsl:template>

 

  <xsl:template name="append-pad">   

  <!-- recursive template to left justify and append  -->

  <!-- the value with whatever padChar is passed in   -->

    <xsl:param name="padChar"> </xsl:param>

    <xsl:param name="padVar"/>

    <xsl:param name="length"/>

    <xsl:choose>

      <xsl:when test="string-length($padVar) &lt; $length">

        <xsl:call-template name="append-pad">

          <xsl:with-param name="padChar" select="$padChar"/>

          <xsl:with-param name="padVar" select="concat($padVar,$padChar)"/>

          <xsl:with-param name="length" select="$length"/>

        </xsl:call-template>

      </xsl:when>

      <xsl:otherwise>

        <xsl:value-of select="substring($padVar,1,$length)"/>

      </xsl:otherwise>

    </xsl:choose>

  </xsl:template>

The 'padChar' param passed in could be as many characters as you want, actually. 'padVar'

is the variable to pad, and length is length,

obviously. Most of the XSLT I do is for fixed-length text files, and these haven't failed me yet.

Sunday 24 October 2021

B2B OIC Outbound Batching

                                                               

As OIC gen 2 does not have a provision of batching outbound EDI batching, below is the workaround steps to achieve it.

 

1.       Create ISA Headers and stage it in a file

 

Translate 810 invoice with b2b translator!

 

    

 

normalize-space(substring-before($readheader/nsmpr15:ReadResponse/nsmpr1:tes/nsmpr1:test/nsmpr1:C1,"ST*810"))

 

The above string will give you the ISA segment before ST segment.

 

2.               Next ST-segment loop

 




 

Loop the multiple invoices to get the ST repeating segments, I have used the Translate EDI activity.



 

For writing the ST segment  file I used the below schema and appended to the same ISA file , so that we will have ISA and then ST repeating segments.

 

<?xml version="1.0" encoding="UTF-8" ?>

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"

            xmlns:nxsd="http://xmlns.oracle.com/pcbpel/nxsd"

            xmlns:tns="http://TargetNamespace.com/fileReference/writedi"

            targetNamespace="http://TargetNamespace.com/fileReference/writedi"

            elementFormDefault="qualified"

            attributeFormDefault="unqualified"

            nxsd:version="NXSD"

            nxsd:stream="chars"

            nxsd:encoding="UTF8"

> 

 

 

  <xsd:element name="tes">

    <xsd:complexType>

      <xsd:sequence>         

        <xsd:element ref="tns:test" minOccurs="1" maxOccurs="unbounded" />

      </xsd:sequence>

    </xsd:complexType>

  </xsd:element>

  <xsd:element name="test" type="tns:testType" />

  <xsd:complexType name="testType">

    <xsd:sequence>

      <xsd:element name="C1" type="xsd:string"  nxsd:style="terminated" nxsd:terminatedBy="${eof}" nxsd:quotedBy="&quot;" />

    </xsd:sequence>

  </xsd:complexType>

</xsd:schema>

 

3.       Footer Segment (GE and IE)






 

<?xml version="1.0" encoding="UTF-8" ?>

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"

            xmlns:nxsd="http://xmlns.oracle.com/pcbpel/nxsd"

            xmlns:tns="http://TargetNamespace.com/fileReference/writedi"

            targetNamespace="http://TargetNamespace.com/fileReference/writedi"

            elementFormDefault="qualified"

            attributeFormDefault="unqualified"

            nxsd:version="NXSD"

            nxsd:stream="chars"

            nxsd:encoding="UTF8"

> 

 

 

  <xsd:element name="Edi810">

    <xsd:complexType>

      <xsd:sequence>

        <xsd:element ref="tns:Edi_810" minOccurs="1" maxOccurs="unbounded" />

      </xsd:sequence>

    </xsd:complexType>

  </xsd:element>

  <xsd:element name="Edi_810" type="tns:Edi810Type" />

  <xsd:complexType name="Edi810Type">

    <xsd:sequence>

      <xsd:element name="Record" type="xsd:string"  nxsd:style="terminated" nxsd:terminatedBy="${eol}"  />

    </xsd:sequence>

  </xsd:complexType>

</xsd:schema>

 

Run the Integration and you will see the EDI outbound batching into single edi file .


Happy Learning 

 

====================================================================================

 

Thursday 18 October 2018

SOA Transaction Boundaries – Part 2

Let us continue with adding some more functionality to our base process. Base process has following activities
  • Consume message from JMS queue using XA
  • BPEL component inserts the data into “sourcetbl” table using XA datasource.
  • BPEL component has oneWayDelivery set to “sync” and “transaction” set to required.
  • No catch all branch
  • Throws rollback at the end of bpel flow.
Base process runs everything in a single transaction and the rollback fault rolls back data inserted into table and puts message back in JMS queue.

Hypothetical Requirement

Let us a consider  a hypothetical requirement.
  • After picking up message from JMS queue, BPEL should insert into “sourcetbl” and “targettbl”.
  • Failure during  insertion into tables, should rollback message in JMS queue
  • Record gets inserted into both table or none of the tables. In other words, if insert to “targettbl” fails, “sourcetbl” insert should rollback.
  • If successfully inserted into source and target table, update source table flag with “Y”. if this fails, JMS message ALONE should rollback. Records inserted into source/target table should not rollback.
  • Refer the image below for the required transaction boundaries.
    • Invoke1 and Invoke 2 should be part of separate transaction. They should rollback /commit together.
    • If Invoke3 fails, it shouldn’t affect invoke1/2. It should rollback only Txn 1.

Base process Modification

  • Add another DB adapter to insert into second table. Use XA datasource.
  • Add one more DB adapter to update sourcetable flag with Y. Use XA datasource.
  • Add invoke  activities after the first invoke in the bpel flow. Ensure the variables are initialized in existing or new assign activity.
  • Remove “Throw” activity.
  • Add a catchAll branch. Throw “Remote Fault”.
    • If binding fault is thrown from DbAdapter and a rollback happens, subsequent redelivery of message is rejected by JMS Adapter with error “Resource adapter invoked onReject() without an associated exception.”
    • Refer this  Resource Adapter invoked onReject Error post.
Do we have the required transaction boundaries with above modifications? Let us find out.

Test Scenario 1

Let us deploy and run the process. The process would complete successfully. It would pick message from JMS; insert record into source table; insert record into target table; update source table flag to ‘Y’.

Test Scenario 2

Let us now try to introduce error while inserting into “targettbl”. Provide invalid JNDI for this.
We can see there are no records in Source/Target table. JMS Message is also rolled back. Modify the process to have valid JNDI so that update goes through fine during next test case.

Test Scenario 3

Now, Let us try to introduce error while updating “Flag” to Y in source table. Modify the process, to have invalid JNDI for third Invoke and deploy the process.
Put a message with a new seq number. Seq number 1 is already in DB. Try with 2.
We can see from audit trail that source & target table insert is completed. However, record with seq number 2 doesn’t exist in those table.  Because of error in third invoke , everything has rolled back. Our hypothetical requirement is
If successfully inserted into source and target table, update source table flag with "Y". if this fails, JMS message ALONE should rollback. Records inserted into source/target table should not rollback.
However, in our case, source and target table have also rolled back. The reason is required transaction boundary is not achieved in the bpel structure we have.
We want Invoke1 and Invoke2 to be in a separate transaction. How do we do that?

Defining Transaction Boundary

Unfortunately there is no direct mechanism at Partner Link level to say these partner links should be in different transaction.  If there is only one resource, we can use non-xa, which will not participate in global transaction. However, we have two resources.
As transaction related properties are available only for BPEL component and not for adapters, we need to embed these adapter calls in a bpel component.
Let us modify our bpel process to look like below image.
Add a new BPEL Component to composite.xml. Let us specify “oneWayDeliveryPolicy” as “sync” and “Transaction” as “required”.
New BPEL Component with oneWayDeliveryPolicy as sync & transaction as required
Modify composite.xml to look like below image.
Modified Composite
Call second BPEL component from first. Remove reference of Source/target table inserts from first BPEL component.
Modified First BPEL
Add Invoke activities for source/target table inserts.
Second BPEL Component Details

Testing Modified Process

Verify all JNDIs are correct and deploy the process. Add a message in queue with seq 2. Process should go through fine without any error. Table will contain two records. We will repeat the same test scenarios as before.

Test Scenario 1

Provide Invalid JNDI for “targettbl” insert. Deploy and run the process. Specify seq number as 3.
We would see everything rolled back as required. No records in tables. Message put back in JMS queue.
Put back valid JNDI in “targettbl” insert.

Test Scenario 2

Provide invalid JNDI for updating flag to “Y”.  Deploy and run the process. Specify seq number as 3.
The result is same as above. Everything rolled back. Message put back in queue. Even though we have embeded in another bpel component everything was executed in single transaction. It is because of the setting we had put initially.
oneWayDeliveryPolicy – sync.  This setting makes first BPEL and Second BPEL to execute in same thread.
transaction – required.  This setting makes the second BPEL to join first BPEL’s transaction instead of creating a new transaction. So, instead of creating two transactions, everything was done in single transaction as earlier.

Test Scenario 3

To make second BPEL component to create new transaction, modify  “transaction” property to “requiresNew”. Deploy and run the process. Specify seq number as 4.
This time, the transaction boundaries would have been created the way we wanted it and our hypothetical requirement is satisfied. Records will be committed in Source and Target table. However, update would have failed and it will roll back only the JMS message.

When working with Adapters, SOA doesn’t provide interface to specify transaction parameters at adapter level. We need to  embed those into BPEL components and specify transaction parameters for BPEL component. By specifying values for oneWayDeliveryPolicy and transaction property we can adjust transaction boundaries and achieve desired results.
In the next post, we will see how throwing and handling faults affects transactions.

SOA Transaction Boundaries

We will try to understand the behavior of SOA transaction  boundaries by creating simple BPEL process and gradually adding functionality to it.
At the very basic, every BPEL process executes in the context of a transaction. It either creates a new transaction or joins an existing transaction.
Let us a create BPEL process which consumes message from a JMS Queue.

Environment

Oracle SOA 11.1.1.7.8  on Windows 7 64 bit OS.

DB Table

CREATE TABLE SOURCETBL(SEQ NUMBER NOT NULL,NAME VARCHAR2(20 BYTE),FLAG VARCHAR2(20 BYTE) NOT NULL,EMAIL VARCHAR2(200 BYTE),CONSTRAINT SOURCETBL_PK PRIMARY KEY(SEQ)ENABLE);

CREATE TABLE TARGETTBL(SEQ NUMBER NOT NULL,NAME VARCHAR2(20 BYTE),FLAG VARCHAR2(20 BYTE) NOT NULL,EMAIL VARCHAR2(200 BYTE),CONSTRAINT TARGETTBL_PK PRIMARY KEY(SEQ)ENABLE)

DataSources & JNDI Names


NameDatasource JNDIDBAdapter JNDI
FirstXAjdbc/FirstXAeis/db/FirstXA
SecondXAjdbc/SecondXAeis/db/SecondXA
FirstNonXAjdbc/Firstnonxaeis/db/FirstNonXA
SecondNonXAjdbc/Secondnonxaeis/db/SecondNonXA

JMS Setup

Following JMS resources are used in the examples.
QueueNonXA CFXA CFAdapter XA JNDIAdapter Non XA JNDI
jms/MyQjms/MyQNonCFXAjms/MyQCFXAeis/jms/XAeis/jms/nonXA
Queue is configured with following “Delivery Failure” Options.
Redelivery Delay Override: 10000
RedeliveryLimit: 1
Expiration Policy: Discard

Sample Schema

<?xml version="1.0" encoding="windows-1252" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns="http://xmlns.oracle.com/ex/emailrec"
 targetNamespace="http://xmlns.oracle.com/ex/emailrec"
 elementFormDefault="qualified">
 <xsd:element name="ERecord" type="ERecordType"/>
 <xsd:complexType name="ERecordType">
 <xsd:sequence>
 <xsd:element name="seq" type="xsd:integer" />
 <xsd:element name="name" type="xsd:string" />
 <xsd:element name="email" type="xsd:string" />
 </xsd:sequence>
 </xsd:complexType>
</xsd:schema>

BPEL Process with JMS Adapter

  • Create a SOA Application.
  • Add JMS Adapter to consume messages based on above schema. Use Non-XA JNDI to start with.
  • Create a BPEL component based on wsdl created as part of above step and wire it with JMS Adapter.
  • In the BPEL process just add an “Empty” activity.
Deploy the process.  Add the following xml message to JMS Queue
<ERecord xmlns="http://xmlns.oracle.com/ex/emailrec">
 <seq>1</seq>
 <name>Krishna</name>
 <email>kri@dom.com</email>
</ERecord>
There is nothing interesting in this base process. A bpel instance would have been created and completed.

Rollback Fault

As part of the bpel flow, let us throw a Rollback fault. Let us see whether our message is rolled back to JMS queue.
Modify BPEL to have a rollback fault (after  the empty activity) and deploy the process.
Add a message to JMS Queue.
Audit trail shows that the transaction was rolled back. However, if we see our JMS queue, our message is not rolled back to the queue.
Is this because we used non-xa?.

Using XA JNDI

Modify the JMS jca file to have XA JNDI instead of non-xa JNDI and redeploy the process. The result is same as before. Transaction would have rolled back , but we don’t see messages back in our queue.
Does it mean the rollback is not doing what it is supposed to do?.
Let us add one more action, inserting into DB table , as part of the BPEL flow.
  • Add a DB Adapter to insert or merge into the table.
  • use XA JNDI
  • Add an invoke before “Throw” to call  DB Insert.
  • Add a assign/transform activity before invoke to initialize variable for DB insert.
Deploy the process and add a message to the queue. Audit trail will show that “DB Insert” was completed successfully and transaction was rolled back.
If we look at the table, there will be no record, which means “rollback” is doing what it is supposed to do. It roll backed the insert. However, the rollback didn’t restore the message back in JMS queue. So, we can conclude, DB Insert happens in a separate transaction and JMS dequeuing happens in a separate transaction.
The above results implies
  • There will be two transactions.
  • JMSAdapter transaction – which gets committed even before BPEL executes
    This is due to the setting async.persist which will put the message in dlv_message table and commit the transaction. BPEL invoker threads will pickup from dlv_message and initiate BPEL, which will run in new transaction.
  • BPEL flow – which runs in new transaction.
When rollback fault is thrown, only Transaction 2 is rolled back(no record in DB Table). However, transaction 1 will be committed. That is the reason, we don’t see the message back in the queue. So,if we use “aysnc.persist” for “oneWayDeliveryPolicy”, Bpel Engine will execute activities in two transactions as shown in above diagram.

Single Transaction

If we want one transaction instead of two, we need to set “oneWayDeliveryPolicy” to sync.With this setting . DLV_Message table is not used. JMSAdapter and BPEL will get executed in the same thread.
Change “oneWayDeliveryPolicy” to “sync”. Redeploy the process and add a message to Queue.
This time, because of rollback fault, you can find that message is rolled back to JMS queue and retried.
Actually, with this setting also, it will be still two transactions as shown in below diagram.
The reason for above behavior is BPEL always starts new transaction. If there is any existing transaction, it suspends that one. Suspended transaction will resume after the current bpel flow completes.
JMSAdapter Transaction (Txn 1) will be suspended and BPEL starts a new transaction (Txn 2) to execute BPEL activities. When Rollback fault is thrown, Txn2 is rolled back. JMSAdapter gets a remote fault and since it doesn’t handle the fault, Txn 1 also will be rolled back.  We can observe these faults in audit trail
To make BPEL to participate in existing transaction, instead of creating new one (which is default behaviour), we need to set “bpel.config.transaction” property to “required”.
If value is “required”, BPEL will participate in existing transaction , if any available. If not it will start a new transaction.
If value is “requiresNew” (default value), BPEL will create new transaction. If any existing transaction is available, that will be suspended.
Add “bpel.config.transaction” property to composite.xml with value “required” and deploy the process.
 <component name="SoaTxBPEL" version="2.0">
 <implementation.bpel src="SoaTxBPEL.bpel"/>
 <property name="bpel.config.transaction" type="xs:string" many="false">required</property>
 <property name="bpel.config.oneWayDeliveryPolicy" type="xs:string" many="false">sync</property>
 </component>
With this setting , Txn boundary will be like below and everything will get executed in single transaction.
When everything happens in a single transaction, and a rollback fault is thrown, we can not catch it inside bpel , even if we have a catch block.
Modify BPEL process to have a catch all and deploy it. In Audit trail we can see that though a “rollback” fault was thrown and catchall block exists, catchall branch doesn’t get executed.  BPEL fault handling, as with other activities, happens in the context of transaction. When the existing only transaction is rolled back, BPEL will not be able to catch or handle faults.
In all these, we haven’t seen single record getting committed in the DB. If we want to commit the DB transaction and at the same time, we need to roll back messages in queue, we need to move DB Insert out of transaction . Use Non-XA JNDI for DB Insert. This will ensure DB Insert operation doesn’t participate in distributed transaction and gets committed irrespective of rollback fault.
As part of this post we saw how Transaction boundaries are determined when JMSAdapter and BPEL components are used and how values of bpel.config.oneWayDeliveryPolicy, bpel.config.transaction influences boundary demarcation.  In next post (SOA Transaction Boundaries – Part 2), we will see how these values influence transaction boundaries when two bpel components are used.

SOA 12c : How to rollback transaction in BPEL

There are scenarios when we want to complete commit or complete rollback.
This is known as transaction handling.
To demonstrate this scenario I am taking following use case.

Use Case : Read a file and insert data into Header and Line tables. Data must be inserted into both the tables or it should be complete roll back in case of any exception.

Lets start the use case :

1. Drag a file adapter in the Exposed Services. Configure it to read a file from Local directory.


2. Configure two database adapters to insert data into header and line tables.
3. Create a BPEL process and wire it to the FTP adapter and database adapter. After wiring it your composite should look like as below :





















4. Add invoke activity and other assign activity to complete BPEL process. Deploy the service to em console.



















5. For handling transactions you must use a XA datasource. You can create a XA datasource using admin console.

6.  There are two cases for transaction handling.
First Case :

If you are not using catch all, transaction will automatically rollback in case of any exception. In the below example first we will insert data in Header_Details table after that we will try to insert a string value for a column of number type in Line_Details table. It will throw an exception and complete transaction will be rollback.






















Since the transaction was rolled back, it should not insert date Header_Details table and Line_Details table.

























Second Case :

If you are using a catch all, then transaction will not be rolled back automatically in case of any exception. Add a catch all activity in the BPEL service.

BPEL Activity :



















Run the service :























Here transaction was not rolled back, even the BPEL process has been completed.
Let see entries in database tables :































From the above screen shots we can see the transaction was not rolled back. It has inserted data into Header_Details table. But as per our requirement it should not happen. To resolve this issue, you need to use a rethrow activity at the end of your catch all block. In this way control will go back to BPEL and it will handle transaction.


















Run the service :






















The transaction was rolled back, lets see the table entries.











xslt padding with characters call template for left pad and right pad

  Could a call-template be written that took two parameters ?   a string, and a   number) return the string with empty spaces appended t...