Sunday, May 18, 2008

xsl:for-each statement with BizTalk mapper

Honestly, I'm not a big fan of the XSL mapper editor shipped with BizTalk extensions for VS2005. likewise with the xsl and C# functions visual representation called functoids. Personally, I find writing the XSL code to transform between one XML to another as easy approach and more easy tuning then fighting with the editor until it generates the appropriate code.

One common scenario is generating xsl:for-each loop in the XSL stylesheet. I stopped counting the times people asked me how to to obtain this with the mapper. The task is easy when you write the xsl code by yourself but much more complicated when you're trying to generate it with the mapper.

  • unbounded element to another unbounded element.

The basic scenario is transforming from one repeating element to another. consider the following:

Source Schema:

 

Destination Schema:

XSL Code:

BizTalk Mapper:

As you can see, to create the above XSL, all you have to do is to drug the source elements to the destination. this is because both source and destination elements are unbounded, so the mapper 'understand' and generating xsl:for-each statement.

  • Unbounded element with maxOccurs="1" child and unbounded child:

consider the following:

Source Schema:

Destination Schema:

Input XML:

<ns0:Root xmlns:ns0="http://Pinhas_Kolsky.Demos.Mapping.Looping.Schema1">

  <Record1>

    <Record>

      <Record2>

        <TargetField1>1</TargetField1>

        <TargetField1>2</TargetField1>

      </Record2>

      <Record2>

        <TargetField1>3</TargetField1>

        <TargetField1>4</TargetField1>

      </Record2>

    </Record>

  </Record1>

  <Record1>

    <Record>

      <Record2>

        <TargetField1>5</TargetField1>

        <TargetField1>6</TargetField1>

      </Record2>

    </Record>

  </Record1>

</ns0:Root>

in this case, you cannot drug the elements like in the basic scenario:

BizTalk Mapper:

 

BizTalk mapper can 'guess' how to build the for-each statement only in the basic scenario, in the case above, the mapper will generate the first child of the unbounded destination element more then once:

XSL Code:

Output XML (Not valid):

<ns0:Root xmlns:ns0="http://Pinhas_Kolsky.Demos.Mapping.Looping.Schema2">

  <LoopRecord1>

    <Record>

      <LoopRecord2>

        <DestField1>1</DestField1>

        <DestField2>2</DestField2>

      </LoopRecord2>

      <LoopRecord2>

        <DestField1>3</DestField1>

        <DestField2>4</DestField2>

      </LoopRecord2>

    </Record>

    <Record>

      <LoopRecord2>

        <DestField1>5</DestField1>

        <DestField2>6</DestField2>

      </LoopRecord2>

    </Record>

  </LoopRecord1>

</ns0:Root>

As you can see, the element 'Record' was created twice.

In this case you must use the looping functiod:

BizTalk Mapper:

XSL Code:

Output XML (valid):

<ns0:Root xmlns:ns0="http://Pinhas_Kolsky.Demos.Mapping.Looping.Schema2">

  <LoopRecord1>

    <Record>

      <LoopRecord2>

        <DestField1>1</DestField1>

        <DestField2>2</DestField2>

      </LoopRecord2>

      <LoopRecord2>

        <DestField1>3</DestField1>

        <DestField2>4</DestField2>

      </LoopRecord2>

    </Record>

  </LoopRecord1>

  <LoopRecord1>

    <Record>

      <LoopRecord2>

        <DestField1>5</DestField1>

        <DestField2>6</DestField2>

      </LoopRecord2>

    </Record>

  </LoopRecord1>

</ns0:Root>

It's impotent to notice that when the mapper is not automatically creates the XSL by drugging the elements, you can't use both - looping functiod for the parent and drugging unbounded to unbounded. this will generate only the first xsl:for-each. you can see this in the following:

BizTalk Mapper:

  

XSL Code:

Output XML (Not valid):

<ns0:Root xmlns:ns0="http://Pinhas_Kolsky.Demos.Mapping.Looping.Schema2">

  <LoopRecord1>

    <Record>

      <LoopRecord2>

        <DestField1>1</DestField1>

        <DestField2>2</DestField2>

      </LoopRecord2>

    </Record>

  </LoopRecord1>

  <LoopRecord1>

    <Record>

      <LoopRecord2>

        <DestField1>5</DestField1>

        <DestField2>6</DestField2>

      </LoopRecord2>

    </Record>

  </LoopRecord1>

</ns0:Root>

Conclusions: generating xsl:for-each statement with BizTalk mapper:

  • In a simple scenario you can generate xsl:for-each by drugging the source unbounded element to the destination unbounded element.
  • When you need to add more logic to the code (like creating maxOccurs="1" element inside the looping) you must use looping functoid.
  • In a case when a looping functoid is necessary, you must use one looping functoid for each unbounded element.  

 
Copyright © 2007 | Diseñado por Blog and Web