R0001 Ebook BizTalk Mapping Patterns and Best Practices 20140923 v1
R0001 Ebook BizTalk Mapping Patterns and Best Practices 20140923 v1
Content
About the Author ............................................................................................................................................... 9
Acknowledgement ........................................................................................................................................... 10
About the Reviewers........................................................................................................................................ 11
About DevScope and BizTalk360 .................................................................................................................... 13
Introduction ..................................................................................................................................................... 15
Who this book is for .................................................................................................................................................... 16
What this book covers ................................................................................................................................................ 16
Prerequisites ............................................................................................................................................................... 17
Conventions ................................................................................................................................................................ 17
Downloading the example code ................................................................................................................................. 18
Contacting the Author ................................................................................................................................................ 18
BizTalk Mapping Master Class .................................................................................................................................... 18
Basic principles of Maps................................................................................................................................... 19
What are maps? .......................................................................................................................................................... 20
Where can maps be used? .......................................................................................................................................... 21
Introduction to the BizTalk Mapper ............................................................................................................................ 23
Links and Functoids ................................................................................................................................................. 26
Mapper Grid ............................................................................................................................................................ 28
Possible operations on pages.............................................................................................................................. 29
Transformations - Basic maps functionalities (Document mapping) ...................................................................... 30
Simple mapping of a given value (direct copy) ................................................................................................... 30
Concatenation of values ..................................................................................................................................... 31
Conditional selection .......................................................................................................................................... 31
Custom scripts ..................................................................................................................................................... 32
Add new values (data) ........................................................................................................................................ 34
Resources ............................................................................................................................................................ 35
Operations available in maps at design time .......................................................................................................... 35
Test Map ............................................................................................................................................................. 36
Validate Map ....................................................................................................................................................... 36
Debug Map .......................................................................................................................................................... 37
How Maps Works ............................................................................................................................................. 39
1
BizTalk Mapping Patterns and Best Practices
2
BizTalk Mapping Patterns and Best Practices
3
BizTalk Mapping Patterns and Best Practices
4
BizTalk Mapping Patterns and Best Practices
How to use the Muenchian Method in your BizTalk Transformations ............................................................. 194
Using an external custom XLS file ................................................................................................................. 195
Muenchian Method inside the Mapper without losing BizTalk Mapper functionalities .............................. 196
First approach ........................................................................................................................................... 196
Second Approach ...................................................................................................................................... 197
Final Approach .......................................................................................................................................... 199
How to implement multi-level Muenchian grouping ................................................................................... 200
Conclusion ..................................................................................................................................................... 201
Resources .............................................................................................................................................................. 202
Sorting Pattern .......................................................................................................................................................... 202
Sorting different structures................................................................................................................................... 203
First approach: Using Functoids and Links ........................................................................................................ 203
Second approach: Using Scripting Functoid with Inline Custom XSLT code ..................................................... 206
Sorting Numbers ........................................................................................................................................... 207
Sorting by multiple fields ...................................................................................................................................... 208
Sort operations within grouping operations using preceding-sibling axis and Muenchian Method. .................. 210
Key notes ............................................................................................................................................................... 210
Resources .............................................................................................................................................................. 211
Conditional Pattern ................................................................................................................................................... 211
Check Existence ..................................................................................................................................................... 212
Difference between an Optional, Nillable and an Empty element ................................................................... 213
How to validate if the Element exist or/and the Data exist? ............................................................................ 213
Check Existence: Optional to Optional Elements.......................................................................................... 213
Data Existence Validation: Optional and Mandatory Elements to Optional Elements ................................ 217
Check Existence: Optional to Mandatory Elements...................................................................................... 221
Check Existence: Inside repeating records ................................................................................................... 227
Check Existence: Inside optional records...................................................................................................... 228
If…Then Condition ................................................................................................................................................. 230
Map a simple record to a record or element base on a condition ................................................................... 231
Map recursive records base on a condition ...................................................................................................... 232
Map recursive records base on a condition to a list ......................................................................................... 235
If…Then…Else Condition........................................................................................................................................ 238
Basic If… Then… Else Condition ......................................................................................................................... 239
First Solution: Using only Functoids .............................................................................................................. 239
5
BizTalk Mapping Patterns and Best Practices
6
BizTalk Mapping Patterns and Best Practices
7
BizTalk Mapping Patterns and Best Practices
8
BizTalk Mapping Patterns and Best Practices
Currently working as a BizTalk consultant at DevScope (www.devscope.net). In the last few years
has been working on integration scenarios and Cloud Provisioning implementations at a major
telecommunications service provider in Portugal. His main focus is on Integration Technologies
where is been using .NET, BizTalk Server, SOAP/XML/XSLT since 2002 and recently Microsoft
Azure.
Sandro is very active in the BizTalk community as blogger (http://sandroaspbiztalkblog.wordpress.com/), member and
moderator on the MSDN BizTalk Server Forums, TechNet Wiki author, Code Gallery and CodePlex contributor, member
of BizTalk Brazil community (http://www.biztalkbrasil.com.br/), NetPonto community (http://netponto.org/),
BiztalkAdminsBlogging community (http://www.biztalkadminsblogging.com), editor of the magazine “Programar”
(http://www.revista-programar.info/?action=editions), public speaker and technical reviewer of "BizTalk 2010
Cookbook", Packt Publishing book.
Sandro is also a member and co-founder of BizTalkCrew along with Nino Crudele, Saravana Kumar, Steef-Jan Wiggers
and Tord Glad Nordahl which are responsible for organizing BizTalk Innovation Day event all across Europe:
https://www.facebook.com/BizTalkInnovationDay
He has been awarded the Microsoft Most Valuable Professional (MVP) since January 2011 for his contributions to the
world-wide BizTalk Server community (https://mvp.microsoft.com/en-us/mvp/Sandro%20Pereira-4030655) and
currently holds MCTS: BizTalk Server BizTalk Server 2006 and BizTalk Server 2010 certifications.
9
BizTalk Mapping Patterns and Best Practices
Acknowledgement
So many things happened in this project that I almost don’t know how to begin. This book topic began with a
conversation with my dear friend José António Silva (also R&D at DevScope) to choose a subject for my session in the
BizTalk Innovation Day Oporto event that took place in March 2013, and he suggested me to speak about Mapper
Patterns or transformation patterns. My initial intention was also to publish these patterns on my personal blog,
however after the event Saravana Kumar challenged me to create a white paper about this topic which later as the
content grew I decided to turn into a book.
It has been a long way, working on this book demanded a lot of effort and attention but I'm extremely happy to have
made this so unusual book. Unusual because it doesn’t follow any publisher rule, it’s a free book and despise I’m the
only author for me it feels like a community book due to the fact that so many people have contributed in one way or
another: Fernando Pires for helping me developing some pure XSLT scenarios in some patterns and discuss different
point of views; Tom Canter for providing me with one real scenario; Mandi Ohlinger, Sujay Talasila and Tord Glad
Nordahl for providing me with feedback for some of the content I wrote; Colin Meade, Pedro Sousa, Ana Russo, Rui
Quintino e João Sousa for proofreading parts of the book; all the BizTalk Innovation day attendees for all the feedback
and tips; my coworker and friend Sónia Gomes (http://ideiasaoscaracois.com) for creating the cover of the book;
Saravana Kumar and BizTalk360 for publishing the book. Thanks guys.
I would also like to thank my fantastic team of Technical Reviewers composed by three Integration MVP’s: Michael
Stephenson, Nino Crudele and Steef-Jan Wiggers and for the person responsible for the initial idea: José António Silva.
Thank you for accepting the challenger and thank you for the incredible effort and time to increase the quality of the
book.
My employer, DevScope, has given me a lot of leverage to spend time writing this book, but also to actively contribute
for the community of BizTalk with articles, blog and conferences. Thanks to all my coworkers at DevScope for all the
support, they are an amazing team and I’m very proud to work with them but I need to highlight: Rui Barbosa, who
believed in me and allowed me to walk the road that led me to where I am today; Márcia Teixeira; Miguel Silva, my
“brother in arms”, and José António Silva for their support, encouragement and for providing me always new
challenges; Rui Quintino, one of the most brilliant technicians that I know, which is always one of the first to say count
me in, it is an honor and a pleasure to work with you; and finally Vânia Braziela for your friendship and support over
these last years.
I would like to thank my family members and dear friends: Celso Renato, Vera Silva, Verinha, Celestino Dourado, Ana
Maria, Sergio Dourado, Juliana Cunha, Martim Dourado, Augusto Ramos, Cremilde Sousa, Tiago Ramos, Lígia Tavares,
Marlene Tavares, Cristóvão Soares, Eugénia, Francisco Rocha, Miguel Filipe G.C. Silva, Diogo Loureiro, Paula Costa and
Carlos Eduardo, for their moral support.
And a special thanks to my Mom and Dad, Maria Quitéria e Manuel Pereira, for their patience, for all their sacrifices
to provide me the life I have now, for buying me many years ago my first home computer a Timex computer and for
always being there when I needed.
10
BizTalk Mapping Patterns and Best Practices
Steef-Jan Wiggers is a principal consultant for a consultancy firm in the Netherlands. He has
almost 15 years’ experience as a technical lead developer, application architect and consultant,
specializing in custom applications, enterprise application integration (BizTalk), Web services and
Windows Azure. Steef-Jan is very active in the BizTalk community as a blogger, Wiki
author/editor, forums, writer and public speaker in the Netherlands and Europe. For these
efforts, Microsoft has recognized him a Microsoft MVP for the past 4 years.
In addition to consulting, Steef-Jan is also an author and technical editor for Packt Publishing. Steef-Jan has written
the BizTalk Server 2010 Cookbook available through Packt Publishing and was a technical reviewer for:
“Sandro has done an outstanding job capturing all the patterns, details and characteristics of mapping in
BizTalk Server. You should view this work as the standard bible. Valuable for anyone working with mapping in
BizTalk Server.”
Nino worked with the integration platform since 2004 and his passion is to architect and deliver significant business
integration project that provide exceptional outcomes for the client. External trading partner integration is still huge
and he have delivered world class BizTalk Server solutions using and integrating many different technologies as EDI,
RosettaNet, HL7, RFID, SWIFT.
Michael is a highly experienced freelance integration architect with lots of experience of designing
and delivering integration projects which leverage the Microsoft technology stack. He has deep,
practical knowledge of delivering complex solutions with BizTalk, Microsoft .NET, Microsoft Azure
and associated technologies. Michael has also been a technical lead on 25+ projects which have
leveraged Microsoft's cloud platform.
11
BizTalk Mapping Patterns and Best Practices
Michael is heavily involved in the community activities around Microsoft technologies through the Microsoft MVP and
Advisor/Insider programmers and also speaks at user groups on a regular basis. Michael is also an author for Pluralsight
having produced a very popular courses on .NET and RabbitMQ.
Michael is also the creator of the BizTalk Maturity Assessment and initiative to help companies to measure the
maturity of how they work with BizTalk and compare how they do BizTalk against recognized good practices. For more
info refer to http://biztalkmaturity.com.
José António Silva is a Software Architect and a mentor in a wide variety of technologies.
Particularly versed with Software as a Service (SaaS) in all aspects of the Strategy, Design,
Deployment and Operation of these multi-tenant applications. Always interested in Agile
methodologies and Data Visualization and anything that can make tedious and repetitive work
disappear from our lives.
As an early adopter of XML, he was lucky to cross very early with BizTalk Framework (1999) and BizTalk Server 2000.
And since then has been advocating for robust asynchronous message-oriented systems using interoperable and
extensible characteristics, enabling integrations that work reliably without changes for many years. He got his first
BizTalk Certification in September, 5th 2001.
José was at Microsoft for 11 years, working in Services and later as an Architect Evangelist in Developer and Platform
Group (DPG) at Microsoft Portugal. He maintained relationships with the Portuguese IT Architects and other Technical
Decision Makers. Beside engaging with early adopters and grasping many of the technology trends and disruptions in
the last two decades, this effort allowed him to speak at major Microsoft events in his region (Techdays, Product
Launches, Architect Forums, MSDN, Partner Congress, TechEd Europe) and in invited talks at Industry Events and
Universities.
Currently he leads R&D at DevScope, and has been investing in the integration of product development (Application
Lifecycle Management) and managed cloud operations (DevOps and Azure).
12
BizTalk Mapping Patterns and Best Practices
About DevScope
and BizTalk360
DevScope [www.devscope.net]
DevScope is proud to be on the cutting-edge and help Microsoft and their customers adopt the latest technologies.
DevScope is an early adopter in many products and solutions, so, often is a part of TAP (Technology Adoption
Programs) and later on the "Beta" teams, to evaluate and test Microsoft's products, before they are widely distributed
in the market. Indeed we know how best to use these technologies no matter your business or technical landscape. It
means customers reap the benefits of faster implementations, reduced risk, and significant cost savings. Collective
experience and deep knowledge of Microsoft enterprise technologies helps our customers get the most out of their
investments.
DevScope is Microsoft’s Gold Certified Partner, continuously renews the commitment to the highest level of
partnership, acting primarily as a services offering, specifically in Business Intelligence, Collaboration (SharePoint),
CRM, Office/Excel add-ons, Systems Integration (BizTalk/EAI, MIIS) and in Mobile development.
BizTalk360 [http://www.biztalk360.com]
Once your BizTalk solutions are developed and taken to production, you get into
the phase of supporting them and operating them on a day-to-day basis. At this
point your support staffs experience various challenges on an ongoing basis. The
standard tools like BizTalk Administration Console is not designed or
appropriate for support/operational activities, it's lacking lot of basic
functionality like fine grained user access, keeping audit trail of activities performed by support staff, etc. Also in some
cases the standard BizTalk Administration Console is way too powerful to hand over to inexperienced or non-BizTalk
people.
The other challenge is on the monitoring side, once your BizTalk solutions are deployed into a production environment,
it's important for you to keep an eye on their health. Ex: You need to get notified if a receive location is down, or a
host is down etc. Right now BizTalk customers need to rely on some external tools like SCOM (System Center
Operations Manager), HPOM etc. SCOM comes with a very good management pack for monitoring BizTalk server, but
the challenging part is in the complexity of setting up SCOM and ongoing management of alerts when your BizTalk
applications starts growing.
13
BizTalk Mapping Patterns and Best Practices
We identified all these challenges faced by various customers in the past 10 years, every time we visited a customer
they always built some kind of custom management solutions on top of BizTalk to address all these challenges. That's
exactly the scope of BizTalk360. It's a
"Single operational and monitoring solution for Microsoft BizTalk Server, to make your life easy once you have your
BizTalk solution in production"
Features
BizTalk360 comes with very sophisticated security mechanism, customers will be able to control things like providing
read-only access, restricting users to certain applications, etc. BizTalk360 also audits all the activities performed by the
support user, ex: if someone stops a host instance, that action is recorded.
BizTalk360 also comes with full monitoring capabilities required to keep the environment healthy, example if a send
port goes down or if you are not receiving the volume of messages you expect, it will send notifications via email, SMS,
etc.
BizTalk360 also makes it possible for you to bring your business users to support your BizTalk solutions. The UI can
completely customized and made simple, so it's easy to train your business users to perform some simple support
activities like checking the port status, suspended instances and many others, either in read-only mode or giving
selective permission to do so.
BizTalk360 comes with several dashboards, productivity tools like advanced event viewer, throttling analyzer,
backup/DR visualizer, message box viewer integration, etc. The tools are also designed to help support people to
perform their activities in a seamless way.
BizTalk360 provides advanced knowledge base management system, all your operational challenges can be
documented and the system will match the appropriate documentation at run time and make it visible.
There are over 50 features targeted towards operations and monitoring of BizTalk Server is present in BizTalk360,
making it an invaluable tool for customers using Microsoft BizTalk server.
14
BizTalk Mapping Patterns and Best Practices
Introduction
Whenever two or more people wish to talk together, some ground-rules must implicitly exist: the most basic one is
that a common language must be spoken between them.
The same implicit rules are applied when different processes or systems want to communicate and exchange data:
they have to agree to speak the same language but also understand the same grammar structure of the messages. The
only difference between them and humans is that humans have the ability to adapt in real time whereas the systems
need all the rules to be described. This mutual agreement can happen with the following approaches:
Explicit Approach: Both processes agree to interoperate by using a common language (flat-file, SOAP and so on)
and grammar structure, i.e., they both need to be aware and respect the same Syntax and Semantic representation
of the messages.
Implicit Approach: External mediators, or translators, which share different common languages and grammar
structures for both systems to achieve interoperability. In this situation, the systems operate without explicitly
knowing how to communicate with other systems, leaving the mediators to accomplish this work.
Regarding to the grammar structures and because the data can emerge from a heterogeneity of systems or
applications, the conflicts can be grouped into three sections:
Syntax Issues: How data is structured or logically organized inside messages. Does the two systems have the same
message structure?
Semantic Issues: How data is interpreted (i.e. what does it mean?). Does the two system have the same data
formats? Does the values mean the same things in different contexts or systems?
Intentional Issues: The sender system or application does not have the data required by the destination system.
Basically this can be considered a sub-conflict of the previous one (Semantic Conflict). This normally happens when
a system does not have the right information for the end system, but will provide some kind of key, so that we can
gather the required information from another source.
But because most of the times we cannot change the surrounding systems, we normally need to have some
mechanism, or a translator, to accomplish this task for us. Because BizTalk Server is a middleware platform it needs to
be able to interact with all the surrounding systems, so BizTalk developers faces these integration challenges in their
day-to-day job when they are developing new BizTalk Server solutions to connect different systems and they need to
work with different components and artifacts such as Business Rules, AppFabric, schemas, adapters, orchestrations or
maps to solve the problem. In this book we will focus only in the process of mapping and transformation of messages
with BizTalk Server Maps.
We can define BizTalk, in a very generic and simple manner, as a server for message routing, capable of handling,
validate, transform and control numerous processes, simplifying the needs of adjustments to connect each system,
i.e., is a tool and infrastructure unique, ideal to be used primarily for Enterprise Application Integration (EAI), Business
to Business (B2B) Integration. Besides the patterns “Fire & Forget”, BizTalk Server is also used for more complex
scenarios where the business logic (workflow) depends on various messages that need to be correlated with
orchestrations - Business Process Management (BPM) solutions. A message enters BizTalk in a certain format and
structure. Based on that you can run into issues or challenges to route that message to a system that cannot
understand the message unless you change it into a format and structure that it can understand. This could mean
change format, structure and language (translation).
15
BizTalk Mapping Patterns and Best Practices
Maps or transformations are one of the most common components in the integration process. Essentially they act as
translators connecting decoupled systems. However, intentional or not, BizTalk Developers normally tended to try to
solve a transformation problem as one large mapping problem, instead of dividing it in several small problems. If we
start dividing the maps into different problems and understand how to overcome these minor problems, they will be
easier to develop and test but we will start also to notice some transformation patterns inside the map. The problems
are that those patterns can be solved and addressed in several ways and often deciding which is the best way to use
it or when to apply in a certain context turns out to be the most difficult because normally there isn’t any BizTalk books
that will cover in such details BizTalk mapping. There isn’t any references for Mapper Patterns explaining different
techniques and providing with tips and best practices for each approach.
In this book, as we explore the BizTalk Mapper Designer, we will explain its main concepts, how maps are processed
internally by the BizTalk mapper engine, some of the best practices and several recipes explaining the different and
best ways to address some of our needs when we develop maps, covering slightly themes such as product architecture,
BizTalk Schemas and some of the most widely used standards in the translation of messages.
Having recipes in this book on how to deal with these transformation challenges can be of tremendous value. All of
the recipes in this book will show you how to use BizTalk Mapper and how can you greatly improve your productivity
as a developer.
I just wrote about patterns and techniques that by one way or another I implemented in my daily life, and all the
decisions, techniques or risks that I have recommended for others to assume or avoid were the decisions, techniques
or risks that I myself assumed or avoided. I'll be the first to be harmed if it is wrong. However this does not mean that
my personal experience represents a sufficient sample to draw any absolute conclusions about all patterns; only that
personal experience gives a seal of authenticity and sincerity in the decisions taken.
This book expects a basic background knowledge of BizTalk Server and Visual Studio. It is targeted towards the
intermediate and expert BizTalk developer, who has previous experience in developing BizTalk Maps so that they might
learn some new tricks or can enhance their already extensive knowledge. But because all of the samples and patterns
present in this book are very detailed and has a chapter to describe the basic principles of the maps, this can also be
used by beginners BizTalk Developers.
With this book you can gain some insight on how transformation can be carried out, what are the most common
patterns and how the maps works and you can use this book as a reference guide for their day-to-day transformations.
16
BizTalk Mapping Patterns and Best Practices
Chapter 2, How Maps Works: This chapter aims to explain, as we explore a simple map solution in the editor, how
maps are executed and processed internally by the BizTalk Mapper Engine.
Chapter 3, Best Practices: Dealing with large transformation can be a challenge, maps can become very complex and
therefore very difficult to implement, maintain and read. This chapter will provide the reader with best practices on
keeping BizTalk Server Maps organized and well documented which may lead you to improved performance in the
processes of maintaining and developing maps.
Chapter 4, BizTalk Mapper Patterns: This chapter will cover a set of transformation patterns that will address the most
common and most challenging problems encountered while developing maps and presenting solutions to solve a
limitless variety of problems within a bounded problem space. Recipes discussed in this chapter will show how to
implement some of the common mapping patterns with BizTalk Server 2013.
Chapter 5, Behind the Scenes: This chapter covers the most misunderstood and unknown properties available in
BizTalk Mapper UI, that you can access through the properties of the background of a grid page, and hidden attributes
that you can modify directly in the mapsource element present in the map file and change certain default behaviors
of BizTalk Mapper.
Prerequisites
This book focuses on mapping patterns and how can we use the translation design tool available in BizTalk Server,
Microsoft BizTalk Mapper Designer, to implement them. This topic requires basic knowledge of BizTalk Server artifacts
(Schemas, Ports, Orchestrations and so on), C#, XML and XSLT. And of course be familiar with Microsoft Visual Studio.
To run the samples provide within this book it is essential to have Visual Studio 2012 and BizTalk Server 2013 Developer
tools and SDK installed. However all this samples can be replicated or recreated using new versions (BizTalk Server
2013 R2) and even old version (BizTalk Server 2006 to 2009) of BizTalk Server.
Conventions
In this book, you will find a number of styles of text that distinguish between different kinds of information. Here are
some examples of these styles, and an explanation of their meaning.
Quotes will appear in the text enclosed in quotation marks and in Italic: “Quote from a book or from a person”
Note
Note description.
17
BizTalk Mapping Patterns and Best Practices
At the end of each chapter, or when important, a link will be provided for the source code. You can also leave some
questions/doubts directly on the Code Gallery or in the CodePlex.
DevScope
Rua Passos Manuel, 223 - 4º Andar
4000-385 Porto, Portugal
Visit DevScope online at http://www.devscope.net. All inquiries, comments, suggestions and feedback are
appreciated.
To know more information about the course please contact Sandro Pereira at [email protected] or
[email protected] or by:
18
BizTalk Mapping Patterns and Best Practices
19
BizTalk Mapping Patterns and Best Practices
This chapter provides the reader with the main concepts of BizTalk Maps and its editor. It intends to be an introductory
note for whom is taking the first steps in this technology, covering slightly themes such as describing the BizTalk
Mapper tool available in Visual Studio, show where we can use maps and demonstrate the most common
transformation functionalities present in maps.
However the aim of this book is not to fully explain the BizTalk Mapper or all of its functionalities so we will not go into
detail on all of the topics. Nevertheless we will provide links for additional resources whenever it is relevant so that
you can acquire and strengthening your knowledge in certain topics.
Although some transformation techniques, or approaches that we will address in this chapter may not be the most
effective or correct, i.e., they may be performed in a more simple, effective and accurate way. Let’s assume for now
they are because they were intentionally addressed in their most common or traditional way, these will be addressed
later on in the BIZTALK MAPPER PATTERNS chapter.
However it is important to understand that those transformations could be done without using the BizTalk Mapper
and instead we could use an external custom XSLT file. This topic will be addressed later on in this book.
The following W3C (Worldwide Web Consortium) standards are utilized in the BizTalk Mapper:
XML (Extensible Markup Language) – designed to transport and store data, it’s a markup language that defines a
set of rules for encoding documents in a format that is both human-readable and machine-readable;
XML Schema (XSD - XML Schema Definition) – describes the structure of a business document (XML document);
XSLT (Extensible Stylesheet Language Transformation) – is a style sheet language for XML documents that defines
the transformation rules of the messages;
W3C is an international consortium where Member organizations, a full-time staff, and the public work together to
develop Web standards.
Syntax Transformations: This type of transformation occurs in receive or send pipelines and aim to transform a
document into another representation, e.g. CSV to XML. Here the document maintains the same data (semantics),
but changes the syntax that is represented. I.e. we translate the document, but typically we don't modify the
20
BizTalk Mapping Patterns and Best Practices
structure. Normally, this type of transformation is bidirectional, since we still have the same semantic content, we
can apply the same transformation logic and obtain the document in its original format. This type of transformation
can be achieved in BizTalk Server within pipelines normally in the assembly and disassembly stages and maps are
not required at this stage (maps cannot be used to accomplish Syntax Transformations).
Semantic Transformations: This type of transformation usually occurs only in BizTalk maps. Here the document
maintains the same syntax that is represented (XML), but changes its semantics (data content). These types of
transformations are typically one-way, since we add and aggregate small parts of the information that compose
the document into another document, we may miss important details for its reconstruction.
In this book we will only cover semantic transformations, i.e., maps in BizTalk. If you want to know more about Syntax
Transformations please check the following resources:
21
BizTalk Mapping Patterns and Best Practices
However, by default, can be used for transforming messages in a receive port, inside orchestrations or in a send port,
as the following figure represents:
The biggest difference between using maps in ports and in orchestrations is that, when we use maps inside
orchestrations we can have multiple input messages (transformations of many documents into one final document –
transformations N1) and ports only allows a single input message (transformations 11).
We mentioned earlier that BizTalk maps are graphical representations of XSLT but when we compile our map project,
as well other BizTalk artifacts, inside Visual Studio they are compiled into a BizTalk assembly which supports better
runtime performance, side-by-side deployment (versioning) and that we can reuse in multiple ports or/and
orchestrations. Some BizTalk artifacts, such as maps, are chosen by fully-qualified strong name, or FQSN, which means
the bindings are mindful of the version used. Making a code change to the map, upping the version number (though
only major and minor build numbers should be changed), compiling, and deploying the additional assembly to the
group (and all machines) would allow users to simply select the new map for inbound or outbound mapping.
22
BizTalk Mapping Patterns and Best Practices
However, calling maps from orchestration may require code changes to the orchestration itself if the map reference
is hard-coded.
If you want to know more about BizTalk Server Application Deployment please check the following resources:
These relationships between elements are internally implemented as XSL Transformations (XSLT - Extensible Stylesheet
Language Transformation) which is the standard recommended by Worldwide Web Consortium (W3C) to perform
transformations between XML schemas.
The BizTalk Mapper resides in the Visual Studio Shell and some of its functionality relies on the user interface elements
of the Visual Studio shell. For example, you use the File, Edit, and View menus just as you would for other development
in Visual Studio. It becomes active when you add a new map (a .btm file) to a BizTalk project, when you open an
existing map, or when you reactivate a map by clicking its tab in the main Visual Studio editing window.
Source Schema view: this is the data structure of the source message and is on the left side of the main window;
Destination Schema view: this is the data structure of the target message and is on the right side of the main
window; the links that define the mapping lead into the destination schema tree view from the grid view, and
ultimately from the source schema tree view.
Mapper Grid view: is in the middle of the main window, between the two data structures (source and target); This
area plays a critical role in the definition of maps, containing the links and Functoids that control how data in a
23
BizTalk Mapping Patterns and Best Practices
source instance message is transformed into an instance message that conforms to the destination schema. The
grid view can have multiple layers, called grid pages, allowing you to organize complex maps into logical
subdivisions of mappings that are accessible through the tabs that are at the bottom of the mapper grid view.
Apart from these three modules, there are three other important windows for the developer:
Toolbox window: typically this is on left side of the source schema; providing access to all Functoids that we can
use in BizTalk maps.
24
BizTalk Mapping Patterns and Best Practices
Properties window: in this window we can view and modify the properties of a selected object on the mapper grid
or in the schemas (link or functoid in a grid page; a schema node in the source or destination schema); it is usually
available on the right of the destination schema.
Task List and Output windows: most of the time hidden, we can and should use these windows to examine the
results of validating, compiling, and testing our BizTalk maps in much the same way that these views are used when
compiling source code and building other types of projects. These windows normally appear underneath of the
Mapper Grid view.
In general, this tool allows us to map elements from one or more source schemas to elements in one or more
destination schemas, using predefined functions (Functoids) to transform values, custom XSLT transformations,
custom .NET/C#, COM, VBScript code or using external XSLT. The use of these custom options rely heavily on the
experience of the programmer.
In fact, the editor is generating an XSLT file that can be used by other .NET (non-BizTalk) applications.
The map editor is fairly common and similar in all versions of BizTalk Server however it has been improving over time
from version to version. The last most significant change in the editor (not in the BizTalk Map Engine) happened in the
25
BizTalk Mapping Patterns and Best Practices
BizTalk Server 2010 version where it was improved with several usability enhancements to help users handle complex
maps.
Links specify the basic function of copying data from an element or attribute in an input instance message to an
element or attribute in an output instance. You create links between records and fields in the source and destination
schemas at design time. This drives the creation, at run time, of an output instance message conforming to the
destination schema from an input instance message conforming to the source schema. However Links have several
properties that appear in the Visual Studio Properties window, such as the following:
Label property provides a short description of the link and is especially helpful in table-driven looping. For
information about the Label property, see How to Manage Existing Links.
Source Links property determines whether the link represents the text value of an element or the name of the
element.
Target Links property enables you to control the order in which links are processed in the map.
If you want to know more about Links please check the following resource:
The user can also specify more complex transformations using Functoids. We can consider Functoids, as pre-defined
functions that we can use to perform complex mappings and transformations
Typically on maps, the data is copied from source to destination by dragging links between elements of the two
schemas. Functoids sits in the middle of these operations and apply an operation on the incoming data in order to
transform them to the format of the destination. The BizTalk Mapper represents a Functoid as a box on the link
between source and destination elements.
26
BizTalk Mapping Patterns and Best Practices
BizTalk Mapper provides an extensive set of Functoids that can be used in maps to perform a variety of operations on
data that is being mapped from a source instance message to a destination instance message.
By default, the Functoids are organized into nine categories based on their intended purpose:
Advanced Functoids: used to create various types of data manipulation, such as implementing custom script (C#,
Visual Basic .NET, XSLT), value mapping, and managing and extracting data from looping records.
Conversion Functoids: used to convert data, such as: convert ASCII to characters or to convert numbers from one
base to another (hex, decimal).
Cumulative Functoids: used to perform various types of accumulation operations for values that occur multiple
times within an instance message.
Database Functoids: used to look up data from a database and to perform simple cross-referencing operations
(sometimes called ID mapping).
Date and Time Functoids: this is a set of operations applicable on dates like, add date, time, date and time, or add
days to a specified date, in output data.
Logical Functoids: used to conditionally control the behavior of other Functoids and to determine whether
particular output data is created.
Mathematical Functoids: used to perform specific numeric calculations such as addition, multiplication, and
division.
Scientific Functoids: used to perform specific scientific calculations such as logarithmic, exponential, and
trigonometric functions.
String Functoids: used to manipulate data strings (text alphanumeric) by using well-known string functions such as
concatenation, length, find, and trim.
27
BizTalk Mapping Patterns and Best Practices
However, the platform allows the creation of new custom functoids by the developer as well as the organization and
creation of new categories. We will discuss a little more this topic later on in the BEST PRACTICES chapter.
If you want to know more about Functoids please check the following resources:
And I personally recommend you to check the great Pluralsight course created by Dan Toomey: Using Functoids in the
BizTalk 2013 Mapper (http://pluralsight.com/training/Courses/TableOfContents/using-Functoids-biztalk-2013-
mapper). This course presents a deep-dive exploration of the BizTalk Mapper toolbox, especially the powerful built-in
Functoids that enable complex message transformations via a drag 'n' drop into the design grid.
Mapper Grid
The mapper grid plays a critical role in the definition of maps, containing the links and Functoids that control how data
in a source instance message is transformed into an instance message that conforms to the destination schema.
The grid view can have multiple layers, called grid pages, allowing you to organize complex maps into logical
subdivisions of mappings. In previous versions of BizTalk Server we could only create a maximum of 20 grid pages,
however since BizTalk Server 2010 this limitation no longer exists.
Partitioning maps on different pages, in addition to being a good practice, can become extremely useful in order to
organize them and thus make them more readable. Although in small maps, one page is enough, when dealing with
complex schemes such as EDI, "infecting" a page with numerous links and Functoids makes them unreadable and
difficult to understand, to the point of not being able to distinguish one element from another.
28
BizTalk Mapping Patterns and Best Practices
We can define the pages as logical containers of links and Functoids, serving only to organize the maps in different
strategy and for several different reasons, this is because at run time they don't have any impact since they are invisible
to the compiler. We will address this topic in more detail later on in the BEST PRACTICES chapter in the DEALING WITH LARGE
TRANSFORMATION can be a challenge, maps can become very complex and therefore very difficult to implement,
maintain and read. This chapter will provide the reader with some of the best practices that we can apply when
developing BizTalk Server Maps to keep them organized and well documented which may lead you to improved
performance in the processes of maintaining and developing maps.
There are 4 operations that can be applied to pages, despite the most frequently used being the creating and renaming
of pages:
Add new page: This is the most common operation, adds a new grid page, also known as a layer, to the grid view
allowing us to organize different areas of the map in logical containers
o Right-click the tab at the bottom of the grid page and select “Add Page” option to add a new grid page to
the map.
Rename an existing page: very often forgotten, this option allows renaming of the displayed grid page, in order to
make them more legible and give them visual impact.
o Right-click the tab at the bottom of the grid page and select “Rename Page” option.
29
BizTalk Mapping Patterns and Best Practices
o Or you can simple use drag and drop to reorganized them with the mouse if you have few tabs.
If you want to know more about BizTalk Mapper Grid please check the following resources:
Here we will take a simple transformation problem that will address each one of these functionalities or operations
providing a simple example on how to accomplish this inside the BizTalk Mapper Editor. Of course there are plenty of
other operations or transformation rules that we could do that will not be addressed here.
For this we need only to drag-and-drop the element in the source schema to the element in the destination schema.
This operation is highlighted in the next image with the mapping of the element "Address"
30
BizTalk Mapping Patterns and Best Practices
Concatenation of values
Concatenating two or more values from the source to a particular element in the destination schema is another of the
regular operations in mapping, for this we need to:
Open the Toolbox window and drag the String Concatenate Functoid onto the grid;
Drag-and-drop a link of the desired elements from the source to the String Concatenate Functoid, for example the
elements: “FirstName” and “LastName”;
Drag-and-drop a link from the String Concatenate Functoid to the element “FullName” in the destination schema;
Note
The order of the input to the Functoid is very important since the concatenation is carried out by the order in which
the elements were associated with the Functoid (we will explore this topic further on).
Conditional selection
Often we don't just want to move values from source to destination schema. Sometimes we need to generate data
output according to certain conditions. We can define these conditions in many different ways using Functoids or
through custom scripts. Here's an example: test whether the value in the source is a valid string, if so map it to the
destination schema, for this we need to:
Open the Toolbox window and drag the Logical String Functoid onto the grid. This Functoid validates whether the
input parameter is a valid string, similar to the C# function String.IsNullOrEmpty.
o Returns “False” if the string is empty or null
o Returns “True” if the value specified by the input parameter is a valid string
Drag-and-drop a link of the desired element from the source to the Logical String Functoid, in this case the element
“ZipCode”
31
BizTalk Mapping Patterns and Best Practices
Drag the Value Mapping Functoid from the Toolbox window onto the grid. This Functoid returns the value of its
second parameter if its first parameter is true, i.e., enables you, based on a Boolean value, to control whether an
entire structure or another single value in an input instance message gets copied to an output instance message.
The Functoid receives two parameters:
o The first is a Boolean (True/False)
o The second is the value to be mapped
o If the value of the first parameter is true, then the value of the second parameter is mapped to the
destination schema; otherwise it will not be mapped.
Drag a link from the Logical String Functoid to the Value Mapping Functoid
Drag a link from the element “ZipCode” from the source schema to the Value Mapping Functoid
Drag a link from the Value Mapping Functoid to the element “ZipCode” in the destination schema
Custom scripts
Custom scripts are commonly used in more complex transformations or to facilitate some mapping conditions.
Basically there are two main scenarios where we can or should use this Functoid:
When none of the existing Functoids, or chain of Functoids, perform the function we require, for example convert
a date of birth to age.
Or when the use of existing functoids becomes extremely complex to solve a mapping problem.
There is a "rule" that normally common BizTalk books described to determine whether we should use Functoids or
custom scripts which tells us: “If you need more than 6 Functoids to solve a mapping problem, you should consider
using a script. If you need six or less Functoids, you should not use a script”.
This is not a hard and fast rule and should be used at your discretion in a thoughtful way and not to the letter, i.e., if
the existing Functoids help you to easily solve the problem, use the existing functoids. If it becomes extremely complex,
then choose to use custom scripts. However there are several other reason to use custom script other than the number
of functoids used like reusability or performance. We will address this topic in more detail later on in the BEST PRACTICES
chapter in the BUILT-IN FUNCTOIDS, SCRIPTING FUNCTOID AND CUSTOM FUNCTOIDS section.
Note
In case of the functoid chain will be slightly complex you may think moving these transformation rule into an
isolated grid page.
The Scripting Functoid enables you to use custom script or code at run time to perform functions otherwise not
available. For example, you can call a .NET assembly at run time by using the Scripting Functoid and writing your own
32
BizTalk Mapping Patterns and Best Practices
custom functions. BizTalk Server supports the following languages for the Scripting Functoid: C# .NET; JScript .NET;
Visual Basic .NET; Extensible Stylesheet Language Transformations (XSLT) and XSLT Call Templates
External Assembly: It allows us to associate the functoid with an existing function in an assembly deployed to the
Global Assembly Cache (GAC).
Inline C#: This option allows us to associate and invoke C# code directly in the Functoid.
Inline JScript .NET: Same as above but using code JScript .NET
Inline Visual Basic .NET: Same as above but using code Visual Basic .NET
Inline XSLT: This option allows us to associate the Scripting Functoid with XSLT.
Inline XSLT Call Template: identical to the above, however it allows us to associate and call XSLT templates directly
in the Functoid.
In this example, we want to convert a date of birth to age, for this we need to:
Open the Toolbox window and drag the Scripting Functoid onto the grid,
Drag a link from the element “DateOfBirth” from the source schema to the Scripting Functoid;
Drag a link from the Scripting Functoid to the element “Age” in the destination schema;
To complete the mapping, we need to configure the custom script. In this example we will use the "Inline C #" script
type, for this we need to:
Double-click in the Scripting Functoid and select the “Script Functoid Configuration” tab
Go to the “Select script type” drop-down box, and select the “Inline C#” option. The “inline script” box will display
a sample script
Inside the “Inline script” property box place the following script:
33
BizTalk Mapping Patterns and Best Practices
A more basic example is to add a timestamp to the final message specifying the date and time it was processed. For
this we need to:
Open the Toolbox window and drag the Date and Time Functoid onto the grid;
Drag a link from the Date and Time Functoid to the element “ProcessingDatetime” in the destination schema;
Note
As you can see, this Functoid doesn't require any input data, returning the current date and time of the system.
34
BizTalk Mapping Patterns and Best Practices
Resources
All source code is available in the Microsoft Code gallery here: BizTalk Server – Basics principles of Maps
(http://code.msdn.microsoft.com/Funcionalidades-bsicas-dos-280cebea)
These features are available to developers in an easy manner and within the development tool, Visual Studio, without
the need to build and deploy the maps or even create and configure ports.
35
BizTalk Mapping Patterns and Best Practices
Test Map
Testing should be a continuous process as you build your map, not only at the end of development, but when
necessary or when a significant or important mapping block is complete. For this we need to:
By default an instance of the input schema is generated automatically with dummy values, according to their type,
and tested in the selected map. At the end, the generated result or the errors that occurred are displayed in the output
window.
We will address this topic in more detail later on in the BEST PRACTICES chapter in the TESTING SHOULD BE A CONTINUOUS
AND INCREMENTAL PROCESS section. You can also found more information about Testing Maps in the following resource:
Validate Map
Sometimes we use many custom script (C# and XSLT) inside our maps and sometimes we make use of external XSLT
files to perform the transformation, in these particulars cases Validate Map is an important operation that will allows
us to validate the structure and syntax of the map. It will also provide us with another way to inspect and analyze the
XSLT code generated by the compiler, providing us with more information on how the maps work and also with an
option to debug maps inside the XSLT code.
36
BizTalk Mapping Patterns and Best Practices
You can also extract the XSLT generated by the BizTalk Mapper for possible hand-crafting or for use in another project.
Right-click the BizTalk Mapper file in the Solution Explorer and select Validate Map option
Verify that there is a message in the Output window indicating that the operation succeeded. Also in the Output
window, note the name and path of the output XSLT. This XSL file will be given the same name as the map file, but
with an XSL extension. You can press CTRL and click the link to display the XSL file in the BizTalk Editor.
Debug Map
This option allows us to debug a map, thereby facilitating the identification and correction of complex mapping
problems at design time. Debugging a map is very straightforward, and can be useful in many situations.
When debugging the map, the Debug Map feature uses the map file properties, such as “TestMap Input Instance” and
“TestMap Output Instance”. Therefore, before you debug the map, it is recommended that you configure the input
and output instance properties on the map file.
In Solution Explorer, right-click the map you want to test, and then click “Debug Map”. Visual Studio displays the
map in XSLT format in its editor.
Press F10 or F11 to debug the XSL code.
o When you press F11 on a Functoid call, Visual Studio steps into the C# code for the Functoid. You can view
the values of variables used in the Functoid source code in the Locals debugger window.
Standard debug shortcuts apply, including: F9 to toggle a breakpoint and F5 to continue
37
BizTalk Mapping Patterns and Best Practices
38
BizTalk Mapping Patterns and Best Practices
39
BizTalk Mapping Patterns and Best Practices
This chapter aims to explain, as we explore a simple map solution in the editor with the basic functionalities of maps
explained earlier in the BASIC PRINCIPLES OF MAPS chapter in TRANSFORMATIONS - BASIC MAPS FUNCTIONALITIES (DOCUMENT
MAPPING) section, how maps works and how maps are executed and processed internally by the BizTalk Mapper Engine.
This article intends to be an introductory note for whom is taking the first steps in this technology.
Again, although some transformation techniques, or approaches that we will address in this chapter may not be the
most effective or correct, i.e., they may be performed in a more simple, effective and accurate way. Let’s assume for
now they are because they were intentionally addressed in their most common or traditional way, these will be
addressed later on in the BIZTALK MAPPER PATTERNS chapter.
BizTalk also uses this technique in the conversions of Flat Files to XML format (Syntax Transformations explained
earlier), however the transformations inside maps use a different approach, as we will see later in this article.
One of the important factors when using integration tools is also having in mind the existing technology standards,
and that's what the creators of the product made. BizTalk works internally, almost exclusively, with XML documents,
so it made sense to use a standard technology to carry out this type of transformations. For that W3C defined the XSLT
(Extensible Stylesheet Language Transformation) as the standard format to represent the transformations between
XML documents
This way all links and Functoids that are graphically visible in the Mapper Grid are a graphical representation of an
XSLT document that transforms the source document in a particular format specified by the destination schema, i.e.,
BizTalk maps are graphical representations of XSLT (Extensible Stylesheet Language Transformation) documents that
allow us to perform, in a simple and visual manner, transformations between XML messages.
During execution, a BizTalk map is focused on the final document and the execution order of mapping rules follows a
sequence based around the requirements of the final document. When the map is compiled, these rules are translated
into XPath queries and XSLT functions in order to transform the required information, i.e., the mapping rules are built
from the destination (target) and not the source as some traditional tools (or traditional models).
The BizTalk mapping engine traverses the destination schema from beginning to end;
40
BizTalk Mapping Patterns and Best Practices
The mapping rules are constructed and executed as links are encountered in the destination schema;
The information is extracted from the source when a link is encountered in the destination schema.
Note
We can use an XSLT created by an external application and include it on the map inside a Scripting Functoid (XSLT
custom script) or by importing a XSLT file that carries out the complete transformation of the map (of course the
editor (BizTalk Mapper Designer) does not represent the graphical representations (links and Functoid) in this
scenario).
Deconstructing a map
In this section we will use the basic mapping operations previously described in the BASIC PRINCIPLES OF MAPS chapter in
TRANSFORMATIONS - BASIC MAPS FUNCTIONALITIES (DOCUMENT MAPPING) section, and analyze the decisions taken by the
BizTalk mapping engine.
Based on these functionalities we will explain how the BizTalk Mapper Designer processes and translates these links
internally. To better understand its functioning, we perform some changes to the structure of the destination schema:
we add an optional element ("CivilStatus") and intentionally disorganized its structure.
Basically on this mapping problem there are two similar schemes, which we intend to map the source elements in
their proper destination and for which we implemented the following challenges:
Concatenate the first and last name in order to give the full name (Concatenation of values);
Map the Address in its destination element (Direct copy);
Transform the date of birth into age (Custom scripts);
The Zip Code should only be mapped if it has a valid string, otherwise it will not be mapped (Conditional selection);
The element “CivilStatus” is optional and as we have no evidence in the source to map it, it should be ignored.
41
BizTalk Mapping Patterns and Best Practices
Additionally, we perform a more advanced mapping logic to calculate the total of national and international calls
using cycles, conditional selections and mathematical operations.
As you can see, we intentionally switched the order of elements in the destination schema in order to, more easily,
understand and verify how BizTalk maps works.
Note
The order in which we perform the links between the elements from source to destination schema, in this scenario,
is irrelevant to the compiler, however the same cannot be said for Functoids. The Functoids require certain input
parameters that can vary according to the Functoid that we are using, in this case the order with which we associate
the link is extremely important.
I will not show the entire representation of this XSLT document because it’s a little extended. However you can view
as inspect the XSLT code by validating the map, explained in the VALIDATE MAP section present in the BASIC PRINCIPLES OF
MAPS chapter (the link for the source code is available at the end of the chapter in the RESOURCES section), or through
the following link:
https://gist.github.com/2508405
Based on this document, we will follow the compiler’s behavior. What he performs is the translation of all the links
and functoids present on the map, as he finds them linked to the destination schema, while he traverses the
destination schema from beginning to end:
The first element found is "Address"; Since there is link associated to this element, the Link is translated by one
XPath expression (”Address/text()”) that defines the element to be extracted from the source:
42
BizTalk Mapping Patterns and Best Practices
The second element found is “ZipCode” also with a link associated; It is a conditional selection (Logical Existence
and Value Mapping Functoids) that will be translated into a XSLT condition (<xsl:if>):
The third element is "CivilStatus", since there are no links associated with this element, it is ignored in the mapping
process.
43
BizTalk Mapping Patterns and Best Practices
The fourth element to be processed is “FullName” and once again there is a link associated, which corresponds to
the concatenation of two elements of the origin; If you check the generated code, the variable value “$var:v3”,
that was generated from the execution of the function userCSharp:StringConcat that is visually represented by
the String Concatenate Functoid, is assigned to the element "FullName":
The fifth element is “Age”, a link is found which means that custom script found inside the CSharp Inline Scripting
Functoid will be carried out:
44
BizTalk Mapping Patterns and Best Practices
Finally we found the record “PhoneBilling” that contain two elements: “TotalInternational” and “TotalNational”
both with links associated.
o Note that although we have not defined any cycle through loop Functoid, the compiler is smart enough to
realize that we are dealing with a cycle and translate it correctly. Also the use of the Cumulative Sum
Functoid will be translated always into a cycle (<xsl:for-each>) and will force that everything that is linked
to it will be under this cycle.
45
BizTalk Mapping Patterns and Best Practices
o However, unfortunately, it will create a new cycle for each element in the destination schema
(“TotalInternational” and “TotalNational”). For a better optimization, it will require us to use a custom
script.
o Both elements are calculated using conditions and mathematical calculations as you will see in the
generated code
In fact the order with which we associate links (Drag&Drop) from the source to different destination elements is
irrelevant, since the compiler, as previously explained, will process them in the correct order… Except if we have to
associate several links to the same destination element or Functoid. In these two last cases the order in which the link
association takes place is extremely important and can lead to unexpected results.
Briefly, the mapping engine process the rules by going through the destination schema from the beginning to the end,
processing the links in the order it finds them and in case of multiple links in a particular element or Functoid, they are
processed in the order in which they were associated.
This means that the links associated with the parent nodes (records) are processed before links associated with
children (elements inside the record).
A good example of this scenario is the use of conditions in the parent node (record) when we want to influence the
outcome according with a particular condition. So…let's find all the names of female clients. To do this we will create
a map with the following settings:
46
BizTalk Mapping Patterns and Best Practices
Open the Toolbox window and drag the Looping Functoid onto the grid;
o Drag a link from the record “Client” from the source schema to the Looping Functoid;
o Drag a link from the Looping Functoid to the record “Person” in the destination schema;
Drag the Equal Functoid from the Toolbox window onto the grid;
o Drag a link from the element “Sex” from the source schema to the Equal Functoid;
o Drag a link from the Equal Functoid to the record “Person” in the destination schema;
o Configure the Equal Functoid, by double clicking in the Functoid, and edit the second condition with the
value “F” to build a condition equivalent to Sex = "F";
47
BizTalk Mapping Patterns and Best Practices
The Equal Functoid will return the value “True” if the first input, in this case, the element “Sex”, is equal to the second
input parameter, i.e., “F”. Otherwise it will return the value “False”. What will lead to: the record “Client” is only
mapped if the condition returns the value "True".
<xsl:template match="/s0:PeopleOrigin">
<ns0:PeopleTarget>
<xsl:for-each select="Client">
<xsl:variable name="var:v1" select="userCSharp:LogicalEq(string(Sex/text()) , "M")" />
<xsl:if test="$var:v1">
<Person>
<Name>
<xsl:value-of select="Name/text()" />
</Name>
<Sex>
<xsl:value-of select="Sex/text()" />
</Sex>
</Person>
</xsl:if>
</xsl:for-each>
</ns0:PeopleTarget>
</xsl:template>
We can check that the first action of the map, after the cycle that travels the various elements of the record “Client”,
is: get the value generated in the Equal Functoid, which is represented in the variable "v1";
And the second action is to validate the condition (IF) with the value of the first operation (v1), i.e., test whether the
value "v1" is "True" or “False”. If the condition is true the code within the condition is executed, otherwise it will move
to the next element without doing anything. Therefore we obtain the desired result:
<ns0:PeopleTarget xmlns:ns0="http://HowMapsWorks.PeopleTarget">
<Person>
<Name>Elsa Ligia</Name>
<Sex>F</Sex>
</Person>
</ns0:PeopleTarget>
This Functoid returns the value of the second parameter if the value of the first parameter is "true". If the value of the
first parameter is not "true", the corresponding element or attribute in the output instance message is not created.
Therefore, it is necessary to respect the order in which we associate the links:
The first parameter must be a value "true" or "false", generally from the output of some other Logical Functoid or
from a variable Boolean field in the input instance message.
The second is the value that is output if parameter 1 is "true". This value can be from: a link from a node in the
source schema that represents simple content, the output from another Functoid, or a constant input parameter.
If we change the order in which the links are associated to the Functoid, it will lead to mapping errors or unexpected
results, according to the Functoid used.
48
BizTalk Mapping Patterns and Best Practices
The link reorganization in Functoids is very easy to accomplish, you just open the Functoid detail (double click) and use
the sort buttons.
Taking the last exercise as example but this time let’s find all client and employees’ male names. To do this we will
create a map with the following settings:
o Configure the Equal Functoid, by double clicking in the Functoid, and edit the second condition with the
value “M” to build a condition equivalent to Sex = "M";
49
BizTalk Mapping Patterns and Best Practices
If you just open the Looping Functoid detail (by double click) to configure the functoid we will notice the order of the
link association, similar to what we explained earlier with the Value Mapping Functoid, we will realize that in the first
place it will process the “Client” node and then the “Employee” node:
<ns0:PeopleTarget xmlns:ns0="http://HowMapsWorks.PeopleTarget">
<Person>
<Name>Sandro Pereira</Name>
<Sex>M</Sex>
</Person>
<Person>
<Name>Pedro Lamas</Name>
<Sex>M</Sex>
</Person>
<Person>
<Name>Jose Antonio</Name>
<Sex>M</Sex>
</Person>
<Person>
<Name>Rui Barbosa</Name>
<Sex>M</Sex>
</Person>
</ns0:PeopleTarget>
However if we change this order, then the output will be complete different:
<ns0:PeopleTarget xmlns:ns0="http://HowMapsWorks.PeopleTarget">
<Person>
<Name>Jose Antonio</Name>
<Sex>M</Sex>
</Person>
<Person>
<Name>Rui Barbosa</Name>
<Sex>M</Sex>
50
BizTalk Mapping Patterns and Best Practices
</Person>
<Person>
<Name>Sandro Pereira</Name>
<Sex>M</Sex>
</Person>
<Person>
<Name>Pedro Lamas</Name>
<Sex>M</Sex>
</Person>
</ns0:PeopleTarget>
Unfortunately, when we associate different links in the same element, there is no way or place in the graphical editor
where you can check the order of the association, for example, similarly to what happens with the Functoids. The
only way to verify the order in these cases is to inspect the XSLT generated code or testing the map.
A good example of this scenario is when we associated two different Scripting Functoid, both with custom inline XSLT
scripts to the same destination element or record, once again, changing the order of the link association may have
unexpected results.
In this example the first Scripting Functoid contains the following XSLT code:
<xsl:for-each select="Client">
<Person>
<Name>
<xsl:value-of select="Name/text()" />
</Name>
<Sex>
<xsl:value-of select="Sex/text()" />
</Sex>
</Person>
</xsl:for-each>
This code performs the mapping of all existing elements in the record "Client" from the source schema to the elements
on the record "Person" in the destination schema.
<xsl:for-each select="Employee">
<Person>
51
BizTalk Mapping Patterns and Best Practices
<Name>
<xsl:value-of select="Name/text()" />
</Name>
<Sex>
<xsl:value-of select="Sex/text()" />
</Sex>
</Person>
</xsl:for-each>
But this time it will map all existing elements in the record "Employee" from the source schema to the elements on
the record "Person" in the destination schema.
The expected outcome that we want to appear in the final document is: all clients presents in the record "Person" first
and then all the employees. If we change the order in which we associated the links in the record “Person”, we will
see that the outcome will also change.
Original Message:
<ns0:PeopleOrigin xmlns:ns0="http://HowMapsWorks.PeopleOrigin">
<Client>
<Name>Sandro Pereira</Name>
<Age>33</Age>
<Sex>M</Sex>
</Client>
<Client>
<Name>Elsa Ligia</Name>
<Age>28</Age>
<Sex>F</Sex>
</Client>
<Client>
<Name>Pedro Lamas</Name>
<Age>28</Age>
<Sex>M</Sex>
</Client>
<Employee>
<Name>Jose Antonio</Name>
<Age>39</Age>
<Sex>M</Sex>
</Employee>
<Employee>
<Name>Rui Barbosa</Name>
<Age>35</Age>
<Sex>M</Sex>
</Employee>
</ns0:PeopleOrigin>
Expected outcome:
<ns0:PeopleTarget xmlns:ns0="http://HowMapsWorks.PeopleTarget">
<Person>
<Name>Sandro Pereira</Name>
<Sex>M</Sex>
</Person>
<Person>
<Name>Elsa Ligia</Name>
<Sex>F</Sex>
</Person>
52
BizTalk Mapping Patterns and Best Practices
<Person>
<Name>Pedro Lamas</Name>
<Sex>M</Sex>
</Person>
<Person>
<Name>Jose Antonio</Name>
<Sex>M</Sex>
</Person>
<Person>
<Name>Rui Barbosa</Name>
<Sex>M</Sex>
</Person>
</ns0:PeopleTarget>
<ns0:PeopleTarget xmlns:ns0="http://HowMapsWorks.PeopleTarget">
<Person>
<Name>Jose Antonio</Name>
<Sex>M</Sex>
</Person>
<Person>
<Name>Rui Barbosa</Name>
<Sex>M</Sex>
</Person>
<Person>
<Name>Sandro Pereira</Name>
<Sex>M</Sex>
</Person>
<Person>
<Name>Elsa Ligia</Name>
<Sex>F</Sex>
</Person>
<Person>
<Name>Pedro Lamas</Name>
<Sex>M</Sex>
</Person>
</ns0:PeopleTarget>
The exception to the rule of Link Sequence: Process links out of order
However there is one important exception to this rule of Link Sequence, especially when using custom scripts in
recursive records or elements.
Once again, a good example of this scenario is the use of custom scripts to increment counters. We can illustrate this
scenario by adding two Scripting Functoids to the map:
The first containing the initialization and the function to increment the counter:
int myCounter = 0;
public void IncrementCounter()
{
myCounter += 1;
}
53
BizTalk Mapping Patterns and Best Practices
{
return myCounter;
}
Note
This example will be associated with a loop, or with a recursive element.
We would expect that in the first cycle the result of the second script to be the value "1", in the second cycle we would
obtain the value "2" and so on. However, if we test the map, we’ll get a different result:
<ns0:PeopleTarget xmlns:ns0="http://HowMapsWorks.PeopleTarget">
<Person>
<LineNumber>0</LineNumber>
</Person>
<Person>
<LineNumber>1</LineNumber>
</Person>
<Person>
<LineNumber>2</LineNumber>
</Person>
</ns0:PeopleTarget>
As we can see in the result above, the sequence in which the links are executed is:
...
<ns0:PeopleTarget>
<xsl:for-each select="Client">
<Person>
<xsl:variable name="var:v1" select="userCSharp:ReturnCounter()" />
<LineNumber>
<xsl:value-of select="$var:v1" />
</LineNumber>
<xsl:variable name="var:v2" select="userCSharp:IncrementCounter()" />
<xsl:value-of select="$var:v2" />
</Person>
</xsl:for-each>
54
BizTalk Mapping Patterns and Best Practices
</ns0:PeopleTarget>
Of course we can change the existing code in the Scripting Functoids so we can get around this behavior and thus
obtain the desired result. However, this example serves to warn that in some scenarios, especially when using custom
scripts in recursive records or elements, it is necessary to verify and validate the sequence in which the rules (links)
are executed.
Resources
All source code is available in the Microsoft Code gallery here: BizTalk Server – Basics principles of Maps
(http://code.msdn.microsoft.com/Funcionalidades-bsicas-dos-280cebea)
55
BizTalk Mapping Patterns and Best Practices
Best Practices
56
BizTalk Mapping Patterns and Best Practices
Dealing with large transformation can be a challenge, maps can become very complex and therefore very difficult to
implement, maintain and read. This chapter will provide the reader with some of the best practices that we can apply
when developing BizTalk Server Maps to keep them organized and well documented which may lead you to improved
performance in the processes of maintaining and developing maps.
Reduce background “noise” using highlight propagation to show only the nodes that are relevant to the user;
Auto-scrolling and coalescing of sibling nodes to help locate the nodes of interest easily;
Support for Searching in all or parts of map that will help us find the nodes or labels of interest easily;
Predictive match.
Dealing with huge and complex maps can be a challenging especially if they are poorly structured.
To minimize this problem, BizTalk server provides three main features to aid in the readability and maintainability of
maps:
Grid Pages to organize maps into blocks of mappings operations – isolated segment groups of links and Functoids
based on some transformation context.
Link Labels to document and clarify the purpose of a link.
Functoid Label and Comment to document and clarify the purpose of a functoid.
57
BizTalk Mapping Patterns and Best Practices
Nevertheless one of the BizTalk developer’s most difficult, challenging and frustration task still is documenting BizTalk
Maps. Unfortunately, there is no magic tool or easy way to accomplished that automatically for us and still the best
way is to have best practices (will be address below) when we are developing the maps that will make our task of
reading and comprehension be easier and more effective.
To help us document our maps we can also make use of some tools provided by the BizTalk community like BizTalk
Map Documenter (http://biztalkmapdoc.codeplex.com/), which basically is a Stylesheet that will transform your
BizTalk map into a HTML view containing the following information:
One of the advantages of having your maps exposed in an HTML format is that this is a friendlier format to share with
non-developers who need to understand the transformations (e.g. testers) and who may not have access to Visual
Studio.
You can also make use of other community tools to make general documentation of your BizTalk Applications, like:
However these tools, in respect to maps, they all require technical expertise to be able to understand them because
they only produce the XSLT representation of the map.
Grid Pages
As we previously said, you can define grid pages as logical containers of links and Functoids with the sole aim to
organize maps, because at run time they don't have any impact, since they will become invisible to the compiler.
Although in small maps using one page can be enough, when dealing with complex schemes such as EDI, "infecting" a
page with numerous links and Functoids makes them unreadable or difficult to understand, even with all the
improvements made on the mapper since BizTalk Server 2010, this can be even more painful if you use oldest versions,
reaching to the point of not being able to distinguish one element from another.
The solution to this potential complexity is to use different grid pages to segment and isolate groups of links and
Functoids into different logical “containers/layers”. ”. You can use them to segregate different aspects of your mapping
58
BizTalk Mapping Patterns and Best Practices
into different pages, and then view and work with those pages separately. This separation is only for
readability/organization purposes, pages have no impact on map execution.
Pages are represented as tabs in the grid and BizTalk Mapper allows you to create, remove, delete and reorder grid
pages. By default, the map file is created with one grid page named “Page 1”, this feature was described earlier on
the POSSIBLE OPERATIONS ON PAGES section of the BASIC PRINCIPLES OF MAPS chapter.
Also to help us organize old and new maps, since BizTalk Server 2010 version, BizTalk Mapper supports some important
features like:
Of course some of these operations have some limitations, for example: Links and Functoids can be pasted into other
pages and other maps, however Links will only be pasted if target node XPath is valid. Or Links and functoids connected
to each other must all be in the same grid page. You can learn more about Working with Grid Pages here:
http://msdn.microsoft.com/en-us/library/aa558697.aspx.
Note
Grid properties apply to the entire grid and not to an individual page. Setting a Grid property establishes the value
for all of the pages and not merely the page displayed.
59
BizTalk Mapping Patterns and Best Practices
When dealing with huge and complex maps, for example mapping IDOCs or EDI documents we can easily have more
than 20 pages in a map. And if we don’t have the care to use a well-formed naming conventions for our grid pages we
end up in a mess of pages called. "Page 1", "Page 2", "Page 3" and so on… making the logic or the purpose of all of the
grid page extremely difficult to understand for any person that needs to read and maintain the map.
Like any traditional programming language where we applied best coding practices, for example, giving well-formed
naming conventions to objects; constants or variables. These same cares should also be applied to any BizTalk artifact:
pipelines, schemas (elements, attributes …), orchestrations, maps, and so on.
Grid pages should have a name, long enough to be meaningful but short enough to avoid being wordy, so that whoever
is reading or maintaining the map can easily comprehend and have a clear notion of the purpose of the grid page.
o You can use different capitalization styles or naming conventions but you should avoid using spaces and try
to use the smallest scope possible, so that you can have a large number of grid pages fitting in your window
and therefore avoiding scrolling operations.
Another convention is to use the name of the segment/node that you are addressing
o This technique can be very useful for example when we are dealing with EDIFACT messages that are
composed by well-known segments:
UNH: Message header - To head, identify and specify a message.
BGM: BEGINNING OF MESSAGE - To indicate the type and function of a message and to transmit
the identifying number.
DTM: DATE/TIME/PERIOD - Function: To specify date, and/or time, or period.
60
BizTalk Mapping Patterns and Best Practices
Readability and Maintainability: For new and even for expert developers, or when working with developers from
other teams, using multiple grid pages will make the map easier to read and maintain.
Level of effort: by being easier to read and maintain you will reduce the development and support time.
Documentation: Using these techniques will also help you to make a better map documentation, and sometimes
this could be enough to self-documenting the map
Link Labels
Labels are helpful to document and to clarify the purpose of a link in a map (or a Functoid). You can use the Label
property to put a description or name a link. This is useful when your map contains big schema structures and
identifying the inputs and output links to a Functoid becomes difficult.
Note
The maximum number of characters allowed for link labels is 256. If a string with more than 256 characters is
specified, the first 256 characters are accepted and the rest are discarded.
In previous BizTalk versions, by default, the XPATH query is presented if a link from the source schema is established
to a Functoid:
Or it will show the name of the previous Functoid if it’s linked from another Functoid, which may cause the reading of
maps more difficult.
Since BizTalk Server 2010 this behavior was slightly improved. Currently, the default value is the name of the element
of the source schema from where the link comes:
61
BizTalk Mapping Patterns and Best Practices
However, the map editor allows us to label the links, replacing the XPATH query (in previous versions) or the name the
element of the source schema, with a friendly description. For this we need to:
62
BizTalk Mapping Patterns and Best Practices
By doing that operation the Functoid becomes more legible, because now we can see the description of the link instead
the name of the Functoid or in previous versions the XPATH query:
We can easily read these comments by placing or moving the cursor over the link without clicking it, a screen tip
appears with useful information about that link (or Functoid) without the need to access to the properties window or
having to enter Functoids properties window
63
BizTalk Mapping Patterns and Best Practices
This is call Infotips and they can displayed in Functoids or links. Infotips over Links will display:
Note
BizTalk Mapper also provides another different screen tip: tooltips. Tooltips are displayed for those schema nodes
that are hidden partially/completely from the current alignment in the grid view (see more here:
http://technet.microsoft.com/en-us/library/ff629720.aspx).
Readability and Maintainability: For new and even for expert developers, or when working with developers from
other teams, using multiple link labels will make the map easier and faster to read and maintain. We can make an
analogy with C# code, if we are reading a function or a piece of code that doesn’t have any comment or inadequate
nomenclature it can become difficult and time consuming to understand, but if it’s well structured and commented
the developer's life will be facilitated, the same applies here.
Note
The BizTalk Mapper provides a search box and options to select which view you want to search in. Unfortunately it
does not have the ability to search link Labels, however If they are linked to Functoids you can use the option
search for functoid input parameters and search for your Link Label. As you enter the search string, the objects
that meet the search criteria are highlighted.
Level of effort: again, by being easier to read and maintain you will reduce the development time.
Documentation: Using this technique will also help you to make a better map documentation
Labels and comments are helpful to document the purpose of a Functoid in a map. You can use the Label property to
provide a name for a Functoid and the Comments property that will provide with a way for you to provide additional
information about the Functoid, typically relevant information about the operation being performed.
The BizTalk Mapper included in the previous releases had already support to add labels for links and Functoids.
However, it was possible to set the labels only through the property grid. Since BizTalk Server 2010, you can now set
the label and add comments for a Functoid from the same dialog box that you use to configure the Functoid. The
dialog box has a Label and Comments tab that you can use to specify a label. For links you continue to set the labels
from the property grid:
64
BizTalk Mapping Patterns and Best Practices
Right-click the Functoid you want to label and comment, and then click Configure Functoid Inputs.
In the Configure <Functoid> Functoid dialog box, click the Label and Comments tab.
Enter the following information, and then click OK.
o Label – Enter the new name. The maximum number of characters allowed is 256. If a string with more than
256 characters is specified, the first 256 characters are accepted and the rest are discarded.
o Comments – Enter the comments for the Functoid. The maximum number of characters allowed is 1024. If
a string with more than 1024 characters is specified, the first 1024 characters are accepted and the rest are
discarded.
Or you can use the Properties windows by selecting the Functoid you want to label and comment and entering the
same information there.
Like we saw with links, we can read directly from the map grid the labels and comments made in the Functoids by
placing or moving the cursor over the link without clicking it. A screen tip will appear with useful information about
that item, again without having the need to access to the properties window or having to open the Functoids
properties window
65
BizTalk Mapping Patterns and Best Practices
Important also to know that BizTalk Mapper provides a search box and options to select which view you want to search
in. You can choose to search for the functoid name, label, comment, or input parameters. As you enter the search
string, the objects that meet the search criteria will be highlighted.
Note
Use labels and Comments on links and in Functoids extensively for better understands your maps. Imagine yourself
reading a C# project without any comment on functions or inline comments and without no well-formed naming
conventions. Well same principle applies to maps.
As you develop a map you can test it 5, 10, 20, 50 or more times, and you must understand that a small modification
in one area of the map can cause a bug to appear, or the map engine may misunderstand of your intentions, and
presenting unintended results or failures, but by running this tests often you can reduce the segment, or mapping
block area, where the errors or bugs are emerging and it will be more easier to locate and fix those issues.
However, if instead of performing this continuous testing process, developers prefer to build the entire map and test
it only at the end, they will realize that often it becomes extremely difficult to find the problems. And if they are new
in this technology probably they don’t know how and where to start looking for the cause of the problem.
A BizTalk developer has a couple of options when it comes to unit testing BizTalk artifacts. Testing each of them can
be done using a framework like: BizUnit; some of the other available tools offered through CodePlex; or with built in
features in BizTalk projects inside Visual Studio. The Test Map feature (an option on the Tools menu) automatically
generates a test instance of the source document from the specification. And you can accomplish this operation by:
66
BizTalk Mapping Patterns and Best Practices
By default an instance of the input schema is generated automatically with dummy values, according to their type,
and tested in the selected map. At the end, the generated result or the errors that occurred are displayed in the output
window.
Note
When you test a map, BizTalk Mapper automatically compiles it. However, it is best to first compile a map and
resolve any warnings or errors prior to testing it.
Nevertheless, all too often this scenario is not ideal, and what we want is to test an existing and real document, not a
dummy one. BizTalk Mapper allows us to specify a source document and it also supports instances as native (CSV, EDI
…) or Extensible Markup Language (XML). In addition, it also supports native output from the map test process where
applicable as well. For this we only need to configure the properties of the map before we execute the test:
In this window we can also configure other properties such as: specify the format of the input instance message
(TestMap Input) or the format for the output instance message (TestMap Output); specify the location where the Test
Map should generate the output message (TestMap Output Instance). But more importantly we can specify whether
we want to validate input instance messages against the source schema before you test the map (Validate TestMap
Input) or the output instance messages against the destination schema after you test the map (Validate TestMap
Output).
If you want to know more about BizTalk Map file properties please check the following resources:
67
BizTalk Mapping Patterns and Best Practices
Note
If you do not designate an output instance, BizTalk Server will create an output file, place the output file into a
folder, and indicate the file name and path.
Note
However it is very important that when you are satisfied with our development, you must enable this property
(set to “True”) for the final test so that you can make sure that the validation succeeds.
Debugging a Map
If your map does not provide you with the output you need and expect, we may need to do some debugging operations
to better comprehend and inspect the problems we are facing. BizTalk supplies you with the option to debug your
map (XSLT code) line for line to see what it is happening. This operation was already explained in the DEBUG MAP section
present in the BASIC PRINCIPLES OF MAPS chapter.
Unit Testing
After a map is developed, validated, tested, and possibly debugged, you should enable unit testing of the map. Testing
is an important aspect of (BizTalk) application life cycle. Before a developer deploys his solution he needs to be
confident that it will perform, and do the task(s) it is intended to do. BizTalk Server ships with the option to do unit
testing on your maps, which you should leverage. With BizTalk Server 2009 the unit test feature was introduced, which
offered built-in developer support for testing schemas, pipelines and also maps in Visual Studio. The test capabilities
offered by Visual Studio in for BizTalk artifacts are the following:
68
BizTalk Mapping Patterns and Best Practices
Validating an XML document instance (not covered by this book, you can learn more about how to Validate Instance
Messages here: http://msdn.microsoft.com/en-us/library/aa577644.aspx).
Testing a map (explained earlier).
Unit test a schema, map and/or a pipeline.
The first thing to do is to enable unit testing on the project that contains a map you want to unit test. To do so you
need to:
Go to Solution Explorer.
Right-click the project that contains the map that is to be unit tested, and choose Properties.
Go to the Deployment pane and enable the Enable Unit Testing property
This feature allows you to create unit tests for schemas, maps, and pipelines. When this feature is enabled and the
project rebuilt, the artifact classes will be derived from the following base classes to support unit testing:
Schema: Microsoft.BizTalk.TestTools.Schema.TestableSchemaBase
Map: Microsoft.BizTalk.TestTools.Mapper.TestableMapBase
Pipeline: Microsoft.BizTalk.TestTools.Pipeline.TestablePipelineBase
On the File menu, choose "Add", and then choose "New Project...."
69
BizTalk Mapping Patterns and Best Practices
In the New Project dialog box, expand "Installed", expand "Visual C#", and then choose "Test".
From the list of templates, select "Unit Test Project".
70
BizTalk Mapping Patterns and Best Practices
Now we need one test class for testing our map. We can use the UnitTest1.cs that was generated by the project
template, but we should give the file and class more descriptive names. We can do that in one step by renaming the
file in Solution Explorer.
using UnitTestingFeatureWithMaps.Maps;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
namespace UnitTestProject1
{
/// <summary>
///This is a test class for HowMapsWorksTest and is intended
///to contain all HowMapsWorksTest Unit Tests
///</summary>
[TestClass()]
public class HowMapsWorksTest
{
private TestContext testContextInstance;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
[TestMethod()]
public void HowMapsWorksMapTest()
{
HowMapsWorks map = new HowMapsWorks();
//=== Use the HelloWorld sample directory path for the message files ===//
71
BizTalk Mapping Patterns and Best Practices
//=== Test the map by using the TestMap method of the TestableMapBase class ===//
map.ValidateOutput = true;
map.TestMap(strSourcePO_XML,
Microsoft.BizTalk.TestTools.Schema.InputInstanceType.Xml,
strDestInvoice_XML,
Microsoft.BizTalk.TestTools.Schema.OutputInstanceType.XML);
//=== Output file should be created as a result of testing the map ===//
Assert.IsTrue(File.Exists(strDestInvoice_XML));
}
[TestMethod()]
public void HowMapsWorksWithoutPhoneCallsMapTest()
{
HowMapsWorks map = new HowMapsWorks();
//=== Use the HelloWorld sample directory path for the message files ===//
string strSourcePO_XML = testContextInstance.TestDir +
"..\\..\\..\\Files\\PersonOrigin2.xml";
string strDestInvoice_XML = testContextInstance.TestDir +
"\\OUT\\PersonTargetWithoutTotals.xml";
//=== Test the map by using the TestMap method of the TestableMapBase class ===//
map.ValidateOutput = true;
map.TestMap(strSourcePO_XML,
Microsoft.BizTalk.TestTools.Schema.InputInstanceType.Xml,
strDestInvoice_XML,
Microsoft.BizTalk.TestTools.Schema.OutputInstanceType.XML);
//=== Output file should be created as a result of testing the map ===//
Assert.IsTrue(File.Exists(strDestInvoice_XML));
}
}
}
To build and run the Unit Test you need to use the Test Explorer window from Visual Studio unit test projects. There
you can also debug tests and analyze test performance and code coverage.
When you build the test project, the tests appear in Test Explorer and as you run, write, and rerun your tests, Test
Explorer displays the results in default groups of Failed Tests, Passed Tests, Skipped Tests and Not Run Tests. You can
change the way Test Explorer groups your tests.
72
BizTalk Mapping Patterns and Best Practices
On the Visual Studio main menu choose "Test", choose "Windows", and then choose "Test Explorer".
You can run all the tests in the solution, all the tests in a group, or a set of tests that you select. Do one of the following:
The pass/fail bar at the top of the Test Explorer window is animated as the tests run. At the conclusion of the test
run, the pass/fail bar turns green if all tests passed or turns red if any test failed.
See more about Running Unit Tests with Test Explorer here: http://msdn.microsoft.com/en-us/library/hh270865.aspx.
Unfortunately there is a bug in BizTalk Server 2013 with Map Unit Test inside Microsoft.BizTalk.TestTools.dll, so each
time we try to run the unit test for the map it give us the following error:
Microsoft forgot to update the TestableMapBase class. They still using the BTSXslTransform instead of using
XslCompiledTransform witch will cause the TestMap() function to failed. The good news is that, until a hotfix is not
available, this can be easily fix using a “.testsettings” file.
Unit tests in Visual Studio 2012 can be configured by using a “.runsettings” file (“.runsettings” is new in Visual Studio
2012 – if you’re familiar with unit testing in previous versions of Visual Studio, you might know about “.testsettings”
files). For example, you can change the .NET Framework on which the tests will be run, the directory where test results
are delivered, and the data collected during a test run.
73
BizTalk Mapping Patterns and Best Practices
You can still use “.testsettings” in Visual Studio 2012, so any test configurations you wrote for previous editions will
still work. But “.testsettings” can be used only to configure tests written for the MSTest adapter. By contrast,
“.runsettings” can be used with any of the adapters built for the extensible unit test framework in Visual Studio 2012,
such as xUnit.net and NUnit.
Unfortunately, if we add a “.runsettings” file our test project still doesn’t work. However if we take the “.testsettings”
file that was generated for example in Visual Studio 2010/BizTalk Server 2010 and add this file to our Test project in
Visual Studio 2012/BizTalk Server 2013 or if we add a new “.testsettings” file from our BizTalk solution it works and
solve the problem that I was facing, I really don’t know why but is the best workaround that we can implement to
solve all the problems.
Unfortunately, if we add a “.runsettings” file our test project still doesn’t work. However if we take the “.testsettings”
file that was generated for example in Visual Studio 2010/BizTalk Server 2010 and add this file to our Test project in
Visual Studio 2012/BizTalk Server 2013 or if we add a new “.testsettings” file from our BizTalk solution it works and
solves the problem. Don’t really know why but this is the best workaround that we can implement at the moment to
solve these problems.
Right click on the BizTalk solution name: “Solution ‘UnitTestingFeatureWithMaps’ (2 projects)”, and select “Add”
and them “New Item…”
74
BizTalk Mapping Patterns and Best Practices
In the “Add New Item – Solution Items” dialog box, expand "Installed" and then choose "Test Settings".
From the list of items, select "Test Settings".
You can add more than one test settings file if you want to be able to switch quickly between different settings.
On the Visual Studio main menu choose "Test", choose "Test Settings", and then choose "Test Settings File".
75
BizTalk Mapping Patterns and Best Practices
In the "Open Setting File" window select the test setting file that we previous create: "TestSettings.testsettings"
Resources
Reference to this pattern:
BizTalk Server 2013: Step-by-Step to implement Unit Testing in Schemas and Maps
(http://social.technet.microsoft.com/wiki/contents/articles/18889.biztalk-server-2013-test-biztalk-artifacts-with-
visual-studio-2012.aspx)
BizTalk Server 2013: Test BizTalk artifacts with Visual Studio 2012
(http://social.technet.microsoft.com/wiki/contents/articles/18889.biztalk-server-2013-test-biztalk-artifacts-with-
visual-studio-2012.aspx)
Using the Unit Testing Feature with Schemas and Maps (http://msdn.microsoft.com/en-
us/library/dd224279.aspx)
BizTalk Server 2010: Step-by-Step to implement Unit Testing in Schemas and Maps
(http://social.technet.microsoft.com/wiki/contents/articles/26329.biztalk-server-2010-step-by-step-to-
implement-unit-testing-in-schemas-and-maps.aspx)
BizTalk Server 2013: Step-by-Step to implement Unit Testing in Schemas and Maps (Part 2)
(http://sandroaspbiztalkblog.wordpress.com/2014/08/29/biztalk-server-2013-step-by-step-to-implement-unit-
testing-in-schemas-and-maps-part-2/)
All source code is available in the Microsoft Code gallery here: BizTalk Server 2013: Using the Unit
Testing Feature with Schemas and Maps (http://code.msdn.microsoft.com/BizTalk-Server-2013-Using-
0fef5b25)
76
BizTalk Mapping Patterns and Best Practices
One-to-One transformations, which consist of a single source schema and single destination schema
Many-to-One transformations, which consist of two or more source schemas and one single destination schemas
Many-to-Many transformations, which consist of two or more source schemas and two or more destination
schemas
However I find myself constantly hear that, despite being easy to test one-to-one maps inside Visual Studio at design
time, when we have multiple inputs to the map, many-to-one or many-to-many transformations, the same doesn't
happen, and it's impossible to test this type of maps inside Visual Studio at design time because we only can specify
an input message… and that it’s not true.
Testing one-to-one maps is extremely simple and straightforward, and although it requires some additional steps,
many-to-one or many-to-many maps are also simple to test inside Visual Studio. But first you have to understand that,
Visual Studio doesn’t let us define multiple native instances in the “TestMap Input Instance” property, it only allows
one instance message. But when a map has multiple source schemas, they are wrapped in a hierarchy multi-part
message created by BizTalk.
So the only way for us to test this type of maps is to provide with an instance of the message in the “TestMap Input
Instance” property that matched with the hierarchy multi-part message created by BizTalk.
The question here is how we can easily create an instance of multi-part message?
And the answer is quite simple, by using the default behavior of the Test Map operation to make this work for us.
When we create a new map the “TestMap Input” and “TestMap Input Instance” properties are defined by default as:
“Generate Instance” and “” (empty) respectively:
This means, as I explained earlier that if we test the map without changing this properties, one instance message will
be generated automatically with dummy values. However in this scenario, it will generate a dummy instance of the
multi-part message expected by the map.
77
BizTalk Mapping Patterns and Best Practices
Through the File Explorer, go to the directory folder specified folder in the Output window to have access to the
dummy input file:
o In this case: “C:\Users\Administrator\AppData\Local\Temp\1”
Copy the file to your project folder, in this case: “inputfile.xml”
As you can see, all the different input messages are there, with the write namespaces and so on… So what we need to
do now is to:
Edit this file and put the User and Address messages that you want (you can do this easily with notepad)
And then specify the “TestMap Input Instance” property with this file.
You need to remember and learn that there’s never only a single way and there are no right or wrong way method to
solve a mapping problem, we can find more effective ways (performances) than others or easiest ways to solve the
problem, yet the output generated will be the same. Quite often, deciding which way is the best approach to use or
have the right balance between the easier and effective way can be difficult and often the approach used depend on
the expertise and personal choice of the developers or company guidelines. If you are a beginner or don’t feel
comfortable with XSLT you probably will try to accomplish all the transformations rules using the basic Functoids
78
BizTalk Mapping Patterns and Best Practices
regardless of how difficult it is, but if you are an XSLT lover you will probably not bothered using the mapper and take
a drastic decision to skip the mapper and do all the problem with a custom XSLT file, we will discuss this topic in the
next section (EXTERNAL CUSTOM XSLT FILE VS. BIZTALK MAPPER), or try accomplish this using custom script inside the
mapper. In this topic we will focus on some of the best practices in how to use Built-in Functoids, Scripting Functoids
or when to develop Custom Functoids to use in the BizTalk Mapper.
While there are a number of choices the correct one to use usually depends on your situation with no hard and fast
rule. However I do have some rules which I use as a guide to help me choose the best approach:
First rule: I prefer to use the built-in Functoids whenever possible unless is not possible to accomplish or the
Functoid chain becomes too complex to unravel easily.
Second rule: I turn to custom scripting Functoids, XSLT or C#, only when I cannot solve my problem with the built-
in Functoids or it is too complex to accomplish using built-in Functoids. A good example for using scripting Functoids
is to solve grouping problems, complex transformations rules with multiple elements or if/else decisions inside
cycles.
Third rule: If is a repeated transformation rule that you can use in several maps you then should create use/create
a custom Functoid to solve this problem.
However, this rules are derived from several factors that help me decide whether to use one option or the other:
Reusability: can this transformation be reused several times in this map or can be reused in several maps?
Level of effort: will this transformation cost me several hours of work?
Complexity: will this transformation be easier to read and maintain?
Performance: is this approach that will bring me more profits?
Built-in Functoids
I generally and strong recommend for you to use Built-in Functoids unless the Functoid chain becomes too complex to
unravel easily.
You probably may ask what’s the reference point to decide when the chain becomes complex and we should use
scripting instead Functoids, and it’s a good question. I personally like to always point this reference: The Rule of Six
that is described in some books that basically say:
“If you need more than six Functoids to accomplish a rule, you should consider using a script. If you need six or less
Functoids, you should not use a script.” - Pro Mapping in BizTalk Server 2009 Book
Note that you should always use this as a guideline and not a rule. I like to use this rule in a thoughtful way and not
to the letter because there are many situations that may contradict this Rule of Six. I can give this example also
reference by many books: if you need to reformat the date format from the source schema (yyyyMMdd) to your
destination schema dd/MM/yyyy.
You can easily implement this transformation rule by using only four simple string Functoids:
Three extraction string Functoids that break the date into year, month and day
And a String Concatenate Functoid then builds the new string
79
BizTalk Mapping Patterns and Best Practices
However, many maps have multiple instances of source dates that must be reformatted, in our example we have two,
which means you would have to replicate this Functoid chain two times, which give us a total of 8 Functoids that we
need to accomplish this transformation rule, which may increase depending on the number of existing date elements
and that also probably will definitely happen in other maps. So in this case the best suggested option is to create a
custom Functoid because:
You will reduce the amount of work needed to accomplish this rule;
You will be able to use them in all your maps
Alternatively we could also use a custom inline C# script to reduce the amount of work needed to accomplish this rule,
nevertheless this approach will only provide Reusability inside this specific map. However there is one important
strategy/rule to apply reusability in Custom Inline C# scripts, you could simple copy and paste the Scripting Functoid
but this will copy all of the function body inside which means that if any change is necessary that you will need to
change or recommend to change the code in two or more places. Because when you have two or more Custom Inline
C# scripts with the same Function name and structure, the compile will only take in consideration the first one linked
in the map, even if the others have a different code inside they are ignored by the compiler. So to be sure and have
coherence and transparency inside the map you need to change the code in all the Scripting Functoids.
80
BizTalk Mapping Patterns and Best Practices
When we use Custom Inline C# scripts the best way to implement reusability is to specify the body function in only
one Scripting Functoid and the remaining ones specify only the function declaration, in this sample in the first Scripting
Functoid will have the following code:
So the “Rule of Six” is just a guideline especially for new developers and for sure that over time you will gain experience
that will help you decide the best approach according to the principles of Reusability, Level of effort, Complexity and
Performance.
Overview/Visibility: Using the Functoids can give a developer a better overview of what functionality a map
provides, and sometimes it also provides a good overview for non-developers. Whereas Scripting Functoids with
custom XSLT needs to be read by a developer to be able to understand what is happening.
Maintainability: A BizTalk developer knows about maps and Functoids without necessarily having to know or be
an expert in XSLT (although I find extremely important). By staying with the Functoids you give a BizTalk developer,
new, expert or even to external team members, the best possible opportunity to understand and maintain a new
map. This reason is valid if you don’t use very complex Functoid chain and use best practices to organize and
document your maps.
Level of effort: by being easier to read and maintain you will reduce the development time.
81
BizTalk Mapping Patterns and Best Practices
Limit of operations scope: Although BizTalk Server provides many Functoids to support a range of diverse
operations, we are limited to the number of existing operations.
Many people do the entire map in XSLT, for example with only one Scripting Functoid inside the BizTalk Mapper editor
invoking the XSLT Script to perform all the transformation, I personally think that this strategy is not a good practice
however there may be one exception in which I agree with this approach that we will discuss and present in the next
section (EXTERNAL CUSTOM XSLT FILE VS. BIZTALK MAPPER).
Some best practices to use Scripting Functoid or Custom Functoids rather than a built-in Functoids chain are:
When you cannot solve our problem with built-in Functoids or if is too complex to accomplish using built-in
Functoids.
If it’s a repeated transformation rule that you can use several times or in several maps
Scripting Functoid
The Scripting Functoid enables you to use custom script or code at run time to perform functions otherwise not
available, supporting the following languages: C# .NET, JScript .NET, Visual Basic .NET, Extensible Stylesheet Language
Transformations (XSLT) and XSLT Call Templates.
Inline scripts are convenient for custom code that you are unlikely to use elsewhere in your application. In addition
to being convenient for one-time scripts, inline scripts are also useful for declaring global variables for use among a
number of scripts.
82
BizTalk Mapping Patterns and Best Practices
Performance. If you have challenging performance requirements and are a strong XSLT developer then you may
choose to create your own XSLT so that you can optimize the transformation and squeeze the best performance
possible out of the transform.
Maintainability and Reusability. If you remember I used this argument also in the built-in Functoids as well with
conditions and the same appends here if you use Scripting Functoids (C# or XSLT) to simplify the complex Functoid
chain or to be more reusable, then you are improving the Readability of the map and therefore enhance the
support process.
Everything is possible: Basically you can do what you want. Use different script types or combine them to solve
your transformation problems.
Reusability: Reusability can also be a disadvantage. We need to be very careful to reuse the same Scripting
Functoids as we explained earlier otherwise we need to rewrite over and over again the code and have code
duplication which can also lead to problems when we need to maintain the map.
Compiler limitations: When you create a script, for example a C# function, remember to give it a correct name
because all scripts with the same name are treated as one by the compiler regardless of whether the code is equal
or not.
o You also have to take in consideration that BizTalk Mapper engine will save the inline scripts in the
Extensible Stylesheet Language Transformations (XSLT) Stylesheet defining the map in the within the
msxsl:script element. The following namespaces are supported by default: System, System.Collection,
System.Text, System.Text.RegularExpressions, System.Xml, System.Xml.Xsl, System.Xml.Xpath,
Microsoft.VisualBasic. You can add support for additional namespaces outside the listed using the
namespace attribute of the child element, <msxsl:using>, of the <msxsl:script> element, but this will force
us to use an External Custom XSLT file to accomplish the transformation. See more here: XSLT Stylesheet
Scripting Using <msxsl:script> (http://msdn.microsoft.com/en-us/library/533texsx%28v=vs.110%29.aspx)
<msxsl:script>
<msxsl:assembly name="system.assemblyName" />
<msxsl:assembly href="path-name" />
<![CDATA[
// User code
]]>
</msxsl:script>
Support: If you are thinking in use XSLT language: it supports only XSLT 1.0 (XSLT 2.0 not supported).
This happens because often complex transformations are difficult to make using only a language and you can also do
the same in your custom scripts, by being able to create for example an inline XSLT and inside that script invoke C#
routines. For that reason, it’s a good practice combining different types of scripting and you should choose the best
type in different situations.
83
BizTalk Mapping Patterns and Best Practices
Custom Functoids
We talked earlier about the ability of having Scripting Functoids to run C# code, and if this is possible why do we need
to create Custom Functoids that can be hard to develop, because there are some steps involved in the creation process
that we need to do and understand. There isn’t too much advance official information about developing custom
Functoids only the basic, there isn’t out of the box with the product, a project template to create this type of resource
and BizTalk comes also with a good collection of readymade Functoid?
Although BizTalk Server provides many Functoids to support a range of diverse operations, when you start to create
many maps, you will start to realize that there are small operations or actions that are common in several of our maps
or you will likely encounter a situation that requires a different approach. As a consequence you will find yourself
spending your time maintaining several equal code snippets that you normally copy and paste into your maps in
several locations inside a map or in several maps. Such code snippet, when it can be condensed into a function, is a
good candidate for inclusion in a custom Functoid. Custom Functoids provide a way for you to extend the range of
operations available within the BizTalk Server mapping environment. Each custom Functoid is deployed as a .NET
assembly using classes derived from Microsoft.BizTalk.BaseFunctoids. And one assembly can contain more than one
custom Functoid.
And also a good news is that several community members already created several Custom Functoids supporting a
large number of operations and a project template for the several BizTalk Server/Visual Studio versions that you can
installed and use for free. You can learn more about this topics here: BizTalk: List of Custom Functoids
(http://social.technet.microsoft.com/wiki/contents/articles/11799.biztalk-list-of-custom-Functoids.aspx)
This way you should consider using a custom Functoid only to solve a repeat transformation rule that you can reuse
in several maps. Rather than writing the same inline code (C#, XSLT, and so on) and pasting it in multiple shapes, or
using a combination of multiple existing Functoids. For example in the following scenarios:
Your functoid depends on .NET namespaces that are not available to maps.
You need to encrypt or decrypt, encode or decode fields.
Get data from a proprietary legacy API, for example return a resolution internal GUID value of lookup field in CRM.
Basic function to generate dynamic data like generate a new Guid.
Functoids that make date time conversions like convert a traditional date (Human Readable Date) into a UNIX date
(Epoch Date) or convert the date time format.
You want to reduce the complexity of a map by combining several related steps, by using a different approach, or
by using new class libraries.
In some cases you do not want your business logic code exposed in clear text for all to read and possibly modify.
Or like I describe before if more than one map is using the same script code in a script Functoid.
The advantages of using custom Functoids (or reasons to develop custom Functoids):
Level of effort and Reusability: They are reusable. Because we are extending the BizTalk Mapper tool set of the
range with more Functoids that will have the same behavior that built-in Functoids, you can use them several times
in the map or in several maps such as built-in Functoids and therefore you are considerably simplifying the
development task at hand. But you can also you can reuse them on other projects not just your own project now.
The idea of developing a custom Functoid instead of a Scripting Functoid is to avoid code repetition and to be able
to modify it in every map that uses it simultaneously.
Overview: Similarity to built-in Functoids they are more easy to read (visually on the map grid) than Scripting
Functoids.
84
BizTalk Mapping Patterns and Best Practices
Deploy and development: Don’t need to be referenced in BizTalk projects you only need to install them on the
server.
Compiler limitations: All Functoids must have a unique ID in order for the runtime to distinguish them.
o Certain Functoid IDs are reserved by standard/inbuilt Mapper Functoids. Usually, the standard Mapper
Functoids use the IDs from 1 to 10000. While creating custom Functoids, do not use the Functoid IDs less
than 10000.
Development: it requires experience with .NET Programming.
Maintenance: This is not about the maintenance of the map but the maintenance of the code behind the Functoid.
o They are more difficult to debug for errors if we compare with Scripting Functoid.
o And more difficult to have version control of this resources.
Testability: Like any other BizTalk artifact, testing this component is not a straight task. It can be accomplished but
will require additional steps or approach:
o The first and common way is to use the custom Functoid inside a map and then validate and test the map
from within Visual Studio 2010, checking that no errors occur and manually inspecting the output to make
sure it provides the expected result;
o The second way is to use the unit testing capabilities of BizTalk maps to test and debug our custom Functoid;
o And the last option in to debug in runtime. When debugging the functoid in runtime, make sure the latest
compiled version is deployed and make sure your host instance has been restarted, so it hasn’t cached a
previous version. Then inside Visual Studio 2010, set breakpoints in your code wherever you want the code
to break and when this it done, choose the BTSNTSvc.exe process in the Visual Studio main menu Debug
on the Attach to Process option.
Note
Don’t write a custom Functoid only to solve a very particular transformation problem, instead you should consider
to use and create a custom Functoid only to solve a repeat transformation rule that you can reuse in several maps.
The reason put your transformation rules logic in a .NET assembly stored in the global assembly cache (GAC) is basic
exactly the same as developing a Custom Functoid and the choice between developing a Custom Functoid or wrap in
an assembly often depend on the expertise and personal choice of the developers or company guidelines but also with
some advantages/disadvantages in their different behaviors.
Maintenance: If you have an external assembly with your transformation rule logic, then you can easily maintain it
(making fixes or updates) without having to update and redeploy the maps. This means that you can change the
way all those maps work by modifying and replacing the assembly in the global assembly cache (GAC).
85
BizTalk Mapping Patterns and Best Practices
Level of effort: They are reusable. Because the .dll containing the transformation rule logics is deployed into the
Global Assembly Cache (GAC), you can reference them in your project you can reference and use this functionality
in your Scripting Functoids as often you want and again considerably simplifying the development task at hand.
Development: You can have several operations inside a single .dll and you can easily implement version control
and have different versions running side-by-side.
Testability: Because they are standard Class Libraries you can easily test them anywhere, for example within a C#
Console Application, so you know it works before its anywhere near the map.
Overview: Because they are encapsulated inside Scripting Functoids, is more difficult to read visually on the map
grid compared with built-in Functoids or custom Functoids.
Compiler limitations: By register the assembly in the GAC will make your function available to BizTalk, but the
function will not be available to the map until you add the .dll as a reference to your mapping project. So you need
to reference your assembly in every single project that you want to use.
Development: it requires experience with .NET Programming and since there may be multiple instances of a map
running at the same time, you have to ensure that the code used in an assembly called from a Scripting Functoid
must be thread safe.
The biggest differences between this two approach and that may make you decide between one and the other are:
86
BizTalk Mapping Patterns and Best Practices
o External Assembly: Because they are encapsulated inside Scripting Functoids, is more difficult to read
visually on the map grid compared with built-in Functoids or custom Functoids.
Note
Often a good strategy is to have a pre-defined helper class which sits alongside each map. Then rather than have a
map call loads of different classes it only calls this one and then inside the class you can call on to other assemblies.
This makes things a bit easier if you want to mock out dependencies and reuse some kind of complex coding model
underneath. This can be consider as a standard façade pattern which makes it easier to maintain the map.
Resources
All source code is available in the Microsoft Code gallery here: BizTalk Mapper: Built-in Functoids,
Scripting Functoid and Custom Functoids (http://code.msdn.microsoft.com/BizTalk-Mapper-Built-in-
7d29f124)
We can agree that using custom-XSLT we have performance benefits when compared to the BizTalk Mapper and the
code automatically generated by the compiler because it can put a lot of junky XSLT code in some circumstances or
scenarios. We can also agree that custom XSLT is the best option when the mapping logic is very complex, is the best
and maybe the only option to certain functionalities like grouping, the best when we use cycles and conditions and so
on.
But I cannot agree that using only custom XSLT for the entire mapping is better or less complex to maintain, and
sometimes it’s quite the opposite. In this approach you need to have really strong expertise to read, understand and
maintain the map and even then it can be a challenge: you cannot create a map in 5 minutes, even if we are talking
about relatively simple maps, creating all operations using custom XSLT are more time-consuming in comparison with
the use of a graphical user interface as BizTalk Mapper and if we want to have more performance and reliability in
your XSLT development we have to rely on external tools or external XSLT editors. Have all your developers’ access
and licenses for these tools? Or will have to use the most common of all: notepad?
All of these details should be analyzed and taken in consideration when we make this kind of decision.
Another detail that we often forget is that the projects are not ours, the client is the owner and we need also to think
about the best approach for the client. The client is not always willing to hire us or we may be we are unavailable on
the dates and we need to rely in another team member to do the job but not always those people have the same
expertise that we have. For these and other reasons we always have to take in consideration:
Performance: What’s the best approach to have performance in maps? Is my message so big that I really need to
worry about performance?
87
BizTalk Mapping Patterns and Best Practices
Maintainability: Can I easily maintain this map? It is easy to read and understand? What the estimated effort for
debug, finding and fix problems?
Complexity/Level of effort: What the expertise levels required to create and maintain this map approach? What
time I expect to develop?
Everybody knows that XSLT automatically generated code cannot perform as well as the personal Custom-XSLT code,
however in most scenarios you wouldn’t really notice too much difference between one and the other. And one of the
improvements introduced in BizTalk Server 2013 is the use of the enhanced XslCompiledTransform API, instead of
using the XslTransform API that is used in older BizTalk versions. When BizTalk Server 2004 was built, the XslTransform
was the only class provided by the Microsoft .NET Framework 1.1 to apply an XSLT to an inbound XML document.
When the Microsoft .NET Framework version 2.0 was released, this API was declared obsolete and thus deprecated.
With this change BizTalk Server would provide significant improvements in mapping engine performance for complex
maps: XslCompiledTransform, except in the first call, is about 40 times faster. (See some statics here:
http://blogs.msdn.com/b/antosha/archive/2006/07/16/xslcompiledtransform-slower-than-xsltransform.aspx). The
caveat is that because the XSLT is compiled to MSIL, the first time the transform is run there is a performance hit, but
subsequent executions are much faster. To avoid paying the extra cost of initial compilation every time a map is
executed. The XSLCompiledTransform class provides performance enhancements, including:
Once the Load method completes successfully, the Transform method can be called simultaneously from multiple
threads.
The new XSLT processor compiles the XSLT style sheet to a common intermediate format. Once the style sheet is
compiled, it can be cached and reused.
Even with this improvement using custom-XSLT will have much better performance because it’s clean code without
junky XSLT code produce by the compiler, however I only recommend do the all map problem with only custom-XSLT
file if you are dealing with huge message and High Performance is our or one of the primary requirements or if you
already have a custom XSLT file provided by another team, or from another system that you can re-use it in your
map, in this case don’t try to reinvent the wheel. For me these are the exceptions, otherwise you should use the BizTalk
Mapper and have a mix of Custom-XSLT and Functoids, why?
Maintainability and Readability: I don’t agree that very large transformations can be difficult to read and maintain
in BizTalk Mapper because we can also use a custom XSLT to solve and simplify more elaborate and complex rules,
and again in this case we have the best of both worlds. And they can be really easy to read and understand if you
apply some of the best practices in organization and documentation inside maps. From the perspective of a strong
developer, they can say that using custom XSLT files are easy to maintainability, and I accept that, but are they
more easily to maintain from a non-developer expert? Because in some situations even a non-developer can
understand and make small changes to a BizTalk mapper.
Level of effort:
o For new BizTalk developer to troubleshoot and/or change an existing map it will more easy to do using
BizTalk Mapper rather than troubleshoot and/or change and entire custom-XSLT file without visual
representation.
o Also when working with developers from other teams of business users the visual aspect can make it easy
to work with them to develop the mappings
Overview. If a new BizTalk developer opens up a map and see only a blank page without any Functoid, he will
probably think that someone forgot to check in the latest version in the source safe or simply forgot to implement
88
BizTalk Mapping Patterns and Best Practices
this map. And after some hours he will understand that there is defined in properties of the map an external file
with all your transformation rules. Really annoying.
Even if you need High Performance and you implement all your transformation rules with custom XSLT by setting the
following property in the map:
Create an empty BizTalk map in your project and set the source and destination schemas.
In the Grid view, click the mapper grid.
In the Properties window, select Custom XSLT Path and click the ellipsis (…) button.
In the Select Custom XSLT File dialog box, navigate to the XSLT file and click the Open button.
Again notice that XSLT 2.0 is not supported so XSLT 1.0 is required. And also that Custom extension XML file is required
if you are using external .NET assemblies.
An alternative approach for not using an external XSLT file is to wrap all your transformation rules into a Scripting
Functoid inside the BizTalk Mapper, at least with this approach new BizTalk developer or business users will
understand and see that there is something there.
Development: XSLT file can be developed separately and hosted in a BizTalk map.
Level of effort: Not quite as intuitive, Functoids are more easy to read visually on the map grid and therefore
Requires “geeky” coding skills
Overview: You loss of visual map representation.
Some people also mention that using External Custom XSLT file can also improve:
Performance and Compiler limitations: Direct XSLT is more powerful, fewer limitations than the BizTalk Mapper
and will definite will improved performance in complex transformation rules.
89
BizTalk Mapping Patterns and Best Practices
I can agree and disagree with this statement because I know that Custom Inline is difficult to edit because we don’t
have a decent editor inside the Scripting Functoids, but you can also have and use the full XSLT power using custom
inline XSLT.
However if you are using an external XSLT file at least you should follow some of these best practices:
Add XSLT files to the solution: you should always add the External XSLT files to your solution, so that they can be
easily find and can be added to the source control. For example, create a folder on your solution, let’s call it
“XSLTResources” and add you’re your XSLT files there or they are side by side in the same directory that maps.
Give it a proper name: don’t call it “ExternalXSLT” or “XSLTCode”, give it a proper name that could identify the
map. For example: “<name of the map>-XSLTFile.xsl” or the exact name of the map.
Add standard XML comments: you should add standard XML comments: “<!-- Comment -->”, every time you
think that it is important to explain little parts of the process. It is good programming practice to add brief comment
describing to your code, this is for your own benefit and the benefit of anyone else who examines the code.
Rename the page grid: if you are using an external XSLT file, at least rename the default grid page (Page 1) to a
name that draws attention to this fact, for example: “ThisMapUseAnExternalXSLTFile”. At least this way new BizTalk
developer can easily read and understand that this maps uses an external XSLT file.
90
BizTalk Mapping Patterns and Best Practices
In Solution Explorer, right-click the map whose complier links you want to view, and then click Test Map.
In the Visual Studio Error List window, scroll to the end and double-click the line that says Double-click here to
show/Hide compiler links.
To change the display state of compiler links from shown to hidden, or from hidden to shown, just double-click that
line again.
Becoming familiar with XSLT is almost a prerequisite to becoming a strong BizTalk mapping developer, not only
because there are many transformation rules that will be very difficult or impossible to implement without using
custom XSLT but also because in many circumstances we don’t obtained the intended final result and you will need
the ability to read the code generated automatically by the map complier, so It is often useful inspecting the XSLT
generated by the compiler provides insight into how the map compiler works but also it will provides another
debugging option. Some of the benefits of inspecting XSLT include:
If you are using looping or custom Functoids, you will better understand how the looping is performed and how
the custom Functoid is invoked.
If you have a complicated map, reviewing the XSLT will enable you to see how the map is translated into a transform
and may give you an insight on how to better structure, replace, or streamline one or more parts.
If you are using custom scripts or other artifacts, reviewing the XSLT will enable you to see how the scripts, artifacts
and other parts of the map interact.
If you experience performance issues, employ this techniques will help you understand what is going on and try
this way to optimize the transformation rules.
Right-click your BizTalk Mapper file in the Solution Explorer, and select Validate Map option
Scroll the Output window to find the URL for the XSL file. Press CTRL and click the URL to view the file
Note
Any changes made to the XSL file will only help you diagnosing the problem and test the solution, they will not be
reflected in the map and will be overwritten on the next build.
91
BizTalk Mapping Patterns and Best Practices
Hidden links can sometimes cause your map to behave in unexpected ways.
If this occurs, always check out the compiler-generated links to make sure that he (the compiler) hasn´t misinterpreted
your intentions. To see them:
Go to Solution Explorer, right-click over the map and select “Validate Map” option
Normally the Error/Task List and Output windows will pop up underneath of the Mapper Grid view, if this doesn't
happen, then go to the Main menu and select “View → Error List” option.
Select the “Error List” tab for open the Error Window and then you need to select the “Message” tab.
92
BizTalk Mapping Patterns and Best Practices
You will see the line “Double-click here to show/hide compiler links”. Double-click in the line and the hidden links
generated by the compiler will appear in the map represented in orange dashed lines.
Other Example:
Compiler-Generated Variables
When you inspect the XSLT generated by the compile you will find probably a lot of unexpected variables. The compiler
creates and uses internal variables for its own use because is the easiest way of referring to the output of interim
operations on the data. If exam with attention this often occurs to contain the output of Functoids or transformation
rules by C# scripts. Any time a logical operation produces output that must be consumed by another operation or
placed into the target model; the compiler creates an internal variable in which the value can be stored temporarily.
BizTalk uses compiler-generated variables liberally, but untangling them is less confusing than untangling the code
without them.
93
BizTalk Mapping Patterns and Best Practices
Compiler-Generated Scripts
C# scripts is the other thing that the compiler will generated for you. Even if you don´t use scripting Functoids with C#
code or any code and only perform transformation rules with built-in Functoids, when you inspect the XSLT generated
by the compile you will probably see a lot of calls to C# scripts in this XSLT document.
These scripts represents a C# function that was created as the result of placing a built-in or custom Functoid on the
map grid, why? Because for some Functoids the mapper compiler translate them to C# code.
These scripts, along with any custom scripts that you add using scripting Functoids, are found in the CDATA section at
the end of the XSLT document.
94
BizTalk Mapping Patterns and Best Practices
95
BizTalk Mapping Patterns and Best Practices
A pattern, apart from the term's use to mean "Template", is a regular and intelligible form or sequence discernible in
the way in which something happens or is done, they can be described as software solutions that solve a recurring
problem within a given context. They are a discernible regularity in the world or a design made by man that recur in
predictable ways that you can observe everywhere: abstract patterns in science, mathematics or even in languages.
“Patterns should be prescriptive, meaning that they should tell you what to do. They don’t just describe a problem, and
they don’t just describe how to solve it—they tell you what to do to solve it.” - Enterprise Integration Patterns:
Designing, Building, and Deploying Messaging Solutions book.
In the context of Enterprise Integration Patterns you can find: Messaging patterns (construction, routing or
transformations), Orchestration patterns, Time Patterns, BPM or SOA Patterns and so on. The use of patterns has
many advantages:
Patterns encapsulate a design expert's time and expertise to solve a software problem.
They promote software reuse and therefore you can have potentially lowers developing costs and save time by
eliminating redesign
They can offer a reliable and code design guidelines that you can share within your organization or team.
Applications that need to be integrated by a messaging system rarely agree on a common data format. For example,
the System B may have a different date format, different semantics representation Address or Client structure (with
more or less information) or just simply different element names than System B. This means that most of the times
we do not have the liberty of modifying the applications to work more easily with other systems. Rather, the
integration solution has to accommodate and resolve the differences between the varying systems.
In this chapter I will speak about some of the BizTalk Mapper Patterns (or Message Transformation Patterns) that we
find in real scenarios:
96
BizTalk Mapping Patterns and Best Practices
AGGREGATOR PATTERN
How do we combine the results of individual, but related
messages, so that they can be processed as a whole to generate
the target message?
SPLITTER PATTERN
How can we process an incoming message into a series of
outgoing messages so that they can be sent to multiple recipient
and processed in different ways?
GROUPING PATTERN
How do we communicate with another system if the target
message requires that the body of the message must be delivered
grouped in a certain way?
SORTING PATTERN
How do we communicate with another system if the target
message requires that the body of the message must be delivered
in a certain order?
CONDITIONAL PATTERN
How do we communicate with another system if the target
message requires that the data items available in message
originator can be passed according on a set of conditions?
LOOPING PATTERN
How do we communicate with another system if the target and/or
originator message have a complex and recursive structures? How
can we apply a set of common procedures to be apply a many
times?
97
BizTalk Mapping Patterns and Best Practices
And I will provide you with common mapper problems and solutions, specifying best practices and some of the best
ways to address some of your needs within the context of message transformation and also to enhance your skills
when using the BizTalk Server Mapper.
The aim of this chapter is not to provide you with some copy-paste code samples or some premade components that
you can use, but rather nuggets of advice that describe solutions to frequently recurring problems. Each pattern
addressed will pose a specific design problem, we will discuss the considerations surrounding the problem, and we
will try to presents an elegant solution that will balance according to several distinctive factors like performance and
productivity. In some cases, the solution is not the first approach that comes to mind, but one that evolved through
the process of developing and the experience by repeatedly implement transformation and learning from mistakes
made.
Note
All the recipes discussed in this chapter will be available for you to download at the end of each pattern in the
resource section.
This is one of the most common pattern used in the transform data from one format to another.
98
BizTalk Mapping Patterns and Best Practices
In this scenarios we just move the data to a different semantic representation without doing any king of data
manipulation or transformation.
BizTalk Mapper provides you we three easy ways to solve this scenarios:
You can manually create single links by dragging and dropping the source element to the destination element, if
the destination schema don’t have a similar structures or the same names.
However, if the destination schema have some type of generic schema (or canonical schema) that enables us to extend
the XML document with elements not specified by the schema, we can accomplish this by using the <any> Element,
then BizTalk Mapper allows you to copy the element in the input instance message corresponding to the source
99
BizTalk Mapping Patterns and Best Practices
schema node connected by using the Mass Copy Functoid. This Functoid also copies any and all of its substructure,
and re-creates it in the output instance message at the linked node in the destination schema.
Drag-and-drop the root name of the source schema, in this case “PurchaseOrder” to the root name of the
destination schema, which will be in this case “PO”, and release the direct button of the mouse.
A windows assistance will pop up were you can select create record-to-record links automatically in the following
ways:
o Direct Link: Using this technique, the BizTalk Mapper links the record from source schema to the selected
record in the destination schema. This will not copy any kind of hierarchy structure from the source to the
destination, it will only link the record or node.
o Link by Structure: Using this technique, the BizTalk Mapper attempts to match the Record and Field nodes
within the Record nodes being linked according to the structures of those Record nodes, regardless of
names of the corresponding nodes within those structures.
o Link by Name: Using this technique, the BizTalk Mapper attempts to match the Record and Field nodes
within the Record nodes being linked according to the names of the corresponding nodes, regardless of
their structure, within the Record nodes being linked.
o Mass Copy: The Mass Copy Functoid enables your maps to use schemas that include any and anyAttribute
elements. For information about the Functoids available in BizTalk Mapper.
100
BizTalk Mapping Patterns and Best Practices
If we take the sample available here: Automatically Link The Record Elements By Structure, Name or Using Mass
Copy (http://code.msdn.microsoft.com/Automatically-Link-The-bd268a64), this will provide with 3 small samples for
you to understand the differences of the last 3 options (Link by Structure, Link By Name, Mass Copy).
The scenario is a standard classic Purchase Order (in which we can see the structure of the message in the image
above) and we will have 3 different output schemas from 3 different systems.
The System A have a similar schema of our system, with the same structure and the same names, but they are
presented in a different order;
o Because the destination schema have the same names of the source schema, the best approach in this
scenario is to use the Link By Name option
The System B have also a similar schema of our system, we as the same order and the same schema structure,
however the elements have different names;
o Because the destination schema have the structure of the source schema, the best approach in this scenario
is to use the Link By Structure option
The System C have a canonical schema (or generic schema) that will accept any structure.
o Because the destination schema will accept any kind of structure, the best approach in this scenario is to
use the Mass Copy option
101
BizTalk Mapping Patterns and Best Practices
Of course this technique as some limitations, and will only work in some scenarios, however even if the BizTalk Mapper
cannot identify all the elements, much of the work can be done through this operation and we subsequently added or
corrected the failures manually.
102
BizTalk Mapping Patterns and Best Practices
Again this technique have the same limitations of the previous, it will only work in some scenarios but again he have
the ability of added or corrected the failures manually.
The Mass Copy Functoid allows source records and containing elements and attributes to be copied and mapped
across to the destination schema. It creates a wildcard (/*) XSLT template match to recursively copy elements.
<xsl:template match="/s0:PurchaseOrder">
<ns0:CanonicalPurchaseOrder>
<xsl:copy-of select="./@*" />
<xsl:copy-of select="./*" />
</ns0:CanonicalPurchaseOrder>
</xsl:template>
May provide a performance benefit, as each source and destination elements does not require a 1:1 detailed
mapping on all subsequent schema nodes, requiring fewer XSLT code instructions to be interpreted and executed
at runtime. Very useful when XML structures in source and destination schemas are compatible (identical).
Allows large structure to be mapped quickly in design time
Very useful when the destination is defined as an <xs:any> type, Mass Copy Functoid can be performed only with
the node level not with the fields level. So the node containing the <ANY> field has to be mapped.
103
BizTalk Mapping Patterns and Best Practices
Mass Copy Functoid will “blindly” copy all child elements specified to the destination schema and it will not copy
elements out of order or check for required values in the destination schema.
Using the Mass Copy Functoid is that it will move all the elements and values from the source schema to the
destination schema but it also will include the targetNamespace of source schema in the destination schema and
this behavior can be a problem in some scenarios.
There is no easy way to accomplished this without the need to use custom XSLT and you will need to customize the
syntax to your scenario.
In this sample if we need to map everything without namespaces we need to “replace” the Mass Copy Functoid for a
Scripting Functoid:
Drag-and-drop the Scripting Functoid from the Toolbox to the map grid page and then:
o And Link the Scripting Functoid to the destination root name “CanonicalPurchaseOrder” to set the output
parameter from the Scripting Functoid;
o This Functoid will not have any input parameters;
Double-click in the Scripting Functoid to show the Properties window, then:
o Select the “Script Functoid Configure” tab, and then choose “Inline XSLT” as your selected script type
o In the “Inline script” text box enter the following XSLT code without the comments (they are only for
explaining the operation of the script):
<!-- The Scripting Functoid will not add the root name, so we need to manually add it -->
<CanonicalPurchaseOrder>
<!-- Get all the element inside PurchaseOrder -->
<xsl:for-each select="/s0:PurchaseOrder/*">
<!-- Because we need to travel all the elements inside the LineItems we need to treat this
different so we will skip this for now -->
<xsl:if test="local-name()!='LineItems'">
<xsl:element name="{local-name(.)}">
<xsl:value-of select="." />
</xsl:element>
</xsl:if>
</xsl:for-each>
<xsl:choose>
<!-- check if there is LineItems to map otherwise we don’t do anything -->
<xsl:when test="count(/s0:PurchaseOrder/LineItems) > 0">
<LineItems>
<!-- Cycle to travel all the element inside the LineItems -->
<xsl:for-each select="/s0:PurchaseOrder/LineItems/*">
<Items>
<!-- Because the LineItems only contain one record we will add this manually but
we need an additional cycle this time to travel all the elements inside the record Item -->
<xsl:for-each select="./*">
<xsl:element name="{local-name(.)}">
<xsl:value-of select="." />
</xsl:element>
</xsl:for-each>
</Items>
</xsl:for-each>
</LineItems>
104
BizTalk Mapping Patterns and Best Practices
</xsl:when>
</xsl:choose>
</CanonicalPurchaseOrder>
Resources
All source code is available in the Microsoft Code gallery here: Automatically Link the Record Elements
by Structure, Name or Using Mass Copy (http://code.msdn.microsoft.com/Automatically-Link-The-
bd268a64)
A different semantics representation of entities (Address, Client entities and so on). For example, the billing system
may be more interested in the customer's tax payer ID numbers while the customer-relationship management
(CRM) system will be more interested in the client data information like phone numbers, contact or addresses.
In addition to changing the structure of a message we often need to change the content of individual values.
o For example, it is common for date and time formats to differ between systems or applications: A System
A includes a date in the format “yyyy-MM-dd HH:mm” (2013-12-24 13:48)), but the System B expects the
same date value to be represented in the format “dd-MM-YYYY” (24-12-2013).
o Or extract and separate the existing content of a string element into one or several element in the target
message: A System A includes a string date in the format “yyyy-MM-dd”, but the System B expects the
same information to be represented in 3 different elements: Year, Month and Day.
Or even the entire schema structure
That will may require more fundamental changes like restructure part of the original data. This pattern describes a
component that modifies the contents of a message like: combining information from several elements in your original
message or apply different data manipulation in some of the elements, translating it to a different format.
So the main difference between this patterns and the previous one, is that, besides moving the data to a different
semantic representation, here we have to apply basic or advanced data manipulation or transformation like:
Concatenation of values;
Conditional selection;
Looping operations;
Math operations;
105
BizTalk Mapping Patterns and Best Practices
And so on.
One of the simplest types of data manipulation is to calculate a new value, using a C# function or Functoid, based on
direct inputs of existing elements in your source message, and most likely, the calculated value will be assigned to a
new element in your target message.
Within the BizTalk Mapper, you can operate on data values using a variety of built-in functions like: Advanced
Functoids (for calling out to custom code in a number of forms, dealing with looping records and so on), Conversion
Functoids, Cumulative Functoids, Database Functoids, Date and Time Functoids, Logical Functoids, Mathematical
Functoids, Scientific Functoids and String Functoids. (For more information see LINKS AND FUNCTOIDS)
A very good example of this pattern was explained earlier on the TRANSFORMATIONS - BASIC MAPS FUNCTIONALITIES
(DOCUMENT MAPPING) and HOW MAPS WORKS chapters (the source code can also be founded there).
The aim of this book is not to explain all the Functoids available and how they work, and in the previous patterns we
will intensively use several Functoids and explain several ways to accomplish data manipulation so we will not address
any recipe here. I personally recommend you to check the Pluralsight course created by Dan Toomey: “Using Functoids
in the BizTalk 2013 Mapper” (http://pluralsight.com/training/Courses/TableOfContents/using-Functoids-biztalk-2013-
mapper). As I stated earlier, this course presents a deep-dive exploration of the BizTalk Mapper toolbox, especially the
powerful built-in Functoids that enable complex message transformations via a drag 'n' drop into the design grid.
Resources
Reference to this pattern:
All source code is available in the Microsoft Code gallery here: BizTalk Server – Basics principles of Maps
(http://code.msdn.microsoft.com/Funcionalidades-bsicas-dos-280cebea)
106
BizTalk Mapping Patterns and Best Practices
The Content Enricher Pattern tells us how we can deal with situations where our message does not have all the
required data items of the destination system to appropriately process the message. In most common scenarios it will
access an external data source to enhance the message with the missing information. An example of message
enrichment is to retrieve data from a database and add the data to a given location in a message where a Database
Lookup can be used to establish the details of the field in any given instance.
107
BizTalk Mapping Patterns and Best Practices
The best use of constant mapping depends on the situation and requirements you are developing against. We should
carefully examine whether:
How often might the values change? Is there is a slight possibility for this value change?
Are we dealing with sensitive information?
Who will want to change the values, a business user or a BizTalk Administrator?
For example the tax number is impossible to change, therefore, even for performance reasons, we can apply constant
values inside the maps. However if there is a slight possibility that values will change, you should think about putting
these configurable static values outside the map for better maintenance. Other good reason to put static values
configurable in some place outside the map is if you constants are set through deterministic logic, complex or
embedded business rules.
There are a couple of options a developer can have when comes to using constant values inside the maps. These
options can be divided into two categories:
In this demo we will have a simple message containing only two element and we will need to enrich the message with
several information that are not provide by the source system but are required by the destination system.
108
BizTalk Mapping Patterns and Best Practices
Development: doesn’t requires any experience and very easy to implement. We are basically using standard
functionalities inside the schemas to set default values.
Level of effort: by being easier to implement you will reduce the development time in the creation stage of these
maps.
Overview: because there isn’t any visual information on the map grid that indicates where these values are defined
there will be difficult to read this transformation rules.
Readability and Maintainability: For new and even for expert developers, or even when working with developers
from other teams, this approach is very hard to read (no visually information on the map grid) and therefore will
be more difficult to maintain this maps.
Level of effort: I know it is a contradiction but by being more difficult to read and maintain you will increase the
development time when we will need to make any change to these maps.
109
BizTalk Mapping Patterns and Best Practices
Limit of operations scope: By using this approach we also cannot set default values to this elements base in some
conditions.
Note
Because of the limitations described above, especially the lack of visibility in the rule when we are reading the map
in BizTalk Mapper editor, I personally don’t recommend use this approach. Instead I will definitely recommend you
to use Functoids to apply this rule.
Using Functoids
The other option, and this approach is what we normally found, to perform this operation is using an existent Functoid
to set constant value to fields and elements.
In this sample we will explain 3 forms of accomplish this and for that we need to:
o Select the “Functoid Inputs” tab and press the plus (+) button to add a constant value as an input in this
Functoid
Drag-and-drop from the second Scripting Functoid to the element “ConstValueUsingScriptingFunctoid2” in the
destination schema
110
BizTalk Mapping Patterns and Best Practices
o Make double-click in the Scripting Functoid and select the “Script Functoid Configuration” tab;
o Go to the “Select script type” drop-down box, and select “Inline XSLT” option. The “Inline script” box will
display a sample script;
o Inside “Inline script” property box place the following script:
<ConstValueUsingScriptingFunctoid2>
Set static constant using custom XSLT
</ConstValueUsingScriptingFunctoid2>
Drag-and-drop from the String Concatenate Functoid to the element “ConstValueUsingStringFunctoids” in the
destination schema
o Make double-click in the String Concatenate Functoid and on the “Functoid Inputs” tab and press the plus
(+) button to add a constant value as an input in this Functoid
Development: doesn’t requires any experience and very easy to implement. We are basically using standard
functionalities inside the schemas to set default values.
Level of effort: by being easier to implement you will reduce the development time in the creation stage of these
maps.
Overview: compare to the previous one (Using Schema Properties) it’s easier to read because we have a visual
information on the map grid that indicates that are some transformation rules applied.
Readability and Maintainability: Although there is a graphical representation, there are no easy way to read and
we need to go inside the Functoid to see or understand what really is happening, especially on the Scripting
Functoid approach.
111
BizTalk Mapping Patterns and Best Practices
o The String Concatenate Functoid approach is very common to be used so expert developers will easy read
that is a constant value that is being defined. The same can’t be true if we are talking about new developers.
o The Scripting Functoid approach with Inline C#” can also bring us other problem: when several Scripting
Functoids have the same method signature, BizTalk selects the first implementation and disregards the
others what can lead to unexpected results.
This Functoid allows you to set constant values (strings) inside de maps and will need one mandatory input parameters:
The output of the Functoid is the string set in the output, Example: “P0011”
Copy the Functoid DLL file to the "%BTS%\Developer Tools\Mapping Extensions" folder, where %BTS% is the
installation folder of BizTalk Server.
Open your BizTalk Project in Visual Studio.NET 2012 and open your map.
Go to "Tools” menu and select the “Choose Toolbox Items" option.
On the “Choose Toolbox Items” window, select "BizTalk Mapper Functoids" tab and check the Functoids that you
want to be available in the toolbox.
Open the Toolbox window and drag the String Constant Functoid to the map grid and then Drag-and-drop a link
from the String Constant Functoid to the element “ConstValueUsingConstantFunctoid” in the destination schema
112
BizTalk Mapping Patterns and Best Practices
o Make double-click in the String Constant Functoid and define a value that you want to be passed to the
element in the destination schema.
Readability: In my opinion, by using this Functoid now there an easy way, for beginners and expert developers, to
read without the need to go inside the Functoid.
In general, the goal is to avoid hard coding any values in source code that could reasonably be expected to change
during the lifetime of the application. Furthermore, those values should be stored in such a way that they can be
accessed and changed without developer involvement. To avoid this behavior, there are a couple of options a
developer can have when comes to using application configurable values. These options can be divided into three
categories:
However, with the exception of the Custom database, there are no default Functoid available out-of-the-box with
BizTalk Server that you can use inside the BizTalk Mapper to archive this goal and we need to create custom Inline C#
code or invoke an external assembly. The problem with this to approach is:
If we are using custom Inline C# code, we will need to constantly add the code to our Scripting Functoid, with can
be annoying, will cost developer time;
If we are using an external assembly, we will be stuck with this DLL dependence in every project and again we
always need to properly configure our Scripting Functoid with will also cost developer time;
And both this approaches will be hard to read and difficult to maintain because we need to go inside the Functoid
to see or understand what really is happening.
Fortunately there are available a suit of custom Functoids in the BizTalk Mapper Extensions UtilityPack
(http://btsmapextutilitypack.codeplex.com/) that can read configuration parameter values from different locations
and that you can use inside BizTalk mapper. This suit of Functoids are available for every BizTalk Server version since
2006.
The main advantage in using this suit of custom Functoids is that once they are installed in you environments you can
easy reuse in every map like an out-of-the-box Functoid.
They are probably the most common way to accomplished that and in many organizations they are the standard to
handle configuration information.
113
BizTalk Mapping Patterns and Best Practices
BTSNTSvc.exe.config file
The BizTalk engine uses an XML file called BTSNTSvc.exe.config, or BTSNTSvc64.exe.config, to determine certain
behaviors. This is probably one of the easiest places to store the configuration information from a developer’s and
deployment perspective and any changes placed in here will be apply to all host instance regardless of their names.
This file is always located in the same directory as the BTSNTSvc.exe file, which is usually “C:\Program Files
(x86)\Microsoft BizTalk Server 2013”. Your can find more information about BizTalk configuration file here:
http://msdn.microsoft.com/en-us/library/aa561903%28v=bts.70%29.aspx.
The BTSNTSvc Config Get Functoid, this Functoid is also available in the BizTalk Mapper Extensions UtilityPack
(http://btsmapextutilitypack.codeplex.com/), allows you to get configuration parameters from BTSNTsvc.exe.config.
This Functoid takes two mandatory input parameters:
String that represents the key name that you want to read from BTSNTsvc.exe.config
String that represents the section (can be an empty String, if there is no section specified, the Functoid reads from
the AppSettings) from the BTSNTsvc.exe.config that you want to read the key name.
The output of the Functoid is a string with the value of the configuration parameters from BTSNTsvc.exe.config
The following example shows the necessary configurations that we need to make inside the BTSNTsvc.exe.config file:
… <!-- Default content of this file are not shown here -->
114
BizTalk Mapping Patterns and Best Practices
In the other hand the external “MyConfigFile.config” will contain the following settings:
<SomeSettings>
<!-- Setting that we need to read -->
<add key="DefaultCity" value="Porto" />
</SomeSettings>
Development: from a developer’s perspective his is very straight forward approach and very easy to implement
and any changes placed in here will be apply to all host instance regardless of their names in the machine of the
configuration file.
Deployment: from a deployment perspective this can also be archive very easy, especially in small environments,
you just need to update the files.
Maintainability: From a maintenance perspective it is a challenger just from the fact of keeping files in sync,
BTSNTSvc.exe.config (for 32 bits host instances) and BTSNTSvc64.exe.config (for 64 bits host instances) and even
more challenger in environments with multiple BizTalk Servers machines (all of the files must be sync in each
machine). It will also be a hell if you need to troubleshoot for errors.
Availability: Another big problem is that for changes to take effect you will need to restart the host instances witch
will cause downtime.
Data Security: By default the data will not be encrypted;
Accessibility: The configuration values can only be changed by an administrator;
Environment Security: You need to be very careful when you are messing around with BizTalk configuration file
(please do not change this file without backing up) otherwise you can stop all our BizTalk environment.
Standard: In many organizations there are standards that describe how you typically handle configuration
information, and because to store configuration information in BTSNTsvc.exe.config is BizTalk related, it can be
difficult to change the companies’ standard configuration store (configuration files or databases).
The Custom Config Get Functoid, like the previous ones this Functoid is also available in the BizTalk Mapper Extensions
UtilityPack (http://btsmapextutilitypack.codeplex.com/), allows you to get configuration parameters from a custom
configuration file. This Functoid takes two mandatory input parameters:
String that represents the key (variable name) that you want to read from a custom configuration file
String that represents the path to the custom configuration file that you want to read the key.
The output of the Functoid is a string with the value of the configuration parameters from a custom configuration file.
115
BizTalk Mapping Patterns and Best Practices
The following example shows the basic structure of a custom configuration file that we use in this sample:
<configuration>
<appSettings>
<add key="Originator" value="The deployment process can become quite painful when we need to
install on different (E2E, Testing, Prod) and large environments because we need to specify the path
to the configuration file statically" />
</appSettings>
</configuration>
Development: from a developer’s perspective his is very straight forward approach and very easy to implement,
accessing a .config file can be done using simple .NET code and you can choose whether or not to use Enterprise
Library or custom code.
Availability: You can change the values were ever you want and the changes will be apply in runtime, you don’t
need to restart the host instances.
Standard: In many organizations there are standards that describe how you typically handle configuration
information and Configuration Files, Registry or Databases are typically the standard used by companies.
This approach has almost the same challenges as using the BizTalk configuration file:
Maintainability: From a maintenance perspective it is a challenger just from the fact of keeping files in sync in the
servers witch can be a challenger if you need to troubleshoot for errors. If the file is put in a central place accessible
by all the servers you can have security problems. However a custom configuration file can be easier to maintain
that the BTSNTSvc.exe.config file
Availability: This can also be a disadvantages because another back draw is I/O with reading from file. You might
need to implement some caching to avoid delays in reading from physical file.
Data Security: By default the data will not be encrypted;
116
BizTalk Mapping Patterns and Best Practices
Windows Registry
Another valid option to store the application configuration values is the Windows Registry. The Registry is a central
hierarchical database used by the Microsoft Windows operating systems to store information that is necessary to
configure the system for one or more users, applications and hardware devices, containing three basic elements:
Hives, keys and Values.
Hives: are the main branches that exist in the registry that contain keys. There are five main branches, each
containing a specific portion of the information stored in the Registry.
o HKEY_CLASSES_ROOT: This branch contains all of your file association mappings to support the drag-and-
drop feature, OLE information, Windows shortcuts, and core aspects of the Windows user interface.
o HKEY_CURRENT_USER: This branch links to the section of HKEY_USERS appropriate for the user currently
logged onto the PC and contains information such as logon names, desktop settings, and Start menu
settings.
o HKEY_LOCAL_MACHINE: This branch contains computer specific information about the type of hardware,
software, and other preferences on a given PC, this information is used for all users who log onto this
computer.
o HKEY_USERS: This branch contains individual preferences for each user of the computer, each user is
represented by a SID sub-key located under the main branch.
o HKEY_CURRENT_CONFIG: This branch links to the section of HKEY_LOCAL_MACHINE appropriate for the
current hardware configuration.
Keys: Each key can contain other keys (sometimes referred to as sub-keys), as well as Values. They are containers
of objects similar to folders. Keys must have a case insensitive name without backslashes.
Values: containing the actual information stored in the Registry. There are three types of values: String, Binary,
and DWORD, the use of these depends upon the context.
The Windows Registry Config Get Functoid, this Functoid is available in the BizTalk Mapper Extensions UtilityPack
(http://btsmapextutilitypack.codeplex.com/), allows you to get configuration parameters from Windows Registry. This
Functoid takes two mandatory input parameters:
String that represents the name or path of the key or sub-key to open.
String that represents the name of the value to retrieve from the registry. This string is not case-sensitive.
The output of the Functoid is a string with the value of the configuration parameters from the registry.
117
BizTalk Mapping Patterns and Best Practices
The following example shows the basic structure of a .reg file that we use in this sample to register the configuration
in the Windows Register:
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\BTSAppConfig]
"CompanyName"="From a maintenance perspective storing values in registry can be hard to maintain in
large environments because we need maintain multiple registries and its hard to back up individual
application settings"
Development: from a developer’s perspective storing values in registry is very straight forward approach and very
easy to implement. It has a key/value interface that does not require parsing. You can put arbitrary data into the
registry without escaping. It already has a GUI tool for inspection and tweaking (regedit).
Availability: You can change the values whenever you want and the changes will be apply in runtime, you don’t
need to restart the host instances. The registry store is managed by the kernel. If your application hangs or crashes,
changes to the registry are still committed.
Accessibility: Access to the registry is thread and multiple instance safe. Multiple threads and multiple processes
can simultaneously access the same registry value and updates are atomic.
Data Security: One of the main advantages is the ability to protect data using ACLs and the ease of programmatic
access.
Standard: In many organizations there are standards that describe how you typically handle configuration
information and Configuration Files, Registry or Databases are typically the standard used by companies.
118
BizTalk Mapping Patterns and Best Practices
Maintainability: From a maintenance perspective storing values in registry can be hard to maintain in large
environments because we need maintain multiple registries and it’s hard to back up individual application settings
Deployment: In a multiple machine BizTalk deployment this is far from ideal option as you have to maintain
multiple registries.
Availability: This can also be a disadvantages. When you begin to make changes and alter the structure of your
registry, you can easily make a mistake and create severe problems for your system. The Windows registry which
is increased in size due to accumulation of junk entries, fragmented and corrupted due to the traces left by
improperly uninstalled programs can lead to performance degradation of the computer system and in the worst
case scenario to systems crashes.
Data Security: By default the data will not be encrypted;
Accessibility: The configuration values can only be changed by an administrator;
However I will advise not to use this. You will see why bellow.
The System Environment Variable Get Functoid, also a Functoid that is available in the BizTalk Mapper Extensions
UtilityPack (http://btsmapextutilitypack.codeplex.com/), allows you to get configuration parameters from machine
System Environment Variable. The Functoid takes one mandatory input parameters:
String that represents the key that you want to read from System Environment Variable
The output of the Functoid is a string with the value of the configuration parameters from System Environment
Variable of the machine
119
BizTalk Mapping Patterns and Best Practices
You can access the environment variable from the Control Panel by open the System option (alternately, you can right-
click on My Computer and select Properties), select the “Advanced system settings” link and then In the System
Properties dialog, click “Environment Variables”.
The following picture will shows the environment variable that we use in this sample:
I will not speak about advantages of this approach because as I say earlier, I will advise you not to use this approach
because:
Availability: The major problem is that for changes to take effect you will need to restart the computer witch will
cause huge downtime in your environment.
Using Databases
So far registry and file options have been discussed. Not the best options when you want to consider a central store
for your application custom configuration data. A database would be a better option from an administrative viewpoint.
120
BizTalk Mapping Patterns and Best Practices
Using the Business Rule composer, you may define constants in vocabularies which could be deploy to the BRE and
stored in the shared rule store.
Start by running the “Business Rule Composer” from the “Start Screen”
In the Facts Explorer window, click the Vocabularies tab.
Right-click Vocabularies, click Add New Vocabulary, and then type the name for the vocabulary, for example:
“DemoAppConf”.
Right-click Version 1.0(not saved) in you vocabulary, and then click Add New Definition.
In the Vocabulary Definition Wizard, select “Constant values, Range of Values or a Set of Values” option and then
click “Next”.
Add a Definition name (for example: “MyDefinition”), a Definition description, set the type as Constant Value and
then click “Next”.
Define the type of the constant, the display name and the value and then click “Finish”.
Right-click Version 1.0(not saved), and then click Save.
Right-click Version 1.0, and then click Publish.
Note
The name and value of the configuration property “MyDefintion”, present in the picture above, will be used in our
next sample.
The Rule Engine Config Get Functoid, this Functoid is available in the BizTalk Mapper Extensions UtilityPack
(http://btsmapextutilitypack.codeplex.com/), allows you to obtain a definition value from a Vocabulary in the Business
Rules Engine. This Functoid takes two mandatory input parameters:
The output of the Functoid is a string with the value of the definition name from a specify vocabulary on the Business
Rule Engine
121
BizTalk Mapping Patterns and Best Practices
Availability: You can change the values whenever you want and the changes will be apply in runtime, you don’t
need to restart the host instances. Also you can prepare a new version without affecting the existent one.
Accessibility: By default, all BizTalk Hosts have the same level of access to rules engine artifacts. And the
configuration values can be changed by anyone with access to BRE (BizTalk Server restricts access to the Business
Rule Engine resources by using two SQL Server roles: The RE_Admin_Users SQL Server role is for users that need to
perform administrative tasks in the Business Rule Engine, such as deploying rules. Members of the RE_Admin_Users
SQL Server role include BizTalk administrators).
Maintainability: From a maintenance perspective is extremely simple and you would get the normal BizTalk fail
over/back up processes out-of-the-box for free.
Deployment: BizTalk will provide out-of-the-box tools (Business Rules Engine Deployment Wizard) where you easily
can import or export business rule policies or vocabularies for you to use in your development, staging, and
production environments.
Versioning: As the configuration is defined as constants they would be read only, however we can follow the BRE
deployment/versioning strategy for implement changes to our configurations.
Development: from a developer’s perspective storing values in BRE is a very straight forward approach and very
easy to implement and BizTalk Server will provide all the tools out-of-the-box to accomplish that. However BRE
sometimes are not very well understood by developers for many reasons, which can may become an obstacle in
the team.
Accessibility: This can also be a disadvantage. The configuration values can be access by anyone with access to BRE;
Data Security: By default the data will not be encrypted;
122
BizTalk Mapping Patterns and Best Practices
Standard: In many organizations there are standards that describe how you typically handle configuration
information, and because to store configuration information in BRE is BizTalk related, it can be difficult to change
the companies’ standard configuration store (configuration files or databases).
Microsoft has built a SSO Application Configuration snap in that provides a good user experience maintaining custom
configuration data.
The SSO Config Get Functoid, this is also a Functoid that is available in the BizTalk Mapper Extensions UtilityPack
(http://btsmapextutilitypack.codeplex.com/), allows you to get configuration parameters from SSO Database. This
Functoid takes two mandatory input parameters:
String that represents the name of the affiliate application to represent the configuration container to access
String that represents the property name to read from the.
The output of the Functoid is a string with the value of the configuration parameters from SSO
Unfortunately I cannot provide here a script code used to create or import the SSO Application because they are
encrypted. However the following picture will shows the configurations that we use in this sample:
123
BizTalk Mapping Patterns and Best Practices
Maintainability: From a maintenance perspective is extremely simple and you would get the normal BizTalk fail
over/back up processes out-of-the-box for free. And because it’s a central store, there is no need to distribute a
configuration file across multiple servers when a value changes, therefor you eliminate the risk of using different
configuration for different servers. The SSO Configuration Application MMC Snap-In tool will allow administrators
to import and export configuration applications.
Availability: You can change the values whenever you want and the changes will be apply in runtime, you don’t
need to restart the host instances.
Accessibility: It is a central store, so all the configuration values will be the exactly the same for all BizTalk Servers
within your group.
Data Security: One of the main advantages is that you get out-of-the-box encryption. The SSO is automatically
encrypted which makes it harder for someone to read it. It offers ability to store sensitive information.
Standard: In many organizations there are standards that describe how you typically handle configuration
information, and because to store configuration information in SSO is typically a BizTalk related, it can be difficult
to change the companies’ standard configuration store (configuration files or databases).
Deployment: From a deployment perspective you will need to use external tools (SSO Configuration Application
MMC Snap-In) to deploy your SSO Application from the command line to different environments.
Development: From a developer perspective you will need to use external tools (SSO Configuration Application
MMC Snap-In) to add and manage applications or add and manage key value pairs. Also if you want to use an
automated build process during development you will need to build some MsBuild or NANT tasks to manage
deployment of the configuration.
Custom Database
Another common place to store application configuration data, in many organizations there are standard, in on a
custom database because they are a well-known technology and language for both developers and administrators.
Basically the developer will create a custom database with a few simple tables to store the configuration data,
sometimes they implement a caching mechanism to reduce the number of round trips to the database, they will be
regular backup by procedures made by administrators and can easily be changed by SQL Scripts.
BizTalk Server will provide out-of-the-box a nice suite of Functoids to access database. The Database Functoids fall into
two categories.
The first category consists of the Database Lookup, Error Return, and Value Extractor Functoids, which are
designed for general purpose retrieval of database values using Microsoft ActiveX Data Objects (ADO) record sets.
The second category consists of the FormatMessage, Get Application ID, Get Application Value, Get Common ID,
Get Common Value, Remove Application ID, and Set Common ID Functoids, which correspond to the methods of
the CrossReferencing class of the Microsoft.BizTalk.CrossReferencing API.
In this sample we will use and explain the 2 basic Functoids to get configuration data form a custom database:
124
BizTalk Mapping Patterns and Best Practices
Database Lookup Functoid: to extract a row from a database table as a Microsoft ActiveX Data Objects (ADO)
record set. You can find more information about this Functoid here: http://msdn.microsoft.com/en-
us/library/aa547392.aspx.
Value Extractor Functoid: to extract the value from a specified column in a Microsoft ActiveX Data Objects (ADO)
record set, which is returned by the Database Lookup Functoid. You can find more information about this Functoid
here: http://msdn.microsoft.com/en-us/library/aa559864.aspx.
The following picture will show the configurations that we use in a custom SQL Server database for this sample:
125
BizTalk Mapping Patterns and Best Practices
Parameter 2: An ActiveX Data Objects .NET (ADO.NET) connection string for a compliant data
source in which to search. ODBC data sources (including DSN sources) are not supported. You can
reference an OLE DB Universal Data Link file to specify the connection string by using the File Name
parameter to specify the full path and file name of the UDL file that contains the connection string
information.
Note
Hard-coding the SQL connection strings might lead to maintenance overhead and serviceability issues. To avoid
these, you can externally configure data sources in the Database Lookup Functoid. You can get the SQL connection
string (parameter 2) from a scripting Functoid, which can then be linked to the Database Lookup Functoid.
o Make double-click in the Value Extractor Functoid and in the “Functoid Input” tab set the following
parameters:
Parameter 1: An ADO record set, which is the output of the Database Lookup Functoid. This record
set never contains more than one database row.
Note
To avoid errors that are only detected at run time, make sure that the first parameter to the Value Extractor
Functoid is the output of a Database Lookup Functoid and not the output of any other Functoid in the Database
category or custom Functoid that returns an ADO record set.
126
BizTalk Mapping Patterns and Best Practices
Parameter 2: The name of a column from which to extract a value for output.
Development: from a developer’s perspective storing values in custom database is very straight forward approach
and very easy to implement. They are a well-known technology and language even for beginner’s developers and
non-BizTalk developers.
Maintainability: From a maintenance perspective storing values in the database you don’t have to worry about
consistency of data across servers like you would with a configuration files. The database can be easily moved to
a new server.
Availability: You can change the values whenever you want and the changes will be apply in runtime, you don’t
need to restart the host instances.
Security: The table of configuration options can be secured using the same security model that the rest of your
application uses. No special handling needed.
Standard: In many organizations there are standards that describe how you typically handle configuration
information and Configuration Files, Registry or Databases are typically the standard used by companies.
Maintainability: This can also be a disadvantage. From a maintenance perspective, you will need to define a
maintenance plan and have your DBA manage this database, you will need to set backup and restore procedures.
Deployment: Although from a deployment perspective the deployment can also be archive very easy that is a false
sensation because the developer need to statically specify the connection string to use inside the Database Lookup
Functoid to extract information from the database and by doing that we need to change our code (the map) and
127
BizTalk Mapping Patterns and Best Practices
deploy again for a different environment or store this parameter in a different storage location (SSO, Registry or
others)
Availability: Custom databases are well known as a cause of bottlenecks in high volume scenarios as they are
often not correctly tuned and optimized. There will be additional custom development work to create and
optimize your database
Data Security: By default the data will not be encrypted;
Resources
Reference to this pattern:
All source code is available in the Microsoft Code gallery here: BizTalk Mapper Patterns: Working with
Constant Values inside maps (http://code.msdn.microsoft.com/BizTalk-Mapper-Patterns-ec6c6711)
Aggregator Pattern
Basically this could also be another example of the CONTENT ENRICHER PATTERN that we explained earlier but sometimes
when we exchange messages between different systems we will need to gather information from multiple external
sources, this is also known as Scatter-Gather Pattern (http://www.eaipatterns.com/BroadcastAggregate.html) that
you can find more details on the Enterprise Integration Patterns site, and once a complete set of messages has been
received, we need to processed them as a whole and combine or merge parts of information from each correlated
message in order to create the expected message by the target system.
So the main difference between this pattern and the previous one is that in the previous we're talking about mapping
one to one message and here we are dealing with multiple inbound messages that were collected from the original
request and need to be mapped and aggregated into a single outbound request. For example, we want to bill the client
order after all items have been pulled from the financial system or warehouse.
128
BizTalk Mapping Patterns and Best Practices
To simplify the demo we will emulate a call to an external source, so we will build statically message within the
orchestration using the message assign shape, however in real cases we would communicate with an external system
or database.
Well since BizTalk Server 2004 that you are able to map many documents into one or map one document into many.
In either case, your inputs will not equal your outputs. Well if it’s possible how can this be accomplished making use
of the BizTalk mapper?
This type of mapping/transformation is only allowed inside the Orchestration, you cannot use this maps in
Receiving Ports or Send Ports.
There isn´t a direct way to create this type of maps without the support of the orchestration designer. So you
cannot create this from Visual Studio as a normal map item, this type of map can only be created from “Transform
Shape” inside the orchestration when you are developing this orchestration in the Visual Studio.
In reality what the mapper does is creating sometime of multi-part message with different messages for the input, or
to the output or the both. This technique the mapper allows the mapper to create or merge multiple messages.
In this demo we will have to different messages gathered from your internal or external systems:
Users: With the User id and the First and Last Name of the users
And Address: With the User Id and the addresses information of the user (Address, Town and Post Code).
129
BizTalk Mapping Patterns and Best Practices
And we basically want to merge this information base on the User Id knowing that one user can have multiple
addresses.
In Solution Explorer, right-click the project name, select “Add”, and then click “New Item”.
In the “Add New Item” dialog box, in the “Categories” pane, click “BizTalk Project Items”, and then in the
“Templates” pane, click “BizTalk Orchestration”.
In the Name box at the bottom of the dialog box, supply a name for the orchestration, and then click “Add”.
Note
The new orchestration is created and displayed in Orchestration Designer, and a corresponding “.odx” file is created
and displayed in Solution Explorer. I will not describe all the steps here because this is not the aim, however I will
provide the key steps.
Create two One-Way logical ports with the binding type set to “Specify later” by:
o Right-click a “Port Surface” and then click “New Port”. Your can find more information about how to use
ports in Orchestrations here: http://msdn.microsoft.com/en-us/library/aa578722.aspx.
One for receiving messages: “InputPort”
And One for sending messages: “OutputPort”
In the Orchestration View window, create 3 messages by:
o Right-click “Messages” and then click “New Message”.
Set the message name as “msgUsers” and set the message type as “InputUsers”
Set the message name as “msgAddresses” and set the message type as “InputAddresses”
Set the message name as “msgResult” and set the message type as “OutputMessage”
130
BizTalk Mapping Patterns and Best Practices
Note
The Construct Message shape is used to construct a new instance of a message type within your orchestration. It
must contain either a Message Assignment shape or a Transform shape, and can contain any number of either, but
no other shapes.
In the “Properties” window, of the Construct Message shape, use the “Messages Constructed”
property to specify which messages this shape will construct. In this case the “msgAddresses”
Right-click the Message Assignment shape and click “Edit Expression” or, in the “Properties”
window, click the Ellipsis (...) button for the “Expression” property. And past the following code to
emulate a call to the external source:
varXML.LoadXml(@"<ns0:Addresses xmlns:ns0=""http://BizTalk_Server_GenerationFichiersReleve.Test2"">
<Address>
<UserID>125</UserID>
<AddressLine1>Praceta do Marao</AddressLine1>
<PostCode>4415-538</PostCode>
<Town>Crestuma</Town>
</Address>
<Address>
<UserID>125</UserID>
<AddressLine1>Rua Passos Manuel, 223 - 4 Andar</AddressLine1>
<PostCode>4000-385</PostCode>
<Town>Porto</Town>
</Address>
<Address>
<UserID>130</UserID>
<AddressLine1>Rua Passos Manuel, 223 - 4 Andar</AddressLine1>
<PostCode>4000-385</PostCode>
<Town>Porto</Town>
</Address>
</ns0:Addresses>");
msgAddresses = varXML;
o Transform Shape
In the “Properties” window, of the Construct Message shape, use the “Messages Constructed”
property to specify which messages this shape will construct. In this case the “msgResult”
Double-click the Transform Shape or right-click the Transform Shape and click "Configure
Transform Shape..."
131
BizTalk Mapping Patterns and Best Practices
Click in “Destination”, and then from the “Destination Transform” drop-down list, select
“msgResult” as the output of the transformation
132
BizTalk Mapping Patterns and Best Practices
Notice that the option “When I click OK, launch the BizTalk Mapper” is checked, Click “OK”
and this will create and open the map for you with two source schemas and one destination
schema.
For now just save the map and closes it, we'll deal with it later.
o Send Shape
In the “Properties” window, select from the “Message” property the message “msgResult” to be
sent
Drag the send connector from the Send Shape to the “OutputPort” logical port
133
BizTalk Mapping Patterns and Best Practices
After we created our process, we will discuss the possible solutions we could perform to reach the desired
transformation, i.e., joining the content of both messages based on User Id.
To solve this mapping problem using this approach, for each element in the destination schema we need to drag:
134
BizTalk Mapping Patterns and Best Practices
Drag a link from the “Address” record in the source schema to the Looping Functoid
And drag a link from the Looping Functoid to the record “Address” in the destination schema
o Drag from the Toolbox window one Equal Functoid and then:
Drag a link from the “UserId” element present in the “User” record in the source schema to the
Equal Functoid
Drag a link from the “UserId” element present in the “Address” record in the source schema to the
Equal Functoid
And drag a link from the Equal Functoid to the record “Address” in the destination schema
Note
In this transformation rule we are saying that the destination element “Address” will be created only if the two
“UserId” values linked to the Equal Functoid are equal.
o Drag a link from the “UserId” element present in the “Address” record in the source schema to the “UserId”
element present in the “Address” record in the destination schema
o Drag a link from the “AddressLine1” element in the source schema to the “AddressLine1” element in the
destination schema
o Drag a link from the “PostCode” element in the source schema to the “PostCode” element in the
destination schema
o Drag a link from the “Town” element in the source schema to the “Town” element in the destination
schema
If we run a quick test in your map by right-clicking the map name and select “Test Map” option:
<ns0:Informations xmlns:ns0="http://BizTalk_Server_GenerationFichiersReleve.Test3">
<Users>
<User>
<UserID>125</UserID>
<LastName>LastName_0</LastName>
<FirstName>FirstName_0</FirstName>
135
BizTalk Mapping Patterns and Best Practices
<Addresses>
<Address>
<UserID>125</UserID>
<AddressLine1>AddressLine1_0</AddressLine1>
<PostCode>PostCode_0</PostCode>
<Town>Town_0</Town>
</Address>
</Addresses>
</User>
</Users>
</ns0:Informations>
At first glance, everything seems to be right… but it is a false perception of reality. This happens because by default
the BizTalk Mapper engine will create a dummy message with one User and one Address and everything will work
well. However if we test with a “real” message with many users and many addresses, for example:
<ns0:Root xmlns:ns0="http://schemas.microsoft.com/BizTalk/2003/aggschema">
<InputMessagePart_0>
<ns1:Users xmlns:ns1="http://BizTalk_Server_GenerationFichiersReleve.test">
<User>
<UserID>125</UserID>
<LastName>Pereira</LastName>
<FirstName>Sandro</FirstName>
</User>
<User>
<UserID>130</UserID>
<LastName>Silva</LastName>
<FirstName>Miguel</FirstName>
</User>
</ns1:Users>
</InputMessagePart_0>
<InputMessagePart_1>
<ns2:Addresses xmlns:ns2="http://BizTalk_Server_GenerationFichiersReleve.Test2">
<Address>
<UserID>125</UserID>
<AddressLine1>Praceta do Marao</AddressLine1>
<PostCode>4415-538</PostCode>
<Town>Crestuma</Town>
</Address>
<Address>
<UserID>125</UserID>
<AddressLine1>Rua Passos Manuel, 223 - 4 Andar</AddressLine1>
<PostCode>4000-385</PostCode>
<Town>Porto</Town>
</Address>
<Address>
<UserID>130</UserID>
<AddressLine1>Rua Passos Manuel, 223 - 4 Andar</AddressLine1>
<PostCode>4000-385</PostCode>
<Town>Porto</Town>
</Address>
</ns2:Addresses>
</InputMessagePart_1>
</ns0:Root>
<ns0:Informations xmlns:ns0="http://BizTalk_Server_GenerationFichiersReleve.Test3">
<Users>
<User>
136
BizTalk Mapping Patterns and Best Practices
<UserID>125</UserID>
<LastName>Pereira</LastName>
<FirstName>Sandro</FirstName>
<Addresses>
<Address>
<UserID>125</UserID>
<AddressLine1>Praceta do Marao</AddressLine1>
<PostCode>4415-538</PostCode>
<Town>Crestuma</Town>
</Address>
<Address>
<UserID>125</UserID>
<AddressLine1>Rua Passos Manuel, 223 - 4 Andar</AddressLine1>
<PostCode>4000-385</PostCode>
<Town>Porto</Town>
</Address>
</Addresses>
</User>
<User>
<UserID>130</UserID>
<LastName>Silva</LastName>
<FirstName>Miguel</FirstName>
<Addresses>
<Address>
<UserID>125</UserID>
<AddressLine1>Praceta do Marao</AddressLine1>
<PostCode>4415-538</PostCode>
<Town>Crestuma</Town>
</Address>
<Address>
<UserID>125</UserID>
<AddressLine1>Rua Passos Manuel, 223 - 4 Andar</AddressLine1>
<PostCode>4000-385</PostCode>
<Town>Porto</Town>
</Address>
</Addresses>
</User>
</Users>
</ns0:Informations>
So why this happen? If we analyze the XSLT generated by the BizTalk mapping engine by:
<xsl:template match="/s2:Root">
<ns0:Informations>
<Users>
<xsl:for-each select="InputMessagePart_0/s0:Users/User">
<User>
<UserID>
<xsl:value-of select="UserID/text()" />
</UserID>
<LastName>
<xsl:value-of select="LastName/text()" />
</LastName>
<FirstName>
<xsl:value-of select="FirstName/text()" />
</FirstName>
<Addresses>
<xsl:for-each select="../../../InputMessagePart_1/s1:Addresses/Address">
137
BizTalk Mapping Patterns and Best Practices
<xsl:variable name="var:v1"
select="userCSharp:LogicalEq(string(../../../InputMessagePart_0/s0:Users/User/UserID/text()) ,
string(UserID/text()))" />
<xsl:if test="$var:v1">
<Address>
<UserID>
<xsl:value-of select="UserID/text()" />
</UserID>
<AddressLine1>
<xsl:value-of select="AddressLine1/text()" />
</AddressLine1>
<PostCode>
<xsl:value-of select="PostCode/text()" />
</PostCode>
<Town>
<xsl:value-of select="Town/text()" />
</Town>
</Address>
</xsl:if>
</xsl:for-each>
</Addresses>
</User>
</xsl:for-each>
</Users>
</ns0:Informations>
</xsl:template>
We’ll notice that inside the “Address” loop the equal condition is not what we expect to happen. Because the
“Address” loop is inside the “User” loop, we expected that in each iteration of the “User” record, to be send to the
Equal Functoid the correct “UserId” associated with this iteration, instead, and as we can check in XSLT, we are always
pick the first “UserId” present in the "User" record.
<xsl:variable name="var:v1"
select="userCSharp:LogicalEq(string(../../../InputMessagePart_0/s0:Users/User/UserID/text()) ,
string(UserID/text()))" />
138
BizTalk Mapping Patterns and Best Practices
This scripting Functoid is for create a C# function to create and to assign the correct value of the
“UserId” for each iteration of the “User” record.
Double click in the Scripting Functoid and specify the scripting type as “Inline C#”
In the Inline script put the following code:
int userId = 0;
o Drag a link from the “LastName” element in the source schema to the “LastName” element in the
destination schema
o Drag a link from the “FirstName” element in the source schema to the “FirstName” element in the
destination schema
139
BizTalk Mapping Patterns and Best Practices
o Drag a link from the “UserId” element present in the “Address” record in the source schema to the “UserId”
element present in the “Address” record in the destination schema
o Drag a link from the “AddressLine1” element in the source schema to the “AddressLine1” element in the
destination schema
o Drag a link from the “PostCode” element in the source schema to the “PostCode” element in the
destination schema
o Drag a link from the “Town” element in the source schema to the “Town” element in the destination
schema
If we test again our map with the same XML sample described earlier with multiple Users and Addresses, we will get
the correct result expected:
<ns0:Informations xmlns:ns0="http://BizTalk_Server_GenerationFichiersReleve.Test3">
<Users>
<User>
<UserID>125</UserID>
<LastName>Pereira</LastName>
<FirstName>Sandro</FirstName>
<Addresses>
<Address>
<UserID>125</UserID>
<AddressLine1>Praceta do Marao</AddressLine1>
<PostCode>4415-538</PostCode>
<Town>Crestuma</Town>
</Address>
<Address>
140
BizTalk Mapping Patterns and Best Practices
<UserID>125</UserID>
<AddressLine1>Rua Passos Manuel, 223 - 4 Andar</AddressLine1>
<PostCode>4000-385</PostCode>
<Town>Porto</Town>
</Address>
</Addresses>
</User>
<User>
<UserID>130</UserID>
<LastName>Silva</LastName>
<FirstName>Miguel</FirstName>
<Addresses>
<Address>
<UserID>130</UserID>
<AddressLine1>Rua Passos Manuel, 223 - 4 Andar</AddressLine1>
<PostCode>4000-385</PostCode>
<Town>Porto</Town>
</Address>
</Addresses>
</User>
</Users>
</ns0:Informations>
The real difference here is that instead of always getting the first “UserId” present in the "User" record, we are forcing
the BizTalk Mapper Engine to understand our intensions and force him to get the correct “UserId” as you can check in
the portion of the XSLT that the engine will generate:
...
<xsl:for-each select="../../../InputMessagePart_1/s1:Addresses/Address">
<xsl:variable name="var:v2" select="userCSharp:GetUserId()" />
<xsl:variable name="var:v3" select="string(UserID/text())" />
<xsl:variable name="var:v4" select="userCSharp:LogicalEq(string($var:v2) , $var:v3)" />
<xsl:if test="$var:v4">
...
Lack of performance: If the destination schema has many elements it takes to much work to do this kind of mapping
because for each iteration inside the “User” loop we need to travel all the elements inside the “Address” record in
order to find the correct addresses associated with the user in question.
o However this limitation will only be applied practically to large messages, otherwise you will not notice
much difference in mapping performance
Because it is inside of a loop, which means that will be applied several times, I decide to use an Inline XSLT Call
Template, otherwise I would have to write all the XSLT code. Using a template, we have the advantage of the write
once and be able to apply as often as we need in order to apply the same transformation rules. Like an inline XSLT
script, an Inline XSLT Call Template must connect directly to a destination node. However, an Inline XSLT Call Template
may use links from the source schema and from other Functoids and like the Inline XSLT Call, the call template is
responsible for creating the destination node and any of its substructures.
141
BizTalk Mapping Patterns and Best Practices
Drag from the Toolbox window one Looping Functoid and then:
o Drag a link from the “User” record in the source schema to the Looping Functoid
o And drag a link from the Looping Functoid to the record “User” in the destination schema
Drag a link from the “UserId” element present in the “User” record in the source schema to the “UserId” element
present in the “User” record in the destination schema
Drag a link from the “LastName” element in the source schema to the “LastName” element in the destination
schema
Drag a link from the “FirstName” element in the source schema to the “FirstName” element in the destination
schema
Drag from the Toolbox window one Scripting Functoid and then:
o Drag a link from the “UserId” element present in the “User” record in the source schema to the Scripting
Functoid
o Drag a link from the Scripting Functoid to the “Addresses” record in the destination schema
o This scripting Functoid is for create an Inline XSLT Call Template to create, based on the “UserId” the
Address structure in the destination schema.
Double click in the Scripting Functoid and specify the scripting type as “Inline XSLT Call Template”
In the Inline script put the following code:
<xsl:template name="AddressTemplate">
<!-- value for the template -->
<xsl:param name='id' select='UserID'/>
<!-- The Scripting Functoid will not add the record in which is linked, so we need
to manually add it -->
<Addresses>
<!-- By using this XPath query we will loop for all the records in which the
UserId in the Address record is the same passed as input. -->
<xsl:for-each select="../../../InputMessagePart_1/s1:Addresses/Address[UserID/text()=$id]">
<Address>
<UserID>
<!-- Because we are under the Addresses/Address segment we can simple use
the syntax UserID/text() to get the element value -->
<xsl:value-of select="UserID/text()"/>
</UserID>
<AddressLine1>
<xsl:value-of select="AddressLine1/text()"/>
</AddressLine1>
<PostCode>
<xsl:value-of select="PostCode/text()"/>
</PostCode>
<Town>
<xsl:value-of select="Town/text()"/>
</Town>
</Address>
</xsl:for-each>
</Addresses>
</xsl:template>
142
BizTalk Mapping Patterns and Best Practices
Readability: Because we use scripting Functoids we cannot read the entire map visually. We need to open the
Functoids and read the XSLT code.
Development: We need basic knowledge of XSLT and XPath.
Resources
All source code is available in the Microsoft Code gallery here: BizTalk Mapper Patterns: Working with
Multiple input messages or joining message (http://code.msdn.microsoft.com/BizTalk-Mapper-
Patterns-14888892)
How to Access Orchestration Variables from the Maps or How to Send Orchestration Variables into Maps
Another quite common problem which often occurs in integration processes is the need to access orchestration
variables inside the maps to make some transformation logic. The question is how we can achieve this easily?
And the answer is really simple: You don’t. You need to apply some kind of workaround to accomplish that and there
are a couple of options a developer can have to accomplish that:
143
BizTalk Mapping Patterns and Best Practices
Former BizTalk MVP Randal van Splunteren wrote a Custom Functoid: OrchestrationVariableRetrieverFunctoid
(http://biztalkmessages.vansplunteren.net/2009/04/05/orchestration-variable-retriever-functoid-and-why-you-
should-not-use-it/) that retrieves a variable value from the orchestration hosting the map.
I will not deep in detail in this approach, because as I reference before is not recommended and like the author himself
described. This approach as several limitation or disadvantages:
Lack of performance: The Functoid code contains a considerable amount of reflection code and reflection comes
with high costs. So in terms of performance it will be much better to use alternative methods.
Support: This is probably not supported by MS. Mainly because it uses XLANG code which is normally hidden from
the developers.
Testing: You cannot test this approach easily or by using Test Map functionality inside Visual Studio, you need to
test this in runtime.
Development: There are better and more efficient alternative ways to accomplish this.
Create a new Visual C# Class Library project inside your BizTalk Solution and give a proper name, for example:
“StoreValuesHelperClass”
o Rename the “Class1.cs” to “StoreValues.cs”
o And copy the following code:
using System;
144
BizTalk Mapping Patterns and Best Practices
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StoreValuesHelperClass
{
public class StoreValues
{
[ThreadStatic]
public static Dictionary<string, string> Data = new Dictionary<string, string>();
/// <summary>
/// This method will read the value of a property (key) defined earlier for this thread.
/// The property (key) must exist in the dictionary
/// </summary>
/// <param name="key">Name of the variable</param>
/// <returns></returns>
public static string GetDataValue(string key)
{
if (Data.ContainsKey(key))
{
return Data[key];
}
else
{
return null;
}
}
/// <summary>
/// This method will set a value of a property (Key) for a specific thread
/// </summary>
/// <param name="key">Name of the variable</param>
/// <param name="value">Value of the variable</param>
public static void SetDataValue(string key, string value)
{
if (Data == null)
Data = new Dictionary<string, string>();
Data[key] = value;
}
}
}
Note
You need to sign this project to be able to use inside the maps or orchestrations. Your can find more information
about this topic here: How to: Sign an Assembly (Visual Studio) (http://msdn.microsoft.com/en-
us/library/ms247123%28v=vs.100%29.aspx)
To use Helper Class inside our BizTalk project we first need to import the Class Library reference created above to our
project. To accomplish that we need to:
In Solution Explorer, right-click the BizTalk project name and then click “Add Reference”.
In the “Reference Manager” dialog box, select the “Solution” tab and then select the reference to the Helper Class
created above. Click “Ok” to finish.
145
BizTalk Mapping Patterns and Best Practices
In Solution Explorer, right-click the BizTalk project name, select “Add”, and then click “New Item”.
In the “Add New Item” dialog box, in the “Categories” pane, click “BizTalk Project Items”, and then in the
“Templates” pane, click “Map”.
o In the Source Schema select the schema “Order” from the BizTalk Type Picker
o In the Destination Schema select the schema “SAPOrder” from the BizTalk Type Picker
Because at this moment is not relevant to our problem I will not describe all mapping rules in this demo. This is the
general overview:
The final goal here is to access the value of the variable “DiscountType” that will be create in the orchestration and
map the value to the “DiscountType” element in the destination schema. To accomplish that we need to:
146
BizTalk Mapping Patterns and Best Practices
Drag from the Toolbox window one Scripting Functoid and then:
o Drag a link from the Scripting Functoid to the “DiscountType” element in the destination schema
o This scripting Functoid is to call the existing method in an external reference for reading the values, i.e., the
existing “GetDataValue” method from the Helper class that we created earlier
Double click in the Scripting Functoid, select the “Script Functoid Configuration” tab and specify the
scripting type as “External Assembly”
In the External Assembly setup put the following configurations:
o In the “Script assembly” specify the “StoreValueHelperClass” assembly
o In the “Script class” specify the “StoreValueHelperClass.StoreValue” class
o In the “Script method” specify the “GetDataValue” method
Select the “Functoid Inputs” tab and then specify the name of the variable you want to reach by:
Click the “+” (plus) button to add a new input row and set the name of the variable, for
example: “varDiscountType”.
147
BizTalk Mapping Patterns and Best Practices
This will provide access to the value of the variable specify in the orchestration.
Finally we need to create the orchestration and set the values of the variables that we want to access from the
maps. To accomplish that we need to:
In Solution Explorer, right-click the BizTalk project name, select “Add”, and then click “New Item”.
In the “Add New Item” dialog box, in the “Categories” pane, click “BizTalk Project Items”, and then in the
“Templates” pane, click “BizTalk Orchestration”.
In the Name box at the bottom of the dialog box, supply a name for the orchestration, and then click “Add”.
Note
I will not describe all the steps here because this is not the aim, however I will provide the key steps.
Create two One-Way logical ports with the binding type set to “Specify later” by:
o Right-click a “Port Surface” and then click “New Port”.
One for receiving messages: “CustomerOrderPort”
And One for sending messages: “SAPPort”
In the Orchestration View window, create 2 messages by:
o Right-click “Messages” and then click “New Message”.
Set the message name as “msgOrder” and set the message type as “Order”
Set the message name as “msgSAPOrder” and set the message type as “SAPOrder”
In the Orchestration View window, create two variable by:
o Right-click the “Variables” folder and then click “New Variable”.
Set the variable name as “varDiscountType” and set the variable type as “System.String”
Set the variable name as “varHasDiscount” and set the variable type as “System.Boolean”
varHasDiscount = true;
varDiscountType = "25%";
148
BizTalk Mapping Patterns and Best Practices
StoreValuesHelperClass.StoreValues.SetDataValue("varHasDiscount", varHasDiscount.ToString());
StoreValuesHelperClass.StoreValues.SetDataValue("varDiscountType", varDiscountType.ToString());
o Transform Shape
In the “Properties” window, of the Construct Message shape, use the “Messages Constructed”
property to specify which messages this shape will construct. In this case the “msgSAPOrder”
Double-click the Transform Shape or right-click the Transform Shape and click "Configure
Transform Shape..."
In the “Transform Configuration” dialog box:
Select the “Existing Map” option, and from the “Fully Qualified Map Name” drop-down list
choose your map.
Then click “Source”, and from the “Source Transform” drop-down list select:
o “msgOrder” as the first input
Click in “Destination”, and then from the “Destination Transform” drop-down list, select
“msgSAPOrder” as the output of the transformation
o Send Shape
In the “Properties” window, select from the “Message” property the message “msgSAPOrder” to
be sent
Drag the send connector from the Send Shape to the “SAPPort” logical port
Maintainability: From a maintenance perspective this approach seams relatively simple to maintain, however if
this is shared by several projects, then you also need handler this dependencies inside the BizTalk Applications
under BizTalk Administration Console.
Reusability: By using this approach you can easily reuse the same Helper Class in our different projects.
149
BizTalk Mapping Patterns and Best Practices
Maintainability: This can also be a disadvantage from a maintenance perspective because if we are using an
external assembly, we will be stuck with this DLL dependence in every project.
Lack of performance: This approach comes with little performance hit also and in some scenarios you may run out
of memory. You if use this approach you can also find yourself in particular dangerous situation, for example if you
don’t validate if the static singleton instance object still exist or not in the code you obtain “object reference not
set to an instance of an object” errors and you may have to restart the host instance to solve this issue.
Development: From a developer’s perspective this sounds very easy to implement, however you have to be very
careful, for example you need to ensure that the dictionary gets persisted to the Message Box otherwise you can
get an empty dictionary and you should create and use a remove method to clear the values from the dictionary to
make sure you don't run out of memory.
o By using this approach we will work only with String so we will lose the concept of types which may lead to
additional developer effort and conversions inside the maps.
Testing: You cannot test this approach easily or by using Test Map functionality inside Visual Studio, you need to
test this in runtime
Readability: In big map transformation this can be more difficult to read and to maintain because we need to go
inside the Functoid to see or understand what really is happening. There isn’t any visual information on the map
grid that indicates what is happening.
Level of effort: by being more difficult to read and maintain the maps and for all the care that we must have in the
orchestrations development this will increase the development time.
Create a new message schema with fields that you need to capture from the orchestration by:
o In Solution Explorer, right-click the BizTalk project name, select “Add”, and then click “New Item”.
o In the “Add New Item” dialog box, in the “Categories” pane, click “BizTalk Project Items”, and then in the
“Templates” pane, click “Schema”.
o Create a schema according to the follow picture:
150
BizTalk Mapping Patterns and Best Practices
o This is optional but to able to access the fields of this message easily from within the orchestration you can
promoted them as distinguished fields.
Right-click the context message schema tree, and select “Promote Show Promotions”.
In the Promote Properties dialog box, select each field in the left window, and click the “Add
button”. When finished click OK.
The orchestration is quite similar to that we created and explained earlier in the SECOND SOLUTION: USING A HELPER CLASS
TO STORES VALUES:
151
BizTalk Mapping Patterns and Best Practices
We will use a Message Assignment to manually create the support message with the content of our orchestration
values. You can accomplish that by using a simple C# code inside the Message Assignment:
msgOrchestrationSupport = varXML;
msgOrchestrationSupport.HasDiscount = varHasDiscount;
msgOrchestrationSupport.DiscountType = varDiscountType;
And we to create the map from “Transform Shape” inside the orchestration, because this is the only way to specify
multiple sources or destination schemas.
After that you can easily use, combine or merge information inside the map editor, for example:
Drag from the Toolbox window one Value Mapping Functoid and then:
o Drag a link from the “User” record in the source schema to the Looping Functoid
o And drag a link from the Looping Functoid to the record “User” in the destination schema
Drag a link from the “HasDiscount” element in the source schema to the Value Mapping Functoid
Drag a link from the “DiscountType” element in the source schema to the Value Mapping Functoid
Drag a link from the Value Mapping Functoid to the “DiscountType” element in the destination schema
In other words, we are mapping the Discount type to the destination message only if the only if there is discount to
be applied in this order, i.e., the “HasDiscount” element is set to “True”. Otherwise no value will be mapped as you
can see in the map picture bellow:
152
BizTalk Mapping Patterns and Best Practices
Performance: From all the solutions presented this is the solution with less performance loss and less issues.
Maintainability: From a maintenance perspective this approach is relatively simple to maintain.
Development: From a developer’s perspective we may have little tedious work to do, but this is very easy to
implement and developer.
Testing: You will have all the Test Map functionality inside Visual Studio this way you don’t need to test this
approach in runtime
I really don’t see any big disadvantages in this approach, the only thing is:
Reusability and Level of effort: we may need and additional development effort to constantly implement this
approach in our projects. Is not easy to reuse this approach unless you create a schema that predicts all your
scenarios.
Resources
All source code is available in the Microsoft Code gallery here: BizTalk Mapper Patterns: How to Access
Orchestration Variables from Maps (http://code.msdn.microsoft.com/BizTalk-Mapper-Patterns-
69cb788d)
153
BizTalk Mapping Patterns and Best Practices
target system will require less information than the source system will provide, for example: the source system will
provided the customer ID, customer name and address but the target system will only need the customer ID. Here we
will remove unimportant data items from a message, sometimes also based on specific criteria (see CONDITIONAL
PATTERN), and we leave only the important ones.
The Content Filter does not necessarily just remove data elements and sometimes can also be used to simplify the
structure of the message. Often times, messages are represented as tree structures. Many messages originating from
external systems or packaged applications contain many levels of nested, repeating groups because they are modeled
after generic, normalized database structures. Frequently, known constraints and assumptions make this level of
nesting superfluous and a Content Filter can be used to 'flatten' the hierarchy into a simple list of elements than can
be more easily understood and processed by other systems.
The Content Filter lets us remove uninteresting data items from a message.
154
BizTalk Mapping Patterns and Best Practices
By having this in mine, removing unnecessary data from the source schema, sometimes also based on specific criteria
for example if the element exist or not in the source schema, and even normalize the data or simplify its structure are
normally an easy task inside mappers.
So if you don’t want to map or use certain elements that exist in the source schema you simple need not to create
rules to apply to that elements, for example: don’t link them to any Functoid or elements in the destination rules. But
let’s look at this example here we have a Customer Service schema that we want to map to a Client structure and see
how we can apply some of this concepts:
As you can see, they are very different schemas were the destination as more less elements that the source schema.
By looking to the schemas we noticed that there are two element: “Name” and “TaxId” which we can easily map to
the destination schemas by using direct links:
Simplifying the structure: Another element that pop up immediately, despite the last one be present in a different
structure from others (“Name” and “TaxId”) is the “Phone” element that is present in the "ContactPhone" record
and that we can once again easily map to the destination schemas by using direct link. In this case we are simplifying
the structure of the original schema and respecting the destination structure.
155
BizTalk Mapping Patterns and Best Practices
Normalizing data: Depending on the system, data can be delivery in different format that we need to transform or
convert it to the expected format in the destination system, a very common example of this are the dates: they can
be delivery in traditional date (Human Readable Date) or in Unix date (Epoch Date), to further complicate matters,
inside traditional date they can be delivery in several formats. This transformation rules are normally made by
making use of Functoids or custom code (C#, VB, JScript or XSLT)
o In this sample we have the “Address” element that is a single element string in the destination that need
to be map from the “Address” record structure in the source.
The destination system doesn’t really need the information about the “Region” and the “Locality”,
so we will ignore these elements and we will use a String Concatenate Functoid to aggregate the
rest of the element into a single string separated by “,” character.
Removing data: So we end up with one last element that need to be mapped: the “Email”. This element it’s an
optional element that needs to be mapped only if there’s information present in the source schema.
156
BizTalk Mapping Patterns and Best Practices
o Improve the quality of data: This type of operations will be explained in more details latter on the
CONDITIONAL PATTERN, however to accomplished this task you should:
Open the Toolbox window and drag to the grid:
One Logical Existence Functoid
And one Value Mapping Functoid
In this approach we will use the Logical Existence Functoid to determine if the Field Element node
that is linked exists in a particular input instance message. If exist we will map the element,
otherwise we will not.
Drag a link from the “Email” field element in the source schema to the Logical Existence Functoid
Drag a link from the Logical Existence Functoid to the Value Mapping Functoid
The first input of the Value Mapping Functoid must be a Boolean value to control whether
the second value gets mapped or not.
Drag a link from the “Email” field element in the source schema to the Value Mapping Functoid
Drag a link from Value Mapping Functoid to the “Email” field element in the destination schema
o Removing unnecessary data: The rest of the element are unnecessary, so we will not create any rules from
them and they will not be mapped.
157
BizTalk Mapping Patterns and Best Practices
A common problem when different systems need to be integrate is to ensure that the data are not duplicate. This is
because the sources often can contain redundant data in different representations. So in order to provide accurate
and consistent data, consolidation of different data representations or elimination of duplicate information become
necessary by specifying cleansing rules that applies changes to enforce consistency and quality on the data.
Note
If possible, this kind of tasks, data cleaning and consistency, should be done in the source systems.
In this first example we will have an order messages gathered from your internal or external systems, however the
system don’t have the capability to control duplications, so we need to assume that:
The input message can have order duplicate base on the “OrderNumber” field element
The orders appear in the message with no defined order, so duplicates can appear anywhere, i.e., orders don't
show up in ascending or descending order.
We don’t want to perform any king of data manipulation or transformation. We just want to remove the duplicates,
if we make an analogy with SQL Server, this will be a SQL SELECT DISTINCT operation.
And we need to validate and delete all the duplicate orders inside the message:
Input Output
<Order> <Order>
<OrderNumber>OrderNumber_0</OrderNumber> <OrderNumber>OrderNumber_0</OrderNumber>
<OrderDate>OrderDate_0</OrderDate> <OrderDate>OrderDate_0</OrderDate>
<CustomerName>CustomerName_0</CustomerName> <CustomerName>CustomerName_0</CustomerName>
<CustomerAddress>CustAdd_0</CustomerAddress> <CustomerAddress>CustAdd_0</CustomerAddress>
<Status>Status_0</Status> <Status>Status_0</Status>
<TotalAmount>TotalAmount_0</TotalAmount> <TotalAmount>TotalAmount_0</TotalAmount>
<Type>Type_0</Type> <Type>Type_0</Type>
</Order> </Order>
<Order> <Order>
<OrderNumber>OrderNumber_0</OrderNumber> <OrderNumber>OrderNumber_1</OrderNumber>
<OrderDate>OrderDate_0</OrderDate> <OrderDate>OrderDate_1</OrderDate>
158
BizTalk Mapping Patterns and Best Practices
<CustomerName>CustomerName_0</CustomerName> <CustomerName>CustomerName_1</CustomerName>
<CustomerAddress>CustAdd_0</CustomerAddress> <CustomerAddress>CustAdd_1</CustomerAddress>
<Status>Status_0</Status> <Status>Status_0</Status>
<TotalAmount>TotalAmount_0</TotalAmount> <TotalAmount>TotalAmount_1</TotalAmount>
<Type>Type_0</Type> <Type>Type_0</Type>
</Order> </Order>
<Order>
<OrderNumber>OrderNumber_1</OrderNumber>
<OrderDate>OrderDate_1</OrderDate>
<CustomerName>CustomerName_1</CustomerName>
<CustomerAddress>CustAdd_1</CustomerAddress>
<Status>Status_0</Status>
<TotalAmount>TotalAmount_1</TotalAmount>
<Type>Type_0</Type>
</Order>
Drag the mouse from the root name “Order” in the source schema, and then drop it to root name “Order” in the
destination schema.
On the shortcut menu, click “Link by Name” or “Link by Structure” option. The BizTalk Mapper will then
automatically map all the Field Elements from the source to the destination schema, as explained in the DIRECT
TRANSLATION PATTERN.
We actually don’t need to have a Looping Functoid because the map will understand that we are using a record
that can occurs several times and we will create an hidden link for us. However we will create just to clarify and to
be more easy to visually read the map:
o Drag from the Toolbox window one Looping Functoid and then:
Drag a link from the “Order” record in the source schema to the Looping Functoid
And drag a link from the Looping Functoid to the record “Order” in the destination schema
159
BizTalk Mapping Patterns and Best Practices
Now the only thing that is missing here is a way to check and select all the distinct orders from the source to the
destination.
o To handle this logic we will create a Global Generic List inside a C# Custom Scripting Functoid to keep track
of all the Unique Order ID that have already been mapped. The function will check if the “OrderNumber”
on each loop is already present in the Global List and:
If not exist, he will map all the elements from the source to the destination schema
And If it’s already present, he will ignore and go to the next loop operation
o We can accomplish this by:
Drag from the Toolbox window to the grid page:
One Scripting Functoid
And one Equal Functoid
Drag a link from the “OrderNumber” field element in the source schema to the Scripting Functoid
and then Double-click in the Scripting Functoid to show the Properties window, then:
Select the “Script Functoid Configure” tab, and then choose “Inline C#” as your selected
script type
In the “Inline script” text box enter the following C# code:
duplicateList.Add(OrderNumber);
return false;
}
160
BizTalk Mapping Patterns and Best Practices
Drag a link from the Equal Functoid to the record “Order” in the destination schema
What this means is that the Scripting Functoid will return true if the “OrderNumber” is already been mapped or false
if needs to be mapped. And by linking the Equal Functoid to the record “Order” in the destination schema, we are
telling that the record will be create if the condition inside the Equal Functoid will be TRUE.
Maintainability: From a maintenance perspective this approach seams relatively simple to maintain, however if
this logic in several maps, then you may think in putting this C# logic inside a HelperClass in an external DLL.
161
BizTalk Mapping Patterns and Best Practices
Lack of performance: This approach comes with little performance hit also and in some heavy scenarios, when you
may dealing with lags number of messages or with large messages, you may run out of memory.
Development: In some complex scenarios, it can be extremely difficult to implement advance distinct rules using
this approach (Mapper, Functoids and C#).
The first thing we need to do is to drag a Scripting Functoid onto the Grid. Then drag a line to the element that we
want to create output for, in this case the “Order” record.
To create the output in the format that we want we could start creating a variable populated with a list of unique
Orders nodes with the following XSLT code:
And then start creating the output of our nodes with in a loop statement through unique order nodes with the
following code:
<xsl:for-each select="$unique-orders">
<Order>
<xsl:copy-of select="./@*" />
<xsl:copy-of select="./*" />
</Order>
</xsl:for-each>
However we will optimize a little the code avoiding the extra variable, using the following XSLT code inside the Scripting
Functoid:
162
BizTalk Mapping Patterns and Best Practices
Development & Performance: From a developer’s perspective this approach is very simple to implement and this
algorithm has a good efficient in “normal” messages (small and medium).
Maintainability & Readability: Despise from a maintenance perspective this approach is relatively simple to
maintain, comparing to the previous one this has more cost effects, because you need to understand the basic of
XSLT language. And because we use scripting Functoids we cannot read the entire map visually. We need to open
the Functoids and read the XSLT code.
Performance: This algorithm is not efficient for large messages but work well for “normal” messages. For large
messages Muenchian method is generally more efficient than using preceding-sibling.
Level of effort: by being more difficult to read and maintain the maps this will increase the development time.
The first thing we need to do is to drag two Scripting Functoid from the Toolbox window onto the Grid.
The first Scripting Functoid will not have any input or output links, it will work as a global place to define global
variables.
And in the second Scripting Functoid you must drag a link from the Functoid to the record “Order” in the
destination schema
163
BizTalk Mapping Patterns and Best Practices
Double-click in the first Scripting Functoid to show the Properties window, then:
o Select the “Script Functoid Configure” tab, and then choose “Inline XSLT” as your selected script type
o In the “Inline script” text box enter the following XSLT code:
<xsl:key name="UniqueOrders" match="Order" use="OrderNumber" />
All of the code put in this Scripting Functoid will be wrapped inside the XSLT file just between the </xsl:template>
and the </xsl:stylesheet> blocks. Here we're creating a key value for this grouping so that the transform engine can
use it to loop through each unique value of that key, i.e., we are creating a key will all the distinct values of the
“OrderNumber” present in the input instance.
Double-click in the second Scripting Functoid to show the Properties window, then:
o Select the “Script Functoid Configure” tab, and then choose “Inline XSLT” as your selected script type
o In the “Inline script” text box enter the following XSLT code:
Were we are basically travelling all the distinct elements that exist in the input instance and map the values, ignoring
the duplicates nodes. (Muenchian Method will be properly explained in the GROUPING PATTERN in the USING MUENCHIAN
METHOD section)
Performance: This is probably the algorithm with most performance that we can use in XSLT 1.0. And it is extremely
beneficial to use when dealing with large messages.
Maintainability & Readability: Despise from a maintenance perspective this approach is relatively simple to
maintain, comparing to the previous one this has more cost effects, because you need to understand the basic of
XSLT language. And because we use scripting Functoids we cannot read the entire map visually. We need to open
the Functoids and read the XSLT code.
164
BizTalk Mapping Patterns and Best Practices
Development: Muenchian Method is not a normal operation that we use inside the maps, they are normal
implement by bypassing the map and implement them in an external XSLT file, and by doing that it requires advance
knowledge of XSLT and XPath. To implement inside the maps it also requires advance knowledge how map works
and how to create global variables and how to use them inside other scripts. So for all these reasons and comparing
to the other approaches this is the most expensive solution.
Level of effort: by being more difficult to read and maintain the maps this will increase the development time.
So in this second example we will have a message with “Application Forms” gathered from your internal or external
systems, which once again don’t have the capability to control duplications or application updates, so we need to
assume that:
The input message can have Application Forms duplicates base on the “FullName” of the candidate
The Application Forms appear in the message with no defined order, so duplicates can appear anywhere, i.e., they
don't show up in ascending or descending order.
We don’t want to perform any king of data manipulation or transformation.
We just want to remove the duplicates, however we want to map the form in which the “RequestDate” field
element is more recent, if we make an analogy with SQL Server, this will be a SQL SELECT DISTINCT … ORDER BY
operations.
Input Output
<Form> <Form>
<FullName>Sandro Pereira</FullName> <FullName>Sandro Pereira</FullName>
<RequestDate>2013-12-10</RequestDate> <RequestDate>2014-01-12</RequestDate>
<Nationality>Portuguese</Nationality> <Nationality>Portuguese</Nationality>
<Address> <Address>
<AddressLine1>Portugal</AddressLine1> <AddressLine1>Portugal</AddressLine1>
<AddressLine2>Porto</AddressLine2> <AddressLine2>Porto</AddressLine2>
<PostalCode>4415</PostalCode> <PostalCode>4415</PostalCode>
<Location>Porto</Location> <Location>Porto</Location>
</Address> </Address>
<Contacts> <Contacts>
<Email>[email protected]</Email> <Email>[email protected]</Email>
<Phone>220000000</Phone> <Phone>220000011</Phone>
</Contacts> </Contacts>
<QualificationsAndSkills> <QualificationsAndSkills>
<AcademicLevel>Lic</AcademicLevel> <AcademicLevel>Degree</AcademicLevel>
<TechnicalKnowledge>TK</TechnicalKnowledge> <TechnicalKnowledge>Eg</TechnicalKnowledge>
</QualificationsAndSkills> </QualificationsAndSkills>
</Form> </Form>
<Form>
<FullName>Sandro Pereira</FullName>
<RequestDate>2014-01-12</RequestDate>
<Nationality>Portuguese</Nationality>
<Address>
<AddressLine1>Portugal</AddressLine1>
<AddressLine2>Porto</AddressLine2>
<PostalCode>4415</PostalCode>
<Location>Porto</Location>
</Address>
<Contacts>
165
BizTalk Mapping Patterns and Best Practices
<Email>[email protected]</Email>
<Phone>220000011</Phone>
</Contacts>
<QualificationsAndSkills>
<AcademicLevel>Degree</AcademicLevel>
<TechnicalKnowledge>Eg</TechnicalKnowledge>
</QualificationsAndSkills>
</Form>
<Form>
<FullName>Sandro Pereira</FullName>
<RequestDate>2014-01-10</RequestDate>
<Nationality>Portuguese</Nationality>
…
</Form>
So the difference is that in the previous sample, we map the first node that we encountered, regardless if it was the
latest or not. In this case we need the last update of each node.
Looking to the solutions presented in the first example, I immediately discarded the use first approach “First Solution:
Using Functoids” because it’s simple impossible or almost impossible to accomplished. And the best solution that I
found was using Muenchian Method.
The first Scripting Functoid will not have any input or output links, it will work as a global place to define global
variables.
And in the second Scripting Functoid you must drag a link from the Functoid to the record “Order” in the
destination schema
166
BizTalk Mapping Patterns and Best Practices
Double-click in the first Scripting Functoid to show the Properties window, then:
o Select the “Script Functoid Configure” tab, and then choose “Inline XSLT” as your selected script type
o In the “Inline script” text box enter the following XSLT code:
<xsl:key name="AppForms" match="Form" use="FullName" />
Once again, we are creating a key will all the distinct values of the “FullName” present in all the forms on the input
instance.
Double-click in the second Scripting Functoid to show the Properties window, then:
o Select the “Script Functoid Configure” tab, and then choose “Inline XSLT” as your selected script type
o In the “Inline script” text box enter the following XSLT code:
<!-- This will loop through each different nodes that have the FullName that we want -->
<xsl:for-each select="/ns0:ApplicationForms/Form[FullName= $FilterName]">
<!-- Here we are apply the sort operation to have the highest date first -->
<xsl:sort select="RequestDate" order="descending"/>
<!-- We only want to map the first element and ignore the rest -->
<xsl:if test="position() = 1">
<Form>
<xsl:copy-of select="./@*" />
<xsl:copy-of select="./*" />
</Form>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
Were we are basically travelling all the distinct elements that exist in the input instance and map the values, applying
a short operation and map the first element founded ignoring the rest of the nodes with the same name. (Muencian
Method will be properly explained in the GROUPING PATTERN in the USING MUENCHIAN METHOD section)
Performance: This was the best solution in terms of performance that I was able to archive.
Performance: I think that if we could avoid some unnecessary loop operation we can increase the performance of
this solution.
Second Solution: Custom External XSLT File, Templates and Support Variables
I’m always trying to avoid using External XSLT files inside the maps, but in some situations this approach is extremelly
useful because you can accomplish several things that you simple cannot apply inside the maps. So in a word they can
be more powerful that the maps.
This sample was provide to me by Fernando Pires (http://fernandodosanjos.wordpress.com/) a country man of mine
and a strong community member. I will not explain this in details but I want to give you a different perspective of how
can you accomplish this task.
167
BizTalk Mapping Patterns and Best Practices
<!-- The msxsl:node-set function enables you to convert a result tree fragment into a node
set. The resulting node set always contains a single node and is the root node of the
tree. In this case we are getting all the Forms nodes -->
<xsl:variable name="sortedNodeSet" select="msxsl:node-set($sorted)/Forms"/>
<!-- We will perform a loop operation to all the forms and check with the following-sibling
axis if the current node is duplicate or not -->
<xsl:for-each select="$sortedNodeSet/*">
<xsl:if test="(FullName != following-sibling::*[1]/FullName) or (position() = last())">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</ns0:ApplicationForms>
</xsl:template>
<xsl:template name="SortFrom" match="Form">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
Maintainability & Readability: For a strong XSLT developer, this approach can be very simple to read, easy to
maintain, easy to comment the code and tracking changes in version control can also way be easier to check when
using external XSLT files.
All the disadvantages of using external XLST files can be found here: EXTERNAL CUSTOM XSLT FILE VS. BIZTALK MAPPER,
however for this particular approach and comparing to the first solution:
Performance: Because you are recreating a variable with the content of the message, I think you will need to use
more memory and because we are using following-sibling axis that has less performance than using keys, I think
that this approach comparing to the first solution can have less performance
Special thanks to Fernando Pires (http://fernandodosanjos.wordpress.com/) that take some of is time to provide me
with a different approach.
168
BizTalk Mapping Patterns and Best Practices
Resources
Reference to this pattern:
All source code is available in the Microsoft Code gallery here: BizTalk Mapper Patterns: Content Filter
Pattern (Data Cleaning Pattern) (http://code.msdn.microsoft.com/BizTalk-Mapper-Patterns-b87eff13)
Splitter Pattern
Previously we explained the AGGREGATOR PATTERN combine or merge parts of information from multiple inbound
messages into a single outbound message. The SPLITTER PATTERN is the opposite and this could also be another example
of the Content Filter Pattern. In some of the integration process’s we need to exchange messages between several
systems, for example: a customer order needs to be sent to CRM System but also to our Inventory and operational
Systems, so we need to be able to splits an incoming message into a series of outgoing messages. Each of the outgoing
messages normally contains a piece of the original message.
The Splitter Pattern provides a method for an inbound request to be mapped into several individual outbound
requests. This can be a rarely implemented pattern because we have the ability to create multiple maps to achieve
the same goal.
As we describe earlier in the AGGREGATOR PATTERN BizTalk Server allows you to create maps not only with several
inputs but also with several outputs, mapping one-to-many messages. This time with multiple output messages can
be a may be a way to solve the problem, however this technic as one strong limitation: This type of mapping is only
allowed inside the Orchestration.
The other option is to create two different maps.
However we also get a different variant of this pattern, combined with the AGGREGATOR PATTERN, and have multiple
inbound messages that were collected from the original request to be mapped and aggregated into several outbound
messages.
169
BizTalk Mapping Patterns and Best Practices
Mapping One-to-Many
In this demo we will need to send a Customer Order receive from in our system to two internal systems:
Part of the information, specially the client detail information, must be send to the CRM System
And other part of the information, the order detail information, must be send to SAP System
So we basically want to split the original information into two different formats to be sent to our internal systems. As
explained earlier, we can achieve this using:
However in this demo we will explain how to create a map with multiple output messages. So for accomplish that,
open your BizTalk Solution and:
First you need to create the different schemas that you will use in you transformation, let’s call them:
o CRMOrder.xsd and SAPOrder.xsd
o And CustomerOrder.xsd
Note
I will not explain the creation or the schemas structure here, because that is not the aim, however you will find this
schema in the source code available here. Your can find more information about this here: Creating Schemas Using
BizTalk Editor (http://msdn.microsoft.com/en-us/library/aa546812.aspx)
170
BizTalk Mapping Patterns and Best Practices
Go to the Construct Message Shape properties and set the property “Messages Constructed” to:
o “msgCRMOrder”
o and “msgSAPOrder”
o Click in “Destination”, and then from the “Destination Transform” and from the “Destination Transform”
drop-down list select:
“msgCRMOrder” as the first destination
“msgSAPOrder” as the second destination
171
BizTalk Mapping Patterns and Best Practices
o Notice that the option “When I click OK, launch the BizTalk Mapper” is checked, Click “OK” and this will
create and open the map for you with two source schemas and one destination schema.
o For now just save the map and closes it, we'll deal with it later.
Add a two Send Shape to your Orchestration.
o In the first Send Shape
In the “Properties” window, select from the “Message” property the message “msgSAPOrder” to
be sent
Drag the send connector from the Send Shape to the SAP logical port
o In the second Send Shape
172
BizTalk Mapping Patterns and Best Practices
In the “Properties” window, select from the “Message” property the message “msgCRMOrder” to
be sent
Drag the send connector from the Send Shape to the CRM logical port
On the “CRMOrder” page we will map the client detail information and the and billing total without care about the
product details, to accomplished that need to:
o Drag a link from the “OrderNumber” element in the source schema to the “OrderID” element in the
destination schema
o Drag a link from the “Name” element in the source schema to the “ClientName” element in the destination
schema
o Drag a link from the “Address” element in the source schema to the “InvoicingAddress” and
“ShippingAddress” elements in the destination schema
o Drag a link from the “Id” element in the source schema to the “ClientId” element in the destination schema
173
BizTalk Mapping Patterns and Best Practices
o Drag from the Toolbox window one Scripting Functoid and then:
Drag a link from the “Id” element in the source schema to the Scripting Functoid
And drag a link from the Scripting Functoid to the “Currency” element in the destination schema
This scripting Functoid is for create a C# function to get the currency of the client base on the client
identification. In real scenarios probably we would have here a CRM Lookup, however for the
purpose of this demo we will emulate this using a C# code:
Double click in the Scripting Functoid and specify the scripting type as “Inline C#”
In the Inline script put the following code:
o Because we don’t have the necessary information in the source schema to check the “DiscountPercent”,
“DiscountAmount”, “TransportationCosts” and “TotalTax” elements but all of this are required by CRM, we
will add a default value of 0 (zero) using the String Constant Functoid
Drag from the Toolbox window one String Constant Functoid and then drag a link from this
Functoid to all of the elements described above
Double-click in the String Constant Functoid and in the “Functoid Inputs” set as input the value “0”
o The last two elements that we need to map is the “Amount” (total price without discount) and
“TotalAmount” (total price with discount), again we don’t have the right information on the source schema,
we only have the “ItemCustomerCode” and “TotalAmount” (of units), so we need to use mathematic
operations to solve this transformation:
Drag from the Toolbox window one Scripting Functoid, one Multiplication Functoid and one
Cumulative Sum Functoid and then:
Drag a link from the “ItemCustomerCode” element in the source schema to the Scripting
Functoid
And drag a link from the Scripting Functoid to the Multiplication Functoid
This scripting Functoid is for create a C# function to get the price of the product base on
the item Customer Code. In real scenarios probably we would have here a query to a
database or to a financial system, however for the purpose of this demo we will emulate
this using a C# code:
o Double click in the Scripting Functoid and specify the scripting type as “Inline
C#”
o In the Inline script put the following code:
Drag a link from the “TotalAmount” element in the source schema to the Multiplication Functoid
Drag a link from the “Multiplication Functoid to the Cumulative Sum Functoid
174
BizTalk Mapping Patterns and Best Practices
Drag a link from the Cumulative Sum Functoid to the “Amount” and “TotalAmount” element in the
destination schema
On the “SAPOrder” page we will map the order detail information required from the source schema to the second
destination schema (ns2:SAPOrder) in ordered to be sent to a different system. To accomplished that need to:
o Drag a link from the “OrderNumber” element in the source schema to the “OrderID” element in the
“SAPOrder” destination schema
o Drag a link from the “Id” element in the source schema to the “ClientId” element in the “SAPOrder”
destination schema
o Drag a link from the “OrderDate” element in the source schema to the “OrderDate” element in the
destination schema
o Drag a link from the “EstimatedDeliveryDate” element in the source schema to the
“EstimatedDeliveryDate” element in the destination schema
o Drag from the Toolbox window one Date and Time Functoid and then:
Drag a link from the Date and Time Functoid to the “ProcessDate” element in the destination
schema
This Date and Time Functoid will return the current date and time. This Functoid does not
require any input parameters. The output format is “CCYY-MM-DDThh:mm:ss”.
o Drag from the Toolbox window one Looping Functoid and then
Drag a link from the “OrderDetails” record in the source schema to the Looping Functoid
Drag a link from the Looping Functoid to the “Details” record in the destination schema
o Drag a link from the “ItemCustomerCode” element in the source schema to the “ItemId” element in the
“SAPOrder” destination schema. In real scenarios probably we would have here a translation between the
customer code and our internal code, however for the purpose of this demo we will simple link them.
o Drag a link from the “TotalAmount” element in the source schema to the “Units” element in the “SAPOrder”
destination schema
175
BizTalk Mapping Patterns and Best Practices
o Drag a link from the “UnitType” element in the source schema to the “UnitType” element in the “SAPOrder”
destination schema
Mapping Many-to-Many
This is the same demo explained earlier, but in this scenario we are gathering from one internal system information
about the discount that should be apply or not in this client order that we need to send to our map. So the main
difference is that instead of having one source schema in this sample we will have two source schemas that need to
be mapped to two destination schemas.
176
BizTalk Mapping Patterns and Best Practices
Note
I will not explain all the steps needed for this demo because they were already covered above. Basically we will
combine the previous demo with the same approach and schema specifying the discount information described in
HOW TO ACCESS ORCHESTRATION VARIABLES FROM THE MAPS OR HOW TO SEND ORCHESTRATION VARIABLES INTO MAPS (THIRD
SOLUTION: USING A SUPPORT SCHEMA)
In terms of the mapping transformation, everything will be the same except the calculation of the “Total” record
information in the “CRMOrder” destination schema because we now have more data so that it can be accomplished
with more details.
To map the Total record in the destination schema we need to use mathematical operations and one of the possible
and easiest ways to solve this is to use a combination of standard Functoids available and custom C# code used inside
Scripting Functoids
Because we don’t have information in the source schemas about “TransportationCosts” and “TotalTax” elements
but they are required by CRM, we will add a default value of 0 (zero) using the String Constant Functoid
o Drag from the Toolbox window one String Constant Functoid and then drag a link from this Functoid to
both elements described above
o Double-click in the String Constant Functoid and in the “Functoid Inputs” set as input the value “0”
For the “Amount” element we will be using the same approach used in the previous sample, so:
o Drag from the Toolbox window one Scripting Functoid, one Multiplication Functoid and one Cumulative
Sum Functoid and then:
Drag a link from the “ItemCustomerCode” element in the source schema to the Scripting Functoid
And drag a link from the Scripting Functoid to the Multiplication Functoid
This scripting Functoid is for create a C# function to get the price of the product base on the item
Customer Code. In real scenarios probably we would have here a query to a database or to a
financial system, however for the purpose of this demo we will emulate this using a C# code:
Double click in the Scripting Functoid and specify the scripting type as “Inline C#”
In the Inline script put the following code:
o Drag a link from the “TotalAmount” element in the source schema to the Multiplication Functoid
o Drag a link from the “Multiplication Functoid to the Cumulative Sum Functoid
o Drag a link from the Cumulative Sum Functoid to the “Amount” element in the destination schema
177
BizTalk Mapping Patterns and Best Practices
In order to calculate the “DiscountPercent” we need to check if the “HasDiscount” is set to “true”:
If so, we need to apply the discount amount contained in the "DiscountType" element
Otherwise the discount amount will be “0” zero.
And finally the value need to be displayed in percentage format, example: "25%"
So we need to:
Drag from the Toolbox window one Equal Functoid, one Logical NOT Functoid, two Value Mapping Functoids and
two String Concatenate Functoids, then:
o Drag a link from the “HasDiscount” element in the source schema to the Equal Functoid
Double click in the Equal Functoid and then:
Click in the add button to add a constant value as an input
Set the value of the new input as “true”
o And drag a link from the Equal Functoid to the Value Mapping Functoid
o Drag a link from the “DiscountType” element in the source schema to the Value Mapping Functoid
178
BizTalk Mapping Patterns and Best Practices
o And drag a link from the Value Mapping Functoid to the Concatenate Functoid. Then select this link and go
to his properties:
Then select this link and go to his properties and set the “Label” property as: “Discount percentage
value”
o Double click in the Concatenate Functoid and then:
Click in the add button to add a constant value as an input
Set the value of the new input as “%”
And drag a link from the Concatenate Functoid to the “DiscountPercent” element in the destination schema
However we still have to deal when the condition is false: the else statement, so we need to:
And drag a link from the Equal Functoid to the Logical NOT Functoid
And drag a link from the Logical NOT Functoid to the Value Mapping Functoid
o Then select this link and go to his properties and set the “Label” property as: “hasDiscount is False”
Double click in the Concatenate Functoid and then:
o Click in the add button to add a constant value as an input
179
BizTalk Mapping Patterns and Best Practices
The next step is to calculate the “DiscountAmount” for that we need to:
Drag from the Toolbox window two Scripting Functoids and then:
o In the first scripting Functoid we will create a C# function to calculate base on the total amount and the
discount percentage the total discount amount
Drag a link from the Cumulative Sum Functoid, that we earlier linked to the “Amount” element in
the destination schema, to the Scripting Functoid
Drag a link from the Value Mapping Functoid, that we earlier in the “True” segment of the discount
condition, to the Scripting Functoid
Drag a link from the Scripting Functoid to the “DiscountAmount” element in the destination schema
o In the second scripting Functoid we will specify the C# function create above to calculate base on the total
amount and the discount percentage the total discount amount
180
BizTalk Mapping Patterns and Best Practices
Drag a link from the Cumulative Sum Functoid, that we earlier linked to the “Amount” element in
the destination schema, to the Scripting Functoid
Drag a link from the Value Mapping Functoid, that we earlier in the “False” segment of the discount
condition, to the Scripting Functoid
Drag a link from the Scripting Functoid to the “DiscountAmount” element in the destination schema
What we are seeing is that we need to duplicate each operation that we must do under the discount condition, one
for the “True” statement and one for the “False” statement.
Finally the next step is to calculate the “TotalAmount” and for that we will use the same approach describe in the step
above for the “DiscountAmount” element:
Drag from the Toolbox window two Scripting Functoids and then:
o In the first scripting Functoid we will create a C# function to calculate base on the total amount and the
discount percentage the total amount with discount
Drag a link from the Cumulative Sum Functoid, that we earlier linked to the “Amount” element in
the destination schema, to the Scripting Functoid
Drag a link from the Value Mapping Functoid, that we earlier in the “True” segment of the discount
condition, to the Scripting Functoid
Drag a link from the Scripting Functoid to the “TotalAmount” element in the destination schema
o In the second scripting Functoid we will specify the C# function create above to calculate base on the total
amount and the discount percentage the total discount amount
181
BizTalk Mapping Patterns and Best Practices
Drag a link from the Cumulative Sum Functoid, that we earlier linked to the “Amount” element in
the destination schema, to the Scripting Functoid
Drag a link from the Value Mapping Functoid, that we earlier in the “False” segment of the discount
condition, to the Scripting Functoid
Drag a link from the Scripting Functoid to the “TotalAmount” element in the destination schema
From a developer’s perspective, despite requires a little effort developing the if-else-statement, this is very straight
forward approach and can easily be implement by beginners or expert developers in small messages, this approach as
several limitation or disadvantages:
Development and Maintainability: From a developer’s and maintenance perspective this approach can be a
challenger when dealing with larger messages or with several condition. We easily fill the maps with huge amount
of Functoid to archive easy tasks. Also we need to be careful with the duplication of several Scripting Functoid.
o Usually developer’s copy the entire content of the scripting Functoid to use in other one. This is a bad
approach because we easily end up with different code inside both or it will force us to be careful to update
every single Functoid. The best approach in this case is to use only the function declaration syntax.
Lack of performance: Although this can be a good approach for small messages, this approach comes with little
performance hit. If we analyze the XSLT regenerated by the BizTalk mapping engine we will see that for each time
we use the Cumulative Sum Functoid it will be one for-each element to recalculate to total amount, so in this
scenario it will calculate 3 times the total amount unnecessarily.
Readability: In big map transformation this can be more difficult to read and to maintain because we can easily fill
the maps with huge amount of Functoid.
Level of effort: by being more difficult to read and maintain the maps and for all the care that we must have in the
orchestrations development this will increase the development time.
182
BizTalk Mapping Patterns and Best Practices
And drag a link from the Scripting Functoid to the Concatenate Functoid. Then select this link and
go to his properties:
Set the “Label” property as: “Discount percentage value”
Double click in the Concatenate Functoid and then:
Click in the add button to add a constant value as an input
Set the value of the new input as “%”
183
BizTalk Mapping Patterns and Best Practices
And drag a link from the Concatenate Functoid to the “DiscountPercent” element in the destination
schema
In order to calculate the “DiscountAmount” we need to:
o Drag from the Toolbox window one Scripting Functoid and then
This scripting Functoid is for create a C# function to calculate base on the total amount and the
discount percentage the total discount amount
Drag a link from the Cumulative Sum Functoid, that we earlier linked to the “Amount” element in
the destination schema, to the Scripting Functoid
Then select this link and go to his properties and set the “Label” property as: “Amount
value”
Drag a link from the Scripting Functoid that we create earlier containing the function
GetDiscountValue to this new Scripting Functoid
Then select this link and go to his properties and set the “Label” property as: “Discount
percentage value”
And drag a link from the Scripting Functoid to the “DiscountAmount” element in the destination
schema
In order to calculate the “TotalAmount” we will apply the same steps described in the previous step but with a
different C# function:
o Drag from the Toolbox window one Scripting Functoid and then
This scripting Functoid is for create a C# function to calculate base on the total amount and the
discount percentage the total discount amount
Drag a link from the Cumulative Sum Functoid, that we earlier linked to the “Amount” element in
the destination schema, to the Scripting Functoid
Then select this link and go to his properties and set the “Label” property as: “Amount
value”
Drag a link from the Scripting Functoid that we create earlier containing the function
GetDiscountValue to this new Scripting Functoid
Then select this link and go to his properties and set the “Label” property as: “Discount
percentage value”
184
BizTalk Mapping Patterns and Best Practices
And drag a link from the Scripting Functoid to the “TotalAmount” element in the destination
schema
Development, Maintainability and Readability: From a developer’s and maintenance perspective this approach
can be easier to developer and to maintain by new and even for expert developers, or even when working with
developers from other teams.
Level of effort: by being easier to read and maintain you will reduce the development time.
Lack of performance: Although this can be a good approach for small messages, this approach comes with little
performance hit. If we analyze the XSLT regenerated by the BizTalk mapping engine we will see that for each time
we use the Cumulative Sum Functoid it will be one for-each element to recalculate to total amount, so in this
scenario it will calculate 3 times the total amount unnecessarily.
You must understand the in certain scenarios this is impossible and we must rely on custom XSLT to solve your
transformations problems. However this is not the case, and we can easily accomplish that by using the concept of a
global variable inside the map and two extra Scripting Functoids with custom C#.
The first change that we need to do is for calculating the “Amount” element:
Drag from the Toolbox window two Scripting Functoid, one Multiplication Functoid and one Cumulative Sum
Functoid and then:
185
BizTalk Mapping Patterns and Best Practices
o Drag a link from the “ItemCustomerCode” element in the source schema to the Scripting Functoid
This scripting Functoid it will have the exact same code of the previous solutions.
o And drag a link from the Scripting Functoid to the Multiplication Functoid
Drag a link from the “TotalAmount” element in the source schema to the Multiplication Functoid
Drag a link from the “Multiplication Functoid to the Cumulative Sum Functoid
Drag a link from the Cumulative Sum Functoid to the second Scripting Functoid
o This scripting Functoid is for create a C# function to create and assign the correct value of the amount
variable and to return the same value back.
o Double click in the Scripting Functoid and specify the scripting type as “Inline C#”
o In the Inline script put the following code:
int amount = 0;
Drag a link from second Scripting Functoid to the “Amount” element in the destination schema
The second change that we need to do is for calculating the “DiscountAmount” and “TotalAmount” elements:
Instead of link the Cumulative Sum Functoid to the Scripting Functoids that are responsible for calculating the value
of these elements, which lead to multiple for-each statements, we will replace them for an additional Scripting
Functoid.
o This scripting Functoid is for create a C# function to get the correct value of the global variable “amount”.
o Double click in the Scripting Functoid and specify the scripting type as “Inline C#”
o In the Inline script put the following code:
Drag a link from this Scripting Functoid to the Scripting Functoids that are responsible for calculating both elements.
186
BizTalk Mapping Patterns and Best Practices
Performance: From all the solutions presented this is the solution with less performance loss and less issues.
Of course this can be improve a little more, if we make the entire "Totals" record mapping using custom XSLT, however
the benefits are so few, so insignificant, that I will not even address this approach and also not to mention the
disadvantages that we would have.
Resources
All source code is available in the Microsoft Code gallery here: BizTalk Mapper Patterns: Working With
Multiple Output Messages (Splitting Msgs) (http://code.msdn.microsoft.com/BizTalk-Mapper-
Patterns-cb32576d)
Grouping Pattern
Grouping is a common pattern in transformations, when exchanging messages between different systems sometimes
we need to make data aggregations based on message content or other criteria. Sometimes systems expect that
information to be passed grouped by certain parameters, for example:
Shopping catalogue where items are compiled together under headings such as 'home', 'sport & leisure', 'women's
clothes' and so on;
All rows in an order request grouped by a certain product type
Or sometimes we need to make mathematic operations base on a certain parameter, for example: the total cost
of all invoice request by different taxes type (VAT / ACT / EP / REE / DA / VP / EL / AAA).
187
BizTalk Mapping Patterns and Best Practices
Grouping operations is a common problem in XSLT style sheets, and is really simple to accomplish using XSLT 2.0
however using XSLT 1.0 can be a challenger trying to accomplish the end result and at the same time keep your eyes
on performance.
Making available instruction like xsl:for-each-group for iteration across a series of groups and with the possibility
for setting criteria for grouping: group-by, group-adjacent, group-starting-with, or group-ending-with, or even
by using distinct-values(…) function: <xsl:for-each select="distinct-values(…)">. XSLT 2.0 makes grouping
really easy and optimized. The main problem is that BizTalk Server only supports XSLT 1.0.
One of the more challenging things to do in XSL 1.0 is grouping and sorting operation. XSLT 1.0 lets you sort elements,
however, it will force you to jump through several hoops to do anything extra with the groups that result from the
sort. For accomplish this we need to use custom XSLT and there is no simple syntax to write this type of XPath query
in XSL 1.0.
When grouping nodes, we also think in sort things to get them into a certain order, then we group all items that have
the same value for the sort key (or keys). We'll use xsl:sort for this grouping, then use variables or functions like
key() or generate-id() to finish the job.
Basically, the expression checks the value of every preceding-sibling and returns “True” when none of the preceding-
sibling elements has the same value that we are validating or “False” otherwise. This expression is used in conjunction
with xsl:for-each element.
The xsl:for-each element will loop through the first occurrence of each unique grouping value and the preceding-
sibling expression will validate the previous existence, emulating this way the existence of a list of unique values.
This algorithm is not efficient for large messages but work well for ‘normal’ messages. For large messages Muenchian
method is generally more efficient than using preceding-sibling.
The trouble with this method is that it involves two XPaths that take a lot of processing for big XML sources. Searching
through all the preceding siblings with the 'preceding-siblings' axis takes a long time if you're near the end of the
records. Similarly, getting all the elements with a certain values involves looking at every single element each
time. This makes it very inefficient.
188
BizTalk Mapping Patterns and Best Practices
Input Output
<ns0:ExternalEmployees <ns0:ListPartners
xmlns:ns0="http://SelectDistinctValues.Input"> xmlns:ns0="http://SelectDistinctValues.Output1">
<Employee> <PartnerName>DevScope</PartnerName>
<Name>Sandro Pereira</Name> <PartnerName>DemoCompany2</PartnerName>
<Company>DevScope</Company> <PartnerName>DemoCompany</PartnerName>
</Employee> </ns0:ListPartners>
<Employee>
<Name>DemoEmployee2</Name>
<Company>DemoCompany2</Company>
</Employee>
<Employee>
<Name>Rui Barbosa</Name>
<Company>DevScope</Company>
</Employee>
<Employee>
<Name>DemoEmployee</Name>
<Company>DemoCompany</Company>
</Employee>
</ns0:ExternalEmployees>
Grouping operation need to be implement using custom XSLT code, using a Scripting Functoid or using a custom
External XSLT File, because they cannot be accomplished using base Functoids.
So the first thing we need to do is to drag a Scripting Functoids onto the Grid. Then drag a line to the element that we
want to create output for.
To create the output in the format that we want we will start with the following XSLT.
<!-- This creates variable named unique-companies and populates with a list of unique companies
nodes. -->
<xsl:variable name="unique-companies" select="//Employee[not(Company=preceding-
sibling::Employee/Company)]/Company" />
<!-- Now we need to start the output of our nodes and then loop through the companies -->
<xsl:for-each select="$unique-companies">
<PartnerName>
<xsl:value-of select="." />
</PartnerName>
</xsl:for-each>
By testing our map using the XML instance provided earlier, we can confirm that the output is validate and according
to the expected:
189
BizTalk Mapping Patterns and Best Practices
<ns0:ListPartners xmlns:ns0="http://SelectDistinctValues.Output1">
<PartnerName>DevScope</PartnerName>
<PartnerName>DemoCompany2</PartnerName>
<PartnerName>DemoCompany</PartnerName>
</ns0:ListPartners>
<In>
<Data Header="AAA" date="2008-10-28" Name="a1" Value="1.0" />
<Data Header="AAA" date="2008-10-28" Name="a2" Value="2.0" />
<Data Header="AAA" date="2008-10-28" Name="a3" Value="3.0" />
<Data Header="BBB" date="2008-10-28" Name="a1" Value="1.0" />
<Data Header="BBB" date="2008-10-28" Name="a2" Value="2.0" />
<Data Header="BBB" date="2008-10-28" Name="a3" Value="3.0" />
</In>
We need to join all the same Headers and combine all the name and values inside a unique Record:
<Data>
<Header>AAA</Header>
<date>2008-10-28</date>
<Record>
<Name>a1</Name>
<Value>1.0</Value>
<Name>a2</Name>
<Value>2.0</Value>
<Name>a3</Name>
<Value>3.0</Value>
</Record>
<Header>BBB</Header>
<date>2008-10-28</date>
<Record>
<Name>a1</Name>
<Value>1.0</Value>
<Name>a2</Name>
<Value>2.0</Value>
<Name>a3</Name>
<Value>3.0</Value>
</Record>
</Data>
The logic is that you have to get the distinct values from Header, and then for all this distinct values select all element
from this particular value, in this sample all element that have AAA in Header and then all BBB.
<xsl:template name="NameValueTemplate">
190
BizTalk Mapping Patterns and Best Practices
The second Scripting Functoid we will select all distinct Header an call the template for each header
And we apply this technique with different and multiple types of script’s to implement all the transformation rules. If
we take another example we have several person’s that can have multiple citizenships (nationality) and emails:
<ns0:Persons xmlns:ns0="http://SelectDistinctValues.InputPersons">
<Person>
<Name>Sandro Pereira</Name>
<Nationality>Portuguese</Nationality>
<Email>sandro@email</Email>
</Person>
<Person>
<Name>Person1</Name>
<Nationality>Portuguese</Nationality>
<Email>email1@email</Email>
</Person>
<Person>
<Name>Person1</Name>
<Nationality>English</Nationality>
<Email>email2@email</Email>
</Person>
<Person>
<Name>Person2</Name>
<Nationality>Portuguese</Nationality>
<Email>email@email</Email>
</Person>
</ns0:Persons>
191
BizTalk Mapping Patterns and Best Practices
And we want to group them by the name in a single record but getting:
<ns0:Persons xmlns:ns0="http://SelectDistinctValues.OutputPersons">
<Person>
<Name>Sandro Pereira</Name>
<Nationality>Portuguese</Nationality>
<Email>sandro@email</Email>
</Person>
<Person>
<Name>Person1</Name>
<Nationality>Portuguese</Nationality>
<Nationality>English</Nationality>
<Email>email2@email</Email>
</Person>
<Person>
<Name>Person2</Name>
<Nationality>Portuguese</Nationality>
<Email>email@email</Email>
</Person>
</ns0:Persons>
<xsl:template name="NationalityTemplate">
<xsl:param name="param1" />
<xsl:for-each select="//Person[Name=$param1]">
<xsl:element name="Nationality">
<xsl:value-of select="Nationality" />
</xsl:element>
</xsl:for-each>
</xsl:template>
The second Scripting Functoid we will created a template that get all citizenships and create multiple “Nationality”
elements.
o This Functoid will not have any kind of inputs or output and will serve to create the concept of a global
template that will be called by the XSLT code that will be inside the second Scripting Functoid.
<xsl:template name="EmailTemplate">
<xsl:param name="paramName" />
<xsl:for-each select="//Person[Name=$paramName]">
<!-- Validate if is the last occurrence of a specific person. If true it will map the email,
this way getting the last email occurrence -->
<xsl:if test="position()=last()">
192
BizTalk Mapping Patterns and Best Practices
<xsl:element name="Email">
<xsl:value-of select="Email" />
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:template>
The second Scripting Functoid we will select all distinct Header an call the template for each header
<!-- This will loop through each different Person present in the input message -->
<xsl:for-each select="//Person[not(Name=preceding-sibling::Person/Name)]">
<xsl:element name="Person">
<xsl:element name="Name">
<xsl:value-of select="Name" />
</xsl:element>
<!-- Call the template to get the Nationality -->
<xsl:call-template name="NationalityTemplate">
<xsl:with-param name="param1" select="string(Name)" />
</xsl:call-template>
<!-- Call the template to get the Email -->
<xsl:call-template name="EmailTemplate">
<xsl:with-param name="paramName" select="string(Name)" />
</xsl:call-template>
</xsl:element>
</xsl:for-each>
Resources
All source code is available in the Microsoft Code gallery here: BizTalk Mapper Patterns: Selecting
distinct nodes (grouping) (http://code.msdn.microsoft.com/BizTalk-Mapping-Selecting-61386ea0)
Keys work by assigning a key value to a node and giving you easy access to that node through the key value. If there
are lots of nodes that have the same key value, then all those nodes are retrieved when you use that key
value. Effectively this means that if you want to group a set of nodes according to a particular property of the node,
then you can use keys to group them together.
The <xsl:key> element is a top-level element which declares a named key that can be used in the style sheet with the
key() function that has the following syntax:
193
BizTalk Mapping Patterns and Best Practices
Where the:
You can find a really fine explanation by Jeni Tennison here: Grouping Using the Muenchian Method
(http://jenitennison.com/xslt/grouping/muenchian.html)
Note
The solutions that I will explain are based on Chris Romp sample, so I will lightly explain the requirements and put
part of the Chris Romp post content here.
Let's say we have an input schema that contains the sales order information. However, for each line, we repeat the
sales header info (in this case it's just "OrderID," but typically this would include customer info, order date, etc.) again
and again:
However, in our destination schema, we want to group the line data for each header, and we want to sort it, too.
Here's the destination schema we need to use.
Input Output
<Order> <Order>
<OrderId>1</OrderId> <OrderId>1</OrderId>
<ItemId>1001</ItemId> <Items>
</Order> <ItemId>1001</ItemId>
<Order> <ItemId>1002</ItemId>
<OrderId>1</OrderId> <ItemId>1003</ItemId>
<ItemId>1002</ItemId> </Items>
194
BizTalk Mapping Patterns and Best Practices
</Order> </Order>
<Order> <Order>
<OrderId>1</OrderId> <OrderId>2</OrderId>
<ItemId>1003</ItemId> <Items>
</Order> <ItemId>1001</ItemId>
<Order> </Items>
<OrderId>2</OrderId> </Order>
<ItemId>1001</ItemId> <Order>
</Order> <OrderId>3</OrderId>
<Order> <Items>
<OrderId>3</OrderId> <ItemId>1000</ItemId>
<ItemId>1000</ItemId> </Items>
</Order> </Order>
Create a new BizTalk map, and then steal its XSLT to use as a template. This way we know the namespaces and
such are correct.
Right-click on the map and choose "Validate," then steal the output ".xsl" file.
Then click on the Functoid grid on the graphical map, and set the Custom XSL Path property to your saved .xsl file.
Within the custom XSLT, we're going to be implementing the Muenchian Method technique to solve this problem.
In the end the custom XSLT will look something like this:
<xsl:template match="/">
<xsl:apply-templates select="/s0:OrdersFF" />
195
BizTalk Mapping Patterns and Best Practices
</xsl:template>
<xsl:template match="/s0:OrdersFF">
<ns0:orders>
</items>
</order>
</xsl:for-each>
</ns0:orders>
</xsl:template>
</xsl:stylesheet>
However, this approach has one huge limitation, by creating and configures Custom XSL Path we lose all mapping
features.
Inspired by Chris Romp solution I struggled to be able to implement this same technique without losing the BizTalk
Mapper functionalities, because in some cases we want to be able to implement Muenchian Method to group a
segment of the message and then use the mapper to transform the rest of the segments.
Muenchian Method inside the Mapper without losing BizTalk Mapper functionalities
First approach
When trying to find a way to implement this technique inside the BizTalk mapper we always think why not try to put
all the XSLT code inside of one Inline XSLT Functoid by:
Drag-and-drop a Scripting Functoid to the map without any input and link this Functoid to the Order record on the
destination schema.
196
BizTalk Mapping Patterns and Best Practices
Double-click in the Scripting Functoid, select the "Scripting Functoid Configuration" tab
Select the script type as: Inline XSLT and past the following code to the Inline script window.
The problem with this approach is that it fails generating the following error:
XSLT compile error at (9,8). See InnerException for details. ‘xsl:key’ cannot be a child of the ‘ns0:OutputOrder’
element.
Because xsl:key element cannot be placed inside the xsl:template segment. So, to avoid this error we need to
separate from the rest of the XSL the “<xsl:key name="groups" match="Order" use="OrderId"/>” code to a
different Scripting Functoid (see second approach)
Second Approach
As explained above, the second approach: Was to try to separate “<xsl:key name="groups" match="Order"
use="OrderId"/>” expression from the rest of the XSL so that we can use this technique inside the BizTalk Mapper
and avoid this way to use an external custom XSL file. To accomplish that we need to:
The second Scripting Functoid will not have any kind of inputs and link this Functoid to the Order record on the
destination schema
o In the second Scripting Functoid, configure to an “Inline XSLT” and the rest of the XSL.
197
BizTalk Mapping Patterns and Best Practices
</OrderId>
<Items>
<!-- Another loop... -->
<xsl:for-each select="key('groups',OrderId)">
<ItemId>
<xsl:value-of select="ItemId" />
</ItemId>
</xsl:for-each>
</Items>
</Order>
</xsl:for-each>
<ns0:InputOrder xmlns:ns0="http://MuenchianGrouping.InputOrder">
<Order>
<OrderId>1</OrderId>
<ItemId>1001</ItemId>
</Order>
<Order>
<OrderId>1</OrderId>
<ItemId>1002</ItemId>
</Order>
<Order>
<OrderId>1</OrderId>
<ItemId>1003</ItemId>
</Order>
<Order>
<OrderId>2</OrderId>
<ItemId>1001</ItemId>
</Order>
<Order>
<OrderId>3</OrderId>
<ItemId>1000</ItemId>
</Order>
</ns0:InputOrder>
We will see the desired final output, but this time implemented inside the BizTalk Mapper without losing any Mapper
functionality:
<ns0:OutputOrder xmlns:ns0="http://MuenchianGrouping.OutputOrder">
<Order>
<OrderId>1</OrderId>
<Items>
<ItemId>1001</ItemId>
<ItemId>1002</ItemId>
<ItemId>1003</ItemId>
</Items>
</Order>
198
BizTalk Mapping Patterns and Best Practices
<Order>
<OrderId>2</OrderId>
<Items>
<ItemId>1001</ItemId>
</Items>
</Order>
<Order>
<OrderId>3</OrderId>
<Items>
<ItemId>1000</ItemId>
</Items>
</Order>
</ns0:OutputOrder>
But can we still can improve a little more this solution? (See final approach)
Final Approach
When leading with large files, speed processing is vital. The classical Muenchian grouping use generate-id() Function
that returns a string value that uniquely identifies a specified node, however, using generate-id() Function is slowest
that using count() function, and shows worst scalability. Probably the reason is poor generate-id() function
implementation. In other words, count() function performs is much better.
Here some performance stats that I found in Oleg Tkachenko's blog post:
http://www.tkachenko.com/blog/archives/000401.html
So to improve Muenchian a little more we have to use count() function instead of generate-id():
199
BizTalk Mapping Patterns and Best Practices
<xsl:for-each select="Order[generate-id(.)=generate-id(key('groups',OrderId))]">
You can read more about the problem in the thread, but basically the problem is: We need to sum all the records and
create a unique record for records containing the same account type and city.
The question that arises is: How can we can we perform multi-level grouping in Muenchian Method inside BizTalk
Mapper? And in this case perform some mathematical operations on this group?
In the previous examples we were performing grouping by only one element from the record and we were specifying
this element on the key function in the attribute use has explained earlier:
To be able to use several element we can make use of the concat(string,string,…) function that will returns a
concatenation of the element values that we want to combine in our multi-level grouping.
o In the second Scripting Functoid, we will configure to an “Inline XSLT” and place the rest of the XSLT code:
<!-- This will loop through our key of Cities and Account Types -->
<xsl:for-each select="Record[generate-id(.)=generate-id(key('groups',concat(City, '|',
AccountType)))]">
<Record>
<!-- read and set two variables with an unique City and Account Type -->
<xsl:variable name="city" select="City/text()" />
<xsl:variable name="type" select="AccountType/text()" />
<!-- Filling the element AccountType and City with the respective values -->
<AccountType>
<xsl:value-of select="$type" />
</AccountType>
<City>
<xsl:value-of select="$city" />
</City>
<!-- We are making the sum of all the Price values that exist in all records where the City and
200
BizTalk Mapping Patterns and Best Practices
the AccountType are equal to the previously values that we read and whose Sign is negative -->
<xsl:variable name="negativeTotal" select="sum(//Record[(City = $city) and (AccountType = $type)
and (Sign = '-')]/Price)" />
<!-- The same but this time where the Sign is positive -->
<xsl:variable name="positiveTotal" select="sum(//Record[(City = $city) and (AccountType = $type)
and (Sign = '+')]/Price)" />
<xsl:choose>
<!-- Comparing if the positiveTotal is great than the negativeTotal so that we can correctly
subtract them and decide if the difference is positive or negative -->
<xsl:when test="$positiveTotal > $negativeTotal">
<Sign>+</Sign>
<Price>
<xsl:value-of select="$positiveTotal - $negativeTotal" />
</Price>
</xsl:when>
<xsl:otherwise>
<Sign>-</Sign>
<Price>
<xsl:value-of select="$negativeTotal - $positiveTotal" />
</Price>
</xsl:otherwise>
</xsl:choose>
</Record>
</xsl:for-each>
o Drag a link from the second Scripting Functoid to the record “Record” in the destination schema;
Conclusion
Both, Chris Romp and mine (of course mine was inspired in Chris Romp solution), are great solutions and both can be
implemented in different scenarios. However, and this is my personal opinion, I try to avoid using external XSL files.
Even if using custom-XSLT will have much better performance because it’s clean code without junky XSLT code produce
by the compiler, I only recommend do the all map problem with only custom-XSLT if you are dealing with huge message
and High Performance is our or one of the primary requirements, for me this is the only exception to the rule,
otherwise you should use the BizTalk Mapper and have a mix of Custom-XSLT and Functoids, why?
Maintainability and Readability: I don’t agree that very large transformations can be difficult to read and maintain
in BizTalk Mapper because you can also because we can also use a custom XSLT to solve and simplify more elaborate
and complex rules, and again in this case we have the best of both worlds. And they can be really easy to read and
understand if you apply some of the best practices in organization and documentation inside maps.
Level of effort: For a new BizTalk developer to troubleshoot and/or change an existing map it will more easy to do
using BizTalk Mapper rather than troubleshoot and/or change and entire custom-XSLT file without a visual
201
BizTalk Mapping Patterns and Best Practices
representation. Also, when working with developers from other teams of business users the visual aspect can make
it easy to work with them to develop the mappings
Overview. If a new BizTalk developer opens up a map and see only a blank page without any Functoid, he will
probably think that someone forgot to check in the latest version in the source safe or simply forgot to implement
this map. And after some hours he will understand that there is defined in properties of the map an external file
with all your transformation rules. Really annoying.
Resources
Reference to this pattern:
All source code is available in the Microsoft Code gallery here: Muenchian Grouping and Sorting in
BizTalk Maps without losing Map functionalities (http://code.msdn.microsoft.com/Muenchian-
Grouping-and-790347d2)
Sorting Pattern
The Sorting Pattern is used to sort the contents of a message body to get them into a certain order, assuming that the
message body contains a list of items that can be sorted. Most of the times are bounded with the Grouping Pattern
and like the previous one, there is no way to simple implement this operation without using Custom XSLT code and in
fact there isn’t also a simple syntax to write this type of XPath query in XSLT 1.0.
XSLT 1.0 lets you sort elements, however, it will force you to jump through several hoops to do anything extra with
the groups that result from the sort and for accomplish this we need to use custom XSLT inside the BizTalk Mapper.
Sorting is a way of manage the randomly data in sequence and basically we can have two types of sorting:
Ascending Sort: is find the smallest number or first letter of the dictionary in the array and placed on first position
and the highest number or last letter of the dictionary and placed on the last position;
And Descending Sort: it’s the opposite, it will find the highest number or last letter of the dictionary in the array
and placed on first position and smallest number or first letter of the dictionary placed on the last position;
For accomplish this task we’ll need to use the XSLT <xsl:sort> element that has the following syntax:
202
BizTalk Mapping Patterns and Best Practices
Where the:
All attributes are optional and the normal use of this element should be.
<ns0:Persons xmlns:ns0="http://BizTalkMapperSortingPattern.Persons">
<Person>
<Name>Sandro Pereira</Name>
<Nacionality>Portuguese</Nacionality>
<ListCountriesVisited>
<Country>Italy</Country>
<Country>Norway</Country>
</ListCountriesVisited>
</Person>
<Person>
<Name>José António Silva</Name>
<Nacionality>Portuguese</Nacionality>
<ListCountriesVisited>
<Country>Irland</Country>
<Country>Spain</Country>
</ListCountriesVisited>
</Person>
</ns0:Persons>
As a developer the first approach we think is to try to solve this mapping problem using only the available Functoids,
i.e. without custom XSLT or custom C# code. I quickly discarded this option and you will see why.
To try to solve this mapping problem using this approach, we just need to:
Drag the mouse from the root name “Person” in the source schema, and then drop it to root name “Person” in the
destination schema.
203
BizTalk Mapping Patterns and Best Practices
Here we are simple making an exact copy of the source to the destination schema, so we need to implement some
technique to order the message based on the fields that we want.
So the first thing that you may think is the rule of the link sequence:
The BizTalk mapping engine traverses the destination schema from beginning to end;
The mapping rules are constructed and executed as links are encountered in the destination schema;
So we can simple link a scripting Functoid with the sort element expression inside to the “Person” record:
204
BizTalk Mapping Patterns and Best Practices
However If we run a quick validation into our map by right-clicking the map name and select “Validate Map” option:
We will notice that the BizTalk Mapper engine will refactor the code in a different way that we expect, instead to put
the <xsl:sort> element just before the <xsl:for-each> element
<xsl:for-each select="Person">
<xsl:sort select="Name" order="ascending" />
<Name>
<xsl:value-of select="Name/text()" />
</Name>
…
He actually put in the end of the <xsl:for-each> element. This happens because as we explained in the
<NS0:PEOPLETARGET XMLNS:NS0="HTTP://HOWMAPSWORKS.PEOPLETARGET">
<PERSON>
<Name>Jose Antonio</Name>
<Sex>M</Sex>
</Person>
<Person>
<Name>Rui Barbosa</Name>
<Sex>M</Sex>
</Person>
<Person>
<Name>Sandro Pereira</Name>
205
BizTalk Mapping Patterns and Best Practices
<Sex>M</Sex>
</Person>
<Person>
<Name>Elsa Ligia</Name>
<Sex>F</Sex>
</Person>
<Person>
<Name>Pedro Lamas</Name>
<Sex>M</Sex>
</Person>
</ns0:PeopleTarget>
The exception to the rule of Link Sequence: Process links out of order section, when we are using Scripting Functoids
in a Record element this links are processed out of order, i.e., all the child’s links/rules are processed first and only
then the links/rules of the father are processed.
Sorting data inside BizTalk maps is a common requirement, normally these scenarios require that data be sorted by a
number, an id or simple a field element that unique identify an object. This is a simple task, however you simple don’t
any way to implement them without using Custom XSLT inside the mapper.
Second approach: Using Scripting Functoid with Inline Custom XSLT code
Taking the same example explained above, to simple solve this problem we could copy all the <xsl:for-each
select="Person"> section, place the <xsl:sort> element in the correct position (right before the <xsl:for-each>
element) and copy the XSLT code to a Scripting Functoid.
Drag one Scripting Functoid from the Toolbox window onto the Grid.
o Double-click in the Scripting Functoid to show the Properties window, then:
Select the “Script Functoid Configure” tab, and then choose “Inline XSLT” as your selected script
type
In the “Inline script” text box enter the following XSLT code:
<xsl:for-each select="Person">
<!-- Order the Person records by the element Name in an ascending way (A...Z) -->
<xsl:sort select="Name" order="ascending" />
<Person>
<Name>
<xsl:value-of select="Name/text()" />
</Name>
<Nacionality>
<xsl:value-of select="Nacionality/text()" />
</Nacionality>
<xsl:for-each select="ListCountriesVisited">
<ListCountriesVisited>
<xsl:for-each select="Country">
<!-- Order the Country elements in an descending way (Z...A) -->
<xsl:sort select="." order="descending" />
<Country>
<xsl:value-of select="./text()" />
</Country>
</xsl:for-each>
<xsl:value-of select="./text()" />
206
BizTalk Mapping Patterns and Best Practices
</ListCountriesVisited>
</xsl:for-each>
<xsl:value-of select="./text()" />
</Person>
</xsl:for-each>
Sorting Numbers
In this sample both sort operations are being done by text elements, the name and the country, however if for some
reason we need to perform sort operation using a number, let’s say that in the sample above implement a small change
to the schema and now each Person has an attribute call "Id" and we want to order all the people in an ascending way
by this attribute:
Input Output
<Person Id="10"> <Person Id="8">
<Name>Sandro Pereira</Name> <Name>Márcia Teixeira</Name>
<Nacionality>Portuguese</Nacionality> <Nacionality>Portuguese</Nacionality>
<ListCountriesVisited> <ListCountriesVisited>
<Country>Italy</Country> <Country>USA</Country>
<Country>Spain</Country> <Country>Spain</Country>
</ListCountriesVisited> </ListCountriesVisited>
</Person> </Person>
<Person Id="8"> <Person Id="10">
<Name>Márcia Teixeira</Name> <Name>Sandro Pereira</Name>
<Nacionality>Portuguese</Nacionality> <Nacionality>Portuguese</Nacionality>
<ListCountriesVisited> <ListCountriesVisited>
<Country>Spain</Country> <Country>Spain</Country>
<Country>USA</Country> <Country>Italy</Country>
</ListCountriesVisited> </ListCountriesVisited>
</Person> </Person>
<Person Id="12"> <Person Id="12">
<Name>José António Silva</Name> <Name>José António Silva</Name>
<Nacionality>Portuguese</Nacionality> <Nacionality>Portuguese</Nacionality>
<ListCountriesVisited> <ListCountriesVisited>
<Country>Irland</Country> <Country>Irland</Country>
</ListCountriesVisited> </ListCountriesVisited>
</Person> </Person>
In this case, the most important change we would have to do is to change the <xsl:sort> element expression to use
this new attribute and to specify that the data-type of the data that we want to be sorted is a number:
<xsl:for-each select="Person">
<xsl:sort select="@Id" data-type="number" order="ascending" />
<Person>
207
BizTalk Mapping Patterns and Best Practices
<!-- Check if Id is present, but in the context of this problem this if condition is
unnecessary -->
<xsl:if test="@Id">
<xsl:attribute name="Id">
<xsl:value-of select="@Id" />
</xsl:attribute>
</xsl:if>
<Name>
<xsl:value-of select="Name/text()" />
</Name>
<Nacionality>
<xsl:value-of select="Nacionality/text()" />
</Nacionality>
<xsl:for-each select="ListCountriesVisited">
<ListCountriesVisited>
<xsl:for-each select="Country">
<!-- Order the Country elements in an descending way (Z...A) -->
<xsl:sort select="." order="descending" />
<Country>
<xsl:value-of select="./text()" />
</Country>
</xsl:for-each>
<xsl:value-of select="./text()" />
</ListCountriesVisited>
</xsl:for-each>
</Person>
</xsl:for-each>
<ns0:Orders xmlns:ns0="http://BizTalkMapperSortingPattern.Order">
<Order OrderId="2">
<ProductId>10</ProductId>
<ProductName>BizTalk Server Enterprise License</ProductName>
<Quantity>1</Quantity>
</Order>
<Order OrderId="1">
<ProductId>10</ProductId>
<ProductName>BizTalk Server Enterprise License</ProductName>
<Quantity>5</Quantity>
</Order>
<Order OrderId="1">
<ProductId>9</ProductId>
<ProductName>SQL Server Enterprise License</ProductName>
<Quantity>2</Quantity>
</Order>
<Order OrderId="3">
<ProductId>1</ProductId>
<ProductName>Windows Server 2013 License</ProductName>
<Quantity>1</Quantity>
</Order>
<Order OrderId="3">
<ProductId>2</ProductId>
<ProductName>Windows Azure BizTalk Services Subscription</ProductName>
208
BizTalk Mapping Patterns and Best Practices
<Quantity>1</Quantity>
</Order>
</ns0:Orders>
And we want to sort all the Order records by: “Id” followed by “ProductId”.
<ns0:Orders xmlns:ns0="http://BizTalkMapperSortingPattern.Order">
<Order OrderId="1">
<ProductId>9</ProductId>
<ProductName>SQL Server Enterprise License</ProductName>
<Quantity>2</Quantity>
</Order>
<Order OrderId="1">
<ProductId>10</ProductId>
<ProductName>BizTalk Server Enterprise License</ProductName>
<Quantity>5</Quantity>
</Order>
<Order OrderId="2">
<ProductId>10</ProductId>
<ProductName>BizTalk Server Enterprise License</ProductName>
<Quantity>1</Quantity>
</Order>
<Order OrderId="3">
<ProductId>1</ProductId>
<ProductName>Windows Server 2013 License</ProductName>
<Quantity>1</Quantity>
</Order>
<Order OrderId="3">
<ProductId>2</ProductId>
<ProductName>Windows Azure BizTalk Services Subscription</ProductName>
<Quantity>1</Quantity>
</Order>
</ns0:Orders>
I will not specify all of the steps because they already been explained in the examples above. However this task is
extremely simples to accomplished and for that we only need to include multiple <xsl:sort> element expressions
with the details of the all the fields we want, by in the exact sequence that we want them to be order by. In this case
scenario we should implement the following code:
<xsl:for-each select="Order">
<!-- We need to include multiple <xsl:sort> element expressions with the details of all the fields
that we want to order -->
<xsl:sort select="@OrderId" data-type="number" order="ascending" />
<xsl:sort select="ProductId" data-type="number" order="ascending" />
<Order>
<xsl:attribute name="OrderId">
<xsl:value-of select="@OrderId" />
</xsl:attribute>
<ProductId>
<xsl:value-of select="ProductId/text()" />
</ProductId>
<ProductName>
<xsl:value-of select="ProductName/text()" />
</ProductName>
<Quantity>
<xsl:value-of select="Quantity/text()" />
</Quantity>
</Order>
</xsl:for-each>
209
BizTalk Mapping Patterns and Best Practices
Sort operations within grouping operations using preceding-sibling axis and Muenchian Method.
Both of this scenarios where already explained in the GROUPING PATTERN and you will find there that many of the
examples will also implement sort operations. However just to have a quick reference here about this topic I will
described the basic steps.
If we look at the example SAMPLE 1 – CREATE A LIST OF DISTINCT VALUES that we used to described HOW TO USE THE PRECEDING-
SIBLING we will see that we didn’t use any kind of sort operations. Taking the same sample, if it was necessary to order
this distinct list alphabetically, we could accomplished that by simple add the <xsl:sort> element before the
<xsl:for-each> element that includes the preceding-sibling axis.
Or simply:
<xsl:for-each select="//Employee[not(Company=preceding-sibling::Employee/Company)]/Company">
<xsl:sort select="." order="ascending" />
<PartnerName>
<xsl:value-of select="." />
</PartnerName>
</xsl:for-each>
The same approach need to be made if we are using Muenchian Method as you may see in the FIRST APPROACH sample
of MUENCHIAN METHOD INSIDE THE MAPPER WITHOUT LOSING BIZTALK MAPPER FUNCTIONALITIES
<xsl:for-each select="Order[generate-id(.)=generate-id(key('groups',OrderId))]">
<!-- And let's do some sorting for good measure... -->
<xsl:sort select="OrderId" order="ascending"/>
Key notes
Sorting data inside BizTalk maps is a common requirement. This is a simple task, however you simple don’t any way to
implement them without using Custom XSLT inside the mapper by using <xsl:sort> instruction to sort a group of
similar elements.
When you sort an element's children the <xsl:sort> instruction can be implemented inside a <xsl:apply-templates>
element:
<xsl:template match="ExternalEmployees">
<xsl:apply-templates>
<xsl:sort select="Name"/>
</xsl:apply-templates>
</xsl:template>
And the only other place you can put an <xsl:sort> instruction is inside of the <xsl:for-each> instruction used to
iterate across a node set:
210
BizTalk Mapping Patterns and Best Practices
<xsl:for-each select="$unique-companies">
<xsl:sort select="." order="ascending" />
…
</xsl:for-each>
However you should avoid this type of operations if they are not necessary because:
Level of effort and Performance: <xsl:sort> instruction will force you to jump through several hoops to do
anything extra with the groups that result from the sort operation that will impact performance and to accomplish
that we need to use custom XSLT inside the BizTalk Mapper.
Resources
Reference to this pattern:
All source code is available in the Microsoft Code gallery here: BizTalk Mapper Patterns: Sorting Pattern
(http://code.msdn.microsoft.com/BizTalk-Mapper-Patterns-3aa69244)
Conditional Pattern
Data mapping often involves decisions and when exchanging messages in an Enterprise Application Integration (EAI)
or Business-to-Business (B2B) scenario it is quite common the need to retrieve only the portion of data from the
message by some filter or under a specific condition based on some criteria. This way we need to be able to apply
Conditional Mapping technics.
Conditional mapping is a fixed condition that helps us to filter the result set that is being mapped from the source
message. A condition statement must always have an answer of true or false. However, you can use building blocks
that have results other than true or false to build a condition statement.
BizTalk Mapper will have a vast range of Functoids to perform a variety of logical operations, often controlling whether
a particular element or attribute is created in an output instance message that will include various kinds of conditions:
not only equality and inequality checks, but also checks like Greater than, Less than, if a particular Record, Field
Element, or Field Attribute exists in a particular input instance message and others. The most valuable for conditional
operations are the Logical Functoids.
Unless otherwise noted, Logical Functoids always output a Boolean value, either True or False. But they are like
“special” Functoids and you cannot directly connect the output of a Logical Functoid to other Functoid that is expecting
string input such as the uppercase Functoid, or field elements hoping to yield an output string like "TRUE". In fact
Logical Functoids can only be connected to some Advanced Functoids (like Scripting, Value Mapping, Value Mapping
211
BizTalk Mapping Patterns and Best Practices
(Flattening) or Nil Value Functoid), other Logical Functoids or Record, Field Element and Field Attribute in the
destination Schema, in this last case to control of the field is created or not.
Possible: i.e., those in which both the condition and its fulfillment are possible.
o Example: If I see him, I will tell him.
Contrary-to-fact: i.e., those in which the condition is contrary to the actual facts at the time spoken of and its
fulfillment possible only hypothetically (in imagination).
o Example: If I were rich, I’d buy a sports car. (But I’m not rich, so I’ll have to keep my old Toyota)
Doubtful or uncertain: i.e., those in which the condition and its fulfillment are possible, but are felt by the speaker
to be unlikely or doubtful.
o Example: If you should ever happen to be in New Your, you might reach me at this address.
And basically you can write the following two types of conditions:
Comparison: you can compare the value of a Field Element, Field Attribute, or the result of a method, with another
value.
o If the value contains or doesn’t contain
o If the value ends with or doesn’t end with
o if the value ends with or doesn’t end with
o If the value is equal or is not equal
o If the value is between number and number
o If the value is empty or is not empty
o If the value is more than or is at least
o is the value less than or is at most
o if the value starts with or doesn’t start with
o and so on
Existence: you can test if a Record, Field Element, or Field Attribute exists in a particular input instance message.
Check Existence
One of the most common problems that we need to deal and perform validation when we are mapping different or
similar schemas is the different and complexity types of elements properties that we can specify inside the schemas:
Is the Record, Field Element, or Field Attribute exists in a particular input instance message? Normally they are
defined as optional elements (Min Occurs (http://msdn.microsoft.com/en-us/library/aa562037.aspx) property is
set to 0)
Is the Record, Field Element, or Field Attribute nillable in a particular input instance message? In this case the
elements exists with a xsi:nil attribute to indicate that it is still valid even if it has no content (Nillable
(http://msdn.microsoft.com/en-us/library/aa547995.aspx) property is set to True)
Is the Field Element, or Field Attribute empty in a particular input instance message? Normally this are associated
string element or attributes were the element exist but as has an empty string value.
Is the Field Element, or Field Attribute contains a valid value? Sometimes we need to ensure that the elements or
attributes have a valid number or a valid string before we perform the mapping.
212
BizTalk Mapping Patterns and Best Practices
If Min Occurs property is set 0 then that element can be absent from the XML message but if it is set to 1 it has to be
present though its value can be empty. An absent element way suggests that element may not be applicable, in that
particular context, to the end system and normally we only need to send them when they exist. This is useful to reduce
the size of the document if only not all the elements are mandatory to end systems. For example we may not have all
the information of a specific client when we are register it in the system (lack of address or phone information) but
they are not significant important to stop the register process and can be added later. It depends upon the end system
as to how to deal with empty element: normally we only need to send them when they exist (if they are also optional)
but sometimes we need to specify a default values or in some cases specify then as a nillable element in the destination
schema.
In other hand, if the Nillable property is set to true, this will indicate that the value of an element in the document
may be null. This NULL values will be expressed with xsi:nil = true attribute in the element, ex:
An element with the attribute xsi:nil = true explicitly means that the value is unavailable or unknown at that moment
and sometimes the end system explicitly requires to be notified that the value of the element is NULL so that they can
take appropriate action. This is also true if certain elements doesn’t exist in the source and we need to explicitly specify
these elements with a xsi:nil = true attribute in the destination schema.
An empty element indicates that element has an empty string value. Again depending on the end system
requirements, they might take same action of both previous cases.
The most common strategy to solve this problem is by using two Functoids:
The Logical Existence Functoid to determine whether the Record, Field Element, or Field Attribute node that is
linked to it exists in a particular input instance message.
And a Value Mapping Functoid to returns the value that we want to linked based on the existence or not of the
Field Element or Field Attribute
Drag one Logical Existence Functoid from the Toolbox window onto the Grid.
213
BizTalk Mapping Patterns and Best Practices
o Drag a link from the “OptionalElement” field element in the source schema to the Logical Existence
Functoid
Drag one Value Mapping Functoid from the Toolbox window onto the Grid.
o Drag a link from the Logical Existence Functoid to the Value Mapping Functoid
o Drag a link from the “OptionalElement” field element in the source schema to the Value Mapping Functoid
o Drag a link from the Value Mapping Functoid to the “ElementExistOutput” field element in the destination
schema
Note
This is also known as the “IF…THEN CONDITION” that we will explain in more detail later in this book.
Sometimes the maps are misunderstood and notorious for producing a lot of unnecessary code that may cause a in
some cases lack of performance. So the question that we can and should ask is whether this is the best solution, or
not, to address this type of operations. To respond this question we should also inspect the generated code produce
by the BizTalk Mapper and in this case we can see that is a decent code despise the used of two extra and possible
unnecessary support variables:
<xsl:variable name="var:v1"
select="userCSharp:LogicalExistence(boolean(OptionalElementExistence/OptionalElement))" />
<xsl:if test="string($var:v1)='true'">
<xsl:variable name="var:v2" select="OptionalElementExistence/OptionalElement/text()" />
<ElementExistOutput>
<xsl:value-of select="$var:v2" />
</ElementExistOutput>
</xsl:if>
Readability: Very easy to visual read the rule, doesn’t requires any experience and very easy to implement.
Performance: This approach will produce some extra unnecessary code that will force to perform extra steps in the
operation that in the global context of the map can induce some “lack of performance” in some scenarios.
214
BizTalk Mapping Patterns and Best Practices
Note
I only reference “lack of performance” because a will compare this approach to other solutions, otherwise this is a
“decent” XSLT code.
So can we improve this solution? It’s really necessary to use the Value Mapping Functoid? Let’s try to see what happen
if we try to remove the Value Mapping Functoid and use only the Logical Existence Functoid to check if the element
exist or not and a direct link.
Drag one Logical Existence Functoid from the Toolbox window onto the Grid.
o Drag a link from the “OptionalElement2” field element in the source schema to the Logical Existence
Functoid
o Drag a link from the Logical Existence Functoid to the “ElementExistOutput2” field element in the
destination schema
Drag a link from the “OptionalElement2” field element in the source schema to the “ElementExistOutput2” field
element in the destination schema
Again, if we inspect the generated code produce by the BizTalk Mapper we can see that despise we simplify the
Mapper by using less Functoids, this not always translate to a better XSLT code:
<xsl:variable name="var:v3"
select="userCSharp:LogicalExistence(boolean(OptionalElementExistence/OptionalElement2))" />
<xsl:if test="$var:v3">
<xsl:if test="OptionalElementExistence/OptionalElement2">
<ElementExistOutput2>
<xsl:value-of select="OptionalElementExistence/OptionalElement2/text()" />
215
BizTalk Mapping Patterns and Best Practices
</ElementExistOutput2>
</xsl:if>
</xsl:if>
In this case, because we didn’t use the Value Mapping Functoid we only have one extra variable to perform the logical
existence validation, however the Mapper will generate two unnecessary conditions, one associated to the Logical
Existence Functoid and the other is associated to the direct link, why? Because this element is optional in the source
and when we perform a direct link to any other element it will automatically translate this rule to a condition.
Readability: Again, very easy to visual read the rule, doesn’t requires any experience and very easy to implement.
This is the best approach in terms of readability.
Performance: This approach will produce a bad XSLT code with unnecessary conditions which could affect the
overall performance of the map.
So if the BizTalk Mapper will automatically translate a direct link associated with an optional element to a condition,
why not using only a direct link?
When mapping optional element from the source to optional element in the destination, actually the best way in
terms of performance is to use only a direct link:
Drag a link from the “OptionalElement3” field element in the source schema to the “ElementExistOutput3” field
element in the destination schema
216
BizTalk Mapping Patterns and Best Practices
<xsl:if test="OptionalElementExistence/OptionalElement3">
<ElementExistOutput3>
<xsl:value-of select="OptionalElementExistence/OptionalElement3/text()" />
</ElementExistOutput3>
</xsl:if>
In this case we are using only one condition, as we expected, and without using any extra support variables to perform
this mapping rule.
Performance: This approach will produce a clean XSLT code without any unnecessary code and extremely efficient.
Readability: By using only a direct link we will lose some visually readability because we aren’t able to read the
logical existence condition.
In this scenario we have a record with 2 mandatory elements (string and an int value) and 1 optional element (datetime
value) that we need to map to the destination schema only if they are present in the messages and contain a valid
value. In this scenario all the destination element are optional.
We saw earlier that we do not need to use Functoids to validate the logical existence of elements, however to
validate the Data Existence we always have to use at least one Functoid.
We saw earlier that not using a Value Mapping Functoid along with the conditional (logical) Functoid will generate
additional XSLT code to perform conditions, the same rule doesn’t apply to mandatory fields or elements.
Note
This book does not aim to explain how all Logical Functoids work but if you want to learn more about them, you
can see the following Pluralsight course from Dan Toomey: Using Functoids in the BizTalk 2013 Mapper
(http://www.pluralsight.com/training/Courses/TableOfContents/using-functoids-biztalk-2013-mapper) or on the
MSDN: Logical Functoids Reference (http://msdn.microsoft.com/en-us/library/aa561635.aspx).
The first two operations: validate if the first element has a valid string and the second has a valid int, are identical, we
only need to use different Logical Functoids:
Logical String Functoid: to validate if the first element has a valid string value;
Logical Numeric Functoid: to validate if the second element has a valid int value; This is not entire true, because
we are trying to validate if the element is a valid integer and in fact this Functoid will validate if is a valid double as
we can check in the code behind the Functoid:
217
BizTalk Mapping Patterns and Best Practices
if (val == null)
{
return false;
}
double d = 0;
return Double.TryParse(val, System.Globalization.NumberStyles.AllowThousands |
System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out d);
}
o However let’s assume that this is good for us, otherwise in this case we will need to create an inline custom
code (C# or XSLT) or a custom Functoid.
Let’s take the first element (string) by example, again the most common strategy to solve this problem is by using two
Functoids: The Logical String Functoid to perform the validation and a Value Mapping Functoid to returns the value
that we want to be linked based on the previous condition.
Drag one Logical String Functoid from the Toolbox window onto the Grid.
o Drag a link from the “StringExist” field element in the source schema to the Logical String Functoid
Drag one Value Mapping Functoid from the Toolbox window onto the Grid.
o Drag a link from the Logical String Functoid to the Value Mapping Functoid
o Drag a link from the “StringExist” field element in the source schema to the Value Mapping Functoid
o Drag a link from the Value Mapping Functoid to the “DataExistOutput” field element in the destination
schema
218
BizTalk Mapping Patterns and Best Practices
Again, by looking to the generated code we can reach to the conclusion that this approach has the same advantages
and disadvantages has we explained in previous sample (CHECK EXISTENCE: OPTIONAL TO OPTIONAL ELEMENTS). It will
produce some unnecessary XSLT Code (support variables).
<xsl:variable name="var:v4"
select="userCSharp:LogicalIsString(string(MandatoryElementExistence/StringExist/text()))" />
<xsl:if test="string($var:v4)='true'">
<xsl:variable name="var:v5" select="MandatoryElementExistence/StringExist/text()" />
<DataExistOutput>
<xsl:value-of select="$var:v5" />
</DataExistOutput>
</xsl:if>
So can we improve this solution? Because is a mandatory field, it makes sense now not to use the Value Mapping
Functoid? Let’s try to see what happen in the second element (valid int) if we try to remove the Value Mapping
Functoid and use only the Logical Numeric Functoid (in this case) and a direct link to the destination element.
Drag one Logical Numeric Functoid from the Toolbox window onto the Grid.
o Drag a link from the “IntExist” field element in the source schema to the Logical Numeric Functoid
o Drag a link from the Logical Numeric Functoid to the “IntExistOutput” field element in the destination
schema
Drag a link from the “IntExist” field element in the source schema to the “IntExistOutput” field element in the
destination schema
Unlike what happened earlier when we try to use this strategy with optional elements, when using mandatory
elements removing the Value Mapping Functoid will help generate a better and clean XSLT code:
219
BizTalk Mapping Patterns and Best Practices
<xsl:variable name="var:v6"
select="userCSharp:LogicalIsNumeric(string(MandatoryElementExistence/IntExist/text()))" />
<xsl:if test="$var:v6">
<IntExistOutput>
<xsl:value-of select="MandatoryElementExistence/IntExist/text()" />
</IntExistOutput>
</xsl:if>
Readability: Again, very easy to visual read the rule, doesn’t requires any experience and very easy to implement.
This is the best approach in terms of readability.
Performance: This approach will produce a clean XSLT code without any unnecessary code and extremely efficient.
Now is only missing to map the date, which is an optional element in the source schema. And the rule to be apply to
this action based on what was explained previous is simple: We always need to use two Functoids, the logical Functoid
(Logical Numeric, Logical String or Logical Date) because we need something to validate the content of the element
and the Value Mapping Functoid to support the mapping rule.
Drag one Logical Date Functoid from the Toolbox window onto the Grid.
o Drag a link from the “DateExist” field element in the source schema to the Logical Date Functoid
Drag one Value Mapping Functoid from the Toolbox window onto the Grid.
o Drag a link from the Logical Date Functoid to the Value Mapping Functoid
o Drag a link from the “DateExist” field element in the source schema to the Value Mapping Functoid
o Drag a link from the Value Mapping Functoid to the “DateExistOutput” field element in the destination
schema
220
BizTalk Mapping Patterns and Best Practices
In this sample scenario we will have a record with 4 elements: 1 mandatory element that can be nillable and 3 optional
elements that we need to map to the destination schema. In this scenario all the destination elements are mandatory
and we need to fill them with a valid value, so if the element doesn’t exist we need to add a default value or set the
destination element as nillable if possible.
The first element “DateExist” is a mandatory element that can be null. If null we need to set a null value in the
destination element also as null, otherwise we need to map the source value. To accomplish that we need to:
Drag one IsNil Functoid from the Toolbox window onto the Grid.
o Drag a link from the “DateExist” field element in the source schema to the IsNill Functoid
Drag one Nil Value Functoid from the Toolbox window onto the Grid.
Drag one Logical NOT Functoid from the Toolbox window onto the Grid.
Drag one Value Mapping Functoid from the Toolbox window onto the Grid.
To create a rule for mapping the value if the element is null
o Drag a link from the IsNill Functoid to the Nil Value Functoid
o Drag a link from the Nil Value Functoid to the “MandatoryButCanBeNill” field element in the destination
schema
Otherwise, To create a rule for mapping the value if the element different of null
o Drag a link from the IsNill Functoid to the Logical NOT Functoid
o Drag a link from the Logical NOT Functoid to the Value Mapping Functoid
o Drag a link from the “DateExist” field element in the source schema to the Value Mapping Functoid
o Drag a link from the Value Mapping Functoid to the “MandatoryButCanBeNill” field element in the
destination schema
221
BizTalk Mapping Patterns and Best Practices
Again, by looking to the generated code we can say that in this case the Mapper has produce a pretty decent XSLT
code:
But the reality is that it can be better. We don’t need to use any support variables, also we don’t necessary need to
use C# code and we actually can remove one if condition by replacing the xsl:if condition for one xsl:choose
condition.
Development, Maintainability and Readability: From a developer’s perspective this approach very easy to visual
read the rule, doesn’t requires any experience and very easy to implement. This is the best approach in terms of
readability.
222
BizTalk Mapping Patterns and Best Practices
Performance: When dealing with a large number of nillable elements, using this approach will produce a lot of
unnecessary XSLT code that can in fact, and of course always depending in the size of the message, can lead to
some lack of performance.
Readability and Maintainability: Again, when dealing with a large number of nillable elements this approach can
be more difficult to read and to maintain because we need to use several Functoid shapes (4 Functoids) and links
(7 links) for each element that can lead to lack of visual Readability and consequently hinder their maintenance.
The problem with nillable elements is that the nil attribute (http://msdn.microsoft.com/en-
us/library/ybce7f69%28v=vs.85%29.aspx) is defined in the XML Schema instance namespace,
“http://www.w3.org/2001/XMLSchema-instance” (commonly associated with the prefix xsi) and this namespace is
not declared by default in the XSL code generated by the BizTalk Mapper.
This namespace is automatically declare only if you use the Nil Functoids (IsNil or Nil Value) in the map, otherwise it
will be omitted. And unfortunately there is no simple way to declare this namespace to the Stylesheet of the map.
Using an external XSLT file: in this case we will bypass the BizTalk Mapper and generate a custom external XSLT
code and add it to the map by specifying the Custom XSLT Path. By using this approach we will have, at least in my
opinion, a major problem:
o We will lose all the BizTalk Mapper functionalities/capabilities, and we need to implement the entire
message transformation using custom XSLT.
Using a mix with Nil Functoids and custom XSLT code: In this case we must use at least form one of the nillable
elements the approach explained previous (using the IsNil or Nil Value Functoids). This will declare automatically
the name xsi namespace for us in the map file. In the rest of the elements that exist in the message, we now can
use Scripting Functoids with a better and optimized XSLT code
o Using this option we will have the advantages of both previous approach and minimize all the
disadvantages/limitations.
You can read more about this approach’s here: BizTalk Mapper: Working With Nillable Values (xsi:nil="true")
(http://sandroaspbiztalkblog.wordpress.com/2014/06/12/biztalk-mapper-working-with-nillable-values-xsiniltrue/)
The three following elements: “OptionalElement”, “OptionalElement2” and “OptionalElement3” are optional
elements that can be omitted in the message. If the elements are omitted (absent) then we need to set a default value
in the destination element because they are mandatory, otherwise we need to map the source value. The most
common strategy to solve this problem is by using a combination of the following Functoids:
The Logical Existence Functoid to determine whether the Record, Field Element, or Field Attribute node that is
linked to it exists in a particular input instance message.
The Logical NOT Functoid to logically negate the value of the Boolean input parameter.
And a Value Mapping Functoid to returns the value that we want to linked based on the existence or not of the
Field Element or Field Attribute
Drag one Logical Existence Functoid from the Toolbox window onto the Grid.
o Drag a link from the “OptionalElement” field element in the source schema to the Logical Existence
Functoid
223
BizTalk Mapping Patterns and Best Practices
To create a rule for mapping the value if the element is present in the message
o Drag one Value Mapping Functoid from the Toolbox window onto the Grid.
Drag a link from the Logical Existence Functoid to the Value Mapping Functoid
Drag a link from the “OptionalElement” field element in the source schema to the Value Mapping
Functoid
Drag a link from the Value Mapping Functoid to the “MandatoryElementOutput” field element in
the destination schema
To create a rule for mapping the value if the element is absent from the message
o Drag one Logical NOT Functoid from the Toolbox window onto the Grid.
o Drag a second Value Mapping Functoid from the Toolbox window onto the Grid.
o Drag a link from the Logical Existence Functoid to the Logical NOT Functoid
o Drag a link from the Logical NOT Functoid to the second Value Mapping Functoid
o Drag a link from the second Value Mapping Functoid to the “MandatoryElementOutput” field element in
the destination schema
Important Tip
As we will confirm later in this book, looping operations and complex conditions will always have a problem with
performance if we try to use standard based Functoids. In most scenarios, in which we work with relatively small
messages, this is not really a big problem because we will lose more time developing an optimized map and maintain
it, than actually the gain in performance, because it will be almost irrelevant and almost unimportant at the end.
However if we are working we large message, it will be recommended that you use custom XSLT to perform this
operations.
224
BizTalk Mapping Patterns and Best Practices
If…Then…Else Condition” that we will explain in more details later in this book. Because of this I will not explain right
know the advantages and disadvantages of this approach. Instead I will give some different approach to implement
this rule and discuss this in more detail later.
A different way to apply the same rule using less Functoids, and with better performance is using the custom Functoid
Default Value Mapping, this Functoid is available in the BizTalk Mapper Extensions UtilityPack
(http://btsmapextutilitypack.codeplex.com/). The Default Value Mapping has a similar but different behavior of the
previous scenario. You can use the Default Value Mapping Functoid to return a value from one of two input
parameters. If the value of the first input parameter is Null or Empty, then the value of the second input parameter is
returned, otherwise the first input is returned.
Drag one Default Value Mapping Functoid from the Toolbox window onto the Grid.
o Drag a link from the “OptionalElement2” field element in the source schema to the Default Value Mapping
Functoid
o Make double-click in the Default Value Mapping Functoid to show the Properties window and then:
Specify a default value in the second input parameter (this can be also a different element from the
source schema or a value generated from another Functoid, for example: SSO Config Get Functoid)
o Drag a link from the Default Value Mapping Functoid to the “MandatoryElementOutput2” field element in
the destination schema
225
BizTalk Mapping Patterns and Best Practices
Performance: Because we will use C# internally, it will produce a better and clean code than the previous approach.
Maintainability: From a developer’s perspective because we are using one Functoid rather then 4, if we have
several conditions this approach is easier to maintain.
Readability: Although there is a graphical representation, in some situations there are no easy way to read the
default value, special If is set hardcode inside the Functoid and we need to go inside it to see or understand what
really is happening.
Development: Despise not being difficult to install a custom Functoid, this is not a default Functoid, so it can cause
some strangeness to developers.
Another different way to accomplish the same result, and to improve the XSLT code generated in the first approach is
to use a Custom Inline XSLT Code. We can accomplish that by:
Drag from the Toolbox window one Scripting Functoid and then:
o Drag a link from the Scripting Functoid to the “MandatoryElementOutput3” element in the destination
schema
o Double click in the Scripting Functoid, select the “Script Functoid Configuration” tab and specify the
scripting type as “Inline XSLT” and past the following code to the “Inline script” textbox
<xsl:choose>
<!-- Check if the element exist-->
<xsl:when test="MoreAdvanceValidation/OptionalElement3">
<MandatoryElementOutput3>
<xsl:value-of select="MoreAdvanceValidation/OptionalElement3/text()" />
</MandatoryElementOutput3>
226
BizTalk Mapping Patterns and Best Practices
</xsl:when>
<xsl:otherwise>
<!-- Otherwise set a default value -->
<MandatoryElementOutput3>Default Value 3</MandatoryElementOutput3>
</xsl:otherwise>
</xsl:choose>
Important Tip
As we will confirm later in this book, looping operations and complex conditions will always have a problem with
performance if we try to use standard based Functoids. In most scenarios, in which we work with relatively small
messages, this is not really a big problem because we will lose more time developing an optimized map and maintain
it, than actually the gain in performance, because it will be almost irrelevant and almost unimportant at the end.
However if we are working we large message, it will be recommended that you use custom XSLT to perform this
operations.
If…Then…Else Condition” section, I will not explain right know the advantages and disadvantages of this approach.
In this scenario the recursive record is composed by one optional element that we want to map if exist to one optional
element in destination schema, and one mandatory element that we need to map if it contains a valid string to one
nillable element in the destination schema.
To map the option element has we explained in the CHECK EXISTENCE: OPTIONAL TO OPTIONAL ELEMENTS section
o Drag a link from the “OptionElement” field element in the source schema to the “OptionalElement” field
element in the destination schema
To map the mandatory element and to validate his content, has we explained in the DATA EXISTENCE VALIDATION:
OPTIONAL AND MANDATORY ELEMENTS TO OPTIONAL ELEMENTS section
o Drag one Logical String Functoid from the Toolbox window onto the Grid.
Drag a link from the “MandatoryElement” field element in the source schema to the Logical String
Functoid
o Drag one Value Mapping Functoid from the Toolbox window onto the Grid.
Drag a link from the Logical String Functoid to the Value Mapping Functoid
Drag a link from the “MandatoryElement” field element in the source schema to the Value Mapping
Functoid
Drag a link from the Value Mapping Functoid to the “MandatoryElement” field element in the
destination schema
o Drag one Logical NOT Functoid from the Toolbox window onto the Grid.
o Drag one Nil Value Functoid from the Toolbox window onto the Grid.
o Drag a link from the Logical String Functoid to the Logical NOT Functoid
To create a rule for mapping the value if the element has an invalid string (null or Empty)
o Drag a link from the Logical NOT Functoid to the Nil Value Functoid
o Drag a link from the Nil Value Functoid to the “MandatoryElement” field element in the destination schema
227
BizTalk Mapping Patterns and Best Practices
The advantages and disadvantages are the same for each approach with the severity of which will now be associated
with a loop, so sometimes you need to be careful and choose the best approach if you need to take in consideration
performance, especially for large messages.
So, in this scenario we will have one option record composed by one optional attribute that we want to map if exist
to one mandatory element in destination schema, otherwise we will need to generate an id. And one mandatory
element that we need to map to one mandatory element in the destination schema.
I will not explain the all scenario, because is basically the same as the previous, using different Functoids, and I will
focus only in how to validate the existence of the record node.
The most common strategy to solve this problem is by using one Functoid:
The Logical Existence Functoid to determine whether the Record node that is linked to exists in a particular input
instance message.
Drag one Logical Existence Functoid from the Toolbox window onto the Grid.
o Drag a link from the “OptionalRecord” record in the source schema to the Logical Existence Functoid
o Drag a link from the Value Mapping Functoid to the “OptionalRecord” record in the destination schema
228
BizTalk Mapping Patterns and Best Practices
This rule will validate if the record exist, if doesn’t exist, none of the rules that are linked to the elements of the
destination schema will be executed. If exist the child rules will be executed.
Although in many scenarios we need to use the Logical Existence Functoid to control the existence or not of the record,
this is not a mandatory rule, and you need to be careful and always inspect the XSLT code generated by the compiler.
By looking to this case we can see that:
<xsl:for-each select="OptionalRecord">
<xsl:variable name="var:v20" select="userCSharp:LogicalExistence(boolean(.))" />
<xsl:if test="$var:v20">
<xsl:variable name="var:v21" select="userCSharp:LogicalExistence(boolean(@Id))" />
<xsl:variable name="var:v23" select="userCSharp:LogicalNot(string($var:v21))" />
<OptionalRecord>
<MandatoryElement>
<xsl:value-of select="MandatoryElement/text()" />
</MandatoryElement>
<xsl:if test="string($var:v21)='true'">
<xsl:variable name="var:v22" select="@Id" />
<Id>
<xsl:value-of select="$var:v22" />
</Id>
</xsl:if>
<xsl:if test="string($var:v23)='true'">
<xsl:variable name="var:v24" select=""n/d"" />
<Id>
<xsl:value-of select="$var:v24" />
</Id>
</xsl:if>
</OptionalRecord>
</xsl:if>
</xsl:for-each>
229
BizTalk Mapping Patterns and Best Practices
Despise being a record that can occur 0 or 1 time, the map unfortunately will use one xsl:for-each expression to
map the optional record, but by using this it means that we don’t actually need any xsl:if condition inside the loop
to validate if the record is present or not. However by using a Logical Existence Functoid this will force the map
compiler to place one xsl:if condition inside the loop to describe the Logical Existence rule.
In this case the best option, of course without using custom XSLT code, is not using the Logical Existence Functoid, as
you can see in the picture bellow:
<xsl:for-each select="OptionalRecord">
<xsl:variable name="var:v20" select="userCSharp:LogicalExistence(boolean(@Id))" />
<xsl:variable name="var:v22" select="userCSharp:LogicalNot(string($var:v20))" />
<OptionalRecord>
<MandatoryElement>
<xsl:value-of select="MandatoryElement/text()" />
</MandatoryElement>
<xsl:if test="string($var:v20)='true'">
<xsl:variable name="var:v21" select="@Id" />
<Id>
<xsl:value-of select="$var:v21" />
</Id>
</xsl:if>
<xsl:if test="string($var:v22)='true'">
<xsl:variable name="var:v23" select=""n/d"" />
<Id>
<xsl:value-of select="$var:v23" />
</Id>
</xsl:if>
</OptionalRecord>
</xsl:for-each>
By removing this Functoid the generated code will be significant better, despise not being the ideal.
If…Then Condition
The If...Then statement is the most basic of all the control flow statements. It tells your program to execute a certain
section of code only if a particular test evaluates to true.
This condition can be apply to Record, Field Element, Field Attribute node or even the outcome of other Functoids.
One basic example of this type of condition apply Record, Field Element or Field Attribute is to check the existence
that we already explained in the CHECK EXISTENCE section, which are normally translated to:
One Logical Functoid (Logical Existence, Logical String, Logical Numeric and so on) to determine whether the
Record, Field Element, or Field Attribute node that is linked to it exists or have a valid value in a particular input
instance message.
And one Value Mapping Functoid to returns the value that we want to linked based on the result of the condition
But it can also be translated to a direct link using optional Field Elements or Field Attributes. But many more and almost
impossible to quantify may occur, however, the most important is to understand the basic principles of conditions, to
learn how to inspect the XLST code and to take action to improve if necessary the approach and code implemented
according to the requirements of the problem.
In this section we will address some of the concern that you need to take in consideration when applying this pattern
to records.
230
BizTalk Mapping Patterns and Best Practices
Drag one Equal Functoid from the Toolbox window onto the Grid.
o Drag a link from the “Number” field element in the source schema to the Equal Functoid
o Make double-click in the Equal Functoid to show the Properties window and then:
Specify the second condition (second input parameter) as 10
Drag a link from the Equal Functoid to the Value Mapping Functoid to the “Number” field element in the destination
schema
Drag a link from the “Number” field element in the source schema to the “Number” field element in the destination
schema
231
BizTalk Mapping Patterns and Best Practices
Because we are dealing with a record that is mandatory and that can only occurs one time, the compiler will not
translate this rule into a for-each segment and instead it will use a condition (xsl:if) directly to element inside the
record to translate the Equal rule.
Witch in this case, despise of not being the ideal, because it will use C# code to perform the validation and is make use
of an unnecessary support variable, it’s not so bad and in normal conditions I will use it and I don’t lose my time trying
to improve it, why?
Development, Maintainability and Readability: From a developer’s perspective, even for new developer’s, when
working with developers from other teams or even by now BizTalk developers, this approach is very easy to visual
read the rule, doesn’t requires any experience and is very easy to implement. This is the best approach in terms of
readability.
Of course if your are a freak for optimization and performance, this is probably not best way to accomplish that and
you can archive a better XSLT code but for me there isn’t any advantages on doing that, in fact it’s the opposite:
Level of effort/Development: Not quite as intuitive, Standard Functoids are easier to read visually on the map grid.
Also in many scenarios using custom XSLT are more time-consuming in comparison Standard Functoids and requires
XSLT knowledge, therefore it requires “geeky” coding skills
Again, we will use a similar approach as the previous one with some small differences, in which the major difference
is in the destination links of the condition. In the previous one we link the out coming link of the Equal Functoid to the
destination element, however this time we only want to create the record element if source element is set to 10,
otherwise we don’t want to create the record, so we need to link the out coming link from the Equal Functoid to the
destination record and not to the elements, and we will see why.
Drag one Equal Functoid from the Toolbox window onto the Grid.
o Drag a link from the “Number” field element in the source schema to the Equal Functoid
o Make double-click in the Equal Functoid to show the Properties window and then:
Specify the second condition (second input parameter) as 10
Drag a link from the Equal Functoid to the Value Mapping Functoid to the “RecordThatMachCondition” record in
the destination schema
Drag a link from the “Number” field element in the source schema to the “Number” field element in the destination
schema
232
BizTalk Mapping Patterns and Best Practices
Drag a link from the “Name” field element in the source schema to the “Name” field element in the destination
schema
Because we are dealing with a recursive record the compiler will translate this rule into a for-each segment and it will
use a condition (xsl:if) inside to validate if the element match to the condition.
<xsl:for-each select="MapRecordBaseCondition">
<xsl:variable name="var:v3" select="userCSharp:LogicalEq(string(Number/text()) , "10")"
/>
<xsl:if test="$var:v3">
<RecordThatMachCondition>
<Number>
<xsl:value-of select="Number/text()" />
</Number>
<Name>
<xsl:value-of select="Name/text()" />
</Name>
</RecordThatMachCondition>
</xsl:if>
</xsl:for-each>
Again, despise of not being the ideal XSLT code, it’s is pretty decent and I will not lose my time trying to improve it in
most of the common scenarios, however this approach has an important limitation that you should be aware that can
occur in some scenarios:
Performance: if we are working with large messages and if the source message has many occurrence of this
elements and in only a few are valid, in the context of this example: are set to 10, them the transformation will
perform several unnecessary loop iteration that can induce some lack of performance.
As all of the mapping solutions, you should take in consideration the requirements of your problem. In normal situation
I will use the approach described earlier, however if I’m working with large messages and performance needs to be a
requirement then I will bypass Functoids and I will instead use a Scripting Functoid with an Inline XSLT script:
<!-- Get only the element from the message that has the Number equal to 10 -->
<xsl:for-each select="MapRecordBaseCondition[Number = 10]">
<RecordThatMachCondition>
<Number>
<xsl:value-of select="Number/text()" />
</Number>
<Name>
<xsl:value-of select="Name/text()" />
</Name>
</RecordThatMachCondition>
233
BizTalk Mapping Patterns and Best Practices
</xsl:for-each>
I told previous that we should associate the out coming link from the Equal Functoid to the Record and not to the
elements, let’s see why and happens when we link the out coming link to the element as the picture bellow describe:
In this scenario independently of the number of occurrence in the source message only one Record will be created in
the destination message, containing inside this record a list of names and numbers
…
<RecordThatMachCondition>
<Number>10</Number>
<Number>10</Number>
<Name>Sandro Pereira</Name>
<Name>Nino Crudele</Name>
</RecordThatMachCondition>
…
This happens because this rules are translated into two for-each statements internally inside this record.
Another valid approach, and often seen in some solutions, is to associate the out coming link to both elements: Record
element and Field elements:
The problem of this solution is that comparing to all of the previous approach this is the one that has the worst
performance, because we will generate a lot of unnecessary XSLT code to translate all of the rules:
<xsl:for-each select="MapRecordBaseCondition">
<xsl:variable name="var:v3" select="userCSharp:LogicalEq(string(Number/text()) , "10")"
/>
234
BizTalk Mapping Patterns and Best Practices
<!-- Test if the Number is equal to 10 to create the record element -->
<xsl:if test="$var:v3">
<xsl:variable name="var:v4" select="string(Number/text())" />
<xsl:variable name="var:v5" select="userCSharp:LogicalEq($var:v4 , "10")" />
<RecordThatMachCondition>
<!-- Test if the Number is equal to 10 to create the Number Field element -->
<xsl:if test="$var:v5">
<Number>
<xsl:value-of select="Number/text()" />
</Number>
</xsl:if>
<!-- Test if the Number is equal to 10 to create the Name Field element -->
<xsl:if test="$var:v5">
<Name>
<xsl:value-of select="Name/text()" />
</Name>
</xsl:if>
</RecordThatMachCondition>
</xsl:if>
</xsl:for-each>
In fact this is actually not a BizTalk Mapper problem, the Mapper is simple trying to translate all of the rules
implemented by the developer. In this case is the developer fault that is duplicating the rules and thereby forcing the
compiler to produce a lot of unnecessary XSLT code.
We cannot associated the out coming link from the Equal Functoid to the Record element, otherwise it will be
translate into a rule that will try to create several records and this record only can occur 1 time.
The “Name” must be present at least one time if the Record is created, so we need to find a way to control the
creation of the Record based on whether the message has content or not to be mapped.
Drag one Equal Functoid from the Toolbox window onto the Grid.
o Drag a link from the “Number” field element in the source schema to the Equal Functoid
o Make double-click in the Equal Functoid to show the Properties window and then:
Specify the second condition (second input parameter) as 10
Drag a link from the Equal Functoid to the Value Mapping Functoid to the “Name” Field element in the destination
schema
Drag a link from the “Name” field element in the source schema to the “Name” field element in the destination
schema
235
BizTalk Mapping Patterns and Best Practices
<ListOfNames>
<Name>Sandro Pereira</Name>
<Name>Nino Crudele</Name>
</ListOfNames>
However is there isn’t any content to be mapped it fails because has we describe earlier, we are not controlling the
creation of the record “ListOfNames” and in this case will produce an empty record.
<ListOfNames />
So solve this problem we basically need to count the number of valid element exist in the source message and if more
than 0 (zero) we will create the record, otherwise it will be abolished. To accomplish that we need to:
Drag one Scripting Functoid from the Toolbox window onto the Grid, to have the rule to increase or not the count
of elements based on if is a valid element or not
Drag one Cumulative Sum Functoid from the Toolbox window onto the Grid, in each iteration it will update the
count number of valid elements in the message.
Drag one Greater Than Functoid from the Toolbox window onto the Grid, to check if is necessary to create the
record.
Drag a link from the previous Equal Functoid to the Scripting Functoid
o Double click in the Scripting Functoid and specify the scripting type as “Inline C#”
o In the Inline script put the following code:
236
BizTalk Mapping Patterns and Best Practices
Drag a link from the Greater Than Functoid to the “ListOfNames” Record element in the destination schema
Again, and as happened in previous scenarios, this is a great solution to small or medium messages because is very
simple to implement, to read and to maintain from a developer perspective, even for new developer’s. However it has
several limitation in terms of performances when dealing with large messages, as we can observe in the XSLT
generated by the compiler:
237
BizTalk Mapping Patterns and Best Practices
<xsl:variable name="var:v8"
select="userCSharp:AddToCumulativeSum(0,string($var:v7),string(./text()))" />
</xsl:for-each>
<xsl:variable name="var:v9" select="userCSharp:GetCumulativeSum(0)" />
<xsl:variable name="var:v10" select="userCSharp:LogicalGt(string($var:v9) , "0")" />
<!-- Create the ListOfNames element if exist valid elements to be mapped -->
<xsl:if test="$var:v10">
<ListOfNames>
<!-- Travel onde again the elements inside the message this time to extract the valid ones -->
<xsl:for-each select="MapRecordBaseCondition">
<xsl:variable name="var:v11" select="string(Number/text())" />
<xsl:variable name="var:v12" select="userCSharp:LogicalEq($var:v11 , "10")" />
<xsl:if test="$var:v12">
<Name>
<xsl:value-of select="Name/text()" />
</Name>
</xsl:if>
</xsl:for-each>
</ListOfNames>
</xsl:if>
As we can see we travel two times the record “MapRecordBaseCondition”, once to count the messages and the second
time to extract the elements. Despise the second iteration only take place if element indeed exist in the source
element, if we have 100 occurrences and only one is need to be mapped, we still need to perform 100 iterations and
execute 100 validations.
Once again, if we are working with large messages and/or performance are required we need to skip the standard
Functoids and perform this translation with custom XSLT code, using a Scripting Functoid with Inline XSLT and using
the following code:
Important Tip
As we will confirm later in this book, looping operations and complex conditions will always have a problem with
performance if we try to use standard based Functoids. In most scenarios, in which we work with relatively small
messages, this is not really a big problem because we will lose more time developing an optimized map and maintain
it, than actually the gain in performance, because it will be almost irrelevant and almost unimportant at the end.
However if we are working we large message, it will be recommended that you use custom XSLT to perform this
operations.
If…Then…Else Condition
You can use If...Then...Else statements to execute blocks of statements depending on the Boolean value of a condition.
It will provide a secondary path of execution when an "if" clause evaluates to false. The condition usually results from
a comparison of two values, but it can be any expression that evaluates to a Boolean value (True or False). This includes
values of other data types, such as numeric types, that have been converted to Boolean.
238
BizTalk Mapping Patterns and Best Practices
Once again, this condition can be apply to Record, Field Element, Field Attribute node or even the outcome of other
Functoids. One basic example of this type of condition apply Record, Field Element or Field Attribute is to check the
existence that we already explained in the CHECK EXISTENCE: OPTIONAL TO MANDATORY ELEMENTS on the CHECK EXISTENCE
section, which are normally translated to:
One Logical Functoid (Logical Existence, Logical String, Logical Numeric and so on) to determine whether the
Record, Field Element, or Field Attribute node that is linked to it exists or have a valid value in a particular input
instance message.
One Logical NOT Functoid to negate the Logical Functoid
And two Value Mapping Functoids to returns the value that we want to linked based on the result of the condition
In this section we will address some of the concern that you need to take in consideration when applying this pattern
to records.
The Equal Functoid to determine whether the Record, Field Element, or Field Attribute node that is linked to it
exists in a particular input instance message.
One Logical NOT Functoid to negate the result of the Equal Functoid
And two Value Mapping Functoids to returns the value that we want to linked based on the result of the condition
Drag one Equal Functoid from the Toolbox window onto the Grid.
o Drag a link from the “CivilStatus” field element in the source schema to the Equal Functoid
o Make double-click in the Equal Functoid to show the Properties window and then:
Specify the second condition (second input parameter) as “M”
Drag one Value Mapping Functoid from the Toolbox window onto the Grid.
o Drag a link from the Equal Functoid to the Value Mapping Functoid
o Drag a link from the Value Mapping Functoid to the “CivilStatus” field element in the destination schema
239
BizTalk Mapping Patterns and Best Practices
o Make double-click in the Value Mapping Functoid to show the Properties window and then:
Specify the second condition (second input parameter) as “Married”
Drag one Logical NOT Functoid from the Toolbox window onto the Grid.
o Drag a link from the Equal Functoid to the Logical NOT Functoid.
Drag one Value Mapping Functoid from the Toolbox window onto the Grid.
o Drag a link from the Equal Functoid to the Value Mapping Functoid
o Drag a link from the Value Mapping Functoid to the “CivilStatusDescription” field element in the destination
schema
o Make double-click in the Value Mapping Functoid to show the Properties window and then:
Specify the second condition (second input parameter) as “Single”
Again, if we take a look in XSLT generated by the compiler, we can see that despise not being the perfect code is once
again very decent:
And this is a great solution to transformations that occurs once or a few times in the message, it is simple to read and
to maintain from a developer perspective, even for new developers.
240
BizTalk Mapping Patterns and Best Practices
Reusability: if in some scenarios we have different or several places with the same conditional rule, we cannot
reuse the shapes, instead we need to duplicate them, that despite being an easy task, since currently we can copy
and paste objects (links and Functoids) in the mapper, it can lead to other problems like: difficulty in reading and
maintenance of the map because the number of Functoids and links can grow dramatically depending in the
number of places that we need to apply this rule. And if a change need to be made, we need to correct in all the
locations one by one.
Drag one Scripting Functoid from the Toolbox window onto the Grid, to have the rule to translate the Civil Status
to a Civil Status Description
Drag a link from the “CivilStatus” field Element in the source schema to the Scripting Functoid.
Drag a link from Scripting Functoid to the “CivilStatusDescription” field Element in the destination schema
Double click in the Scripting Functoid and specify the scripting type as “Inline C#”
o In the Inline script put the following code:
By taking this approach, instead of using a complex Functoid, chain we will simplify the map the map in some scenarios
making them sometimes easier to read. Or simply in some occasions we will optimize the transformation rules because
in some situations the XSLT code generated automatically by the compiler can’t perform as well as C# code.
Important Tip
Just remember that if we need to use this rule in a different place, we need to add a new Scripting Functoid and
add only the function declaration inside the Functoid.
241
BizTalk Mapping Patterns and Best Practices
Compilation limitations: When we create a script, for example a C# function, remember to give it a correct name
because all scripts with the same name are treated as one by the compiler regardless of whether the code is equal
or not.
Drag one Scripting Functoid from the Toolbox window onto the Grid, to have the rule to translate the Civil Status
to a Civil Status Description
Drag a link from the Scripting Functoid to the “CivilStatusDescription” field Element in the destination schema
Double click in the Scripting Functoid and specify the scripting type as “Inline XSLT”
o In the Inline script put the following code:
<xsl:choose>
<xsl:when test="string(Person/CivilStatus/text()) = 'M'">
<CivilStatusDescription>Married</CivilStatusDescription>
</xsl:when>
<xsl:otherwise>
<CivilStatusDescription>Single</CivilStatusDescription>
</xsl:otherwise>
</xsl:choose>
However this approach has the same limitation of the first solution:
Reusability: if in some scenarios we have different or several places with the same conditional rule, we cannot
reuse the shapes, instead we need to duplicate them.
242
BizTalk Mapping Patterns and Best Practices
We can solve this limitation by converting the XSLT code in a template using an Inline XSLT Call Template script type:
<xsl:template name="GetCivilStatusDescriptionTemplate">
<xsl:param name="param1" />
<xsl:choose>
<xsl:when test="string($param1) = 'M'">
<CivilStatusDescription>Married</CivilStatusDescription>
</xsl:when>
<xsl:otherwise>
<CivilStatusDescription>Single</CivilStatusDescription>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Calling an XSLT template is very similar to using inline XSLT, the main difference is the way in which values within the
source document are accessed. With the inline XSLT, node values in the source document are accessed through XSL
methods or XPATH Queries, whereas with called XSLT templates, the values are passed in as parameters.
Reusability: Because we are creating the structure of the nodes inside the template, we can only use this rule if the
destination node (Record or Elements) has the same structure and names.
Important Tip
Just remember that if we need to use this rule, in this case invoke the same template, in a different place, we need
to add a new Scripting Functoid and instead of using a XSLT Call Template, we need to use an Inline XSLT with a
similar XSLT code:
<xsl:call-template name="GetCivilStatusDescriptionTemplate">
<xsl:with-param name="param1" select="string(OtherRecord/CivilStatus/text())" />
</xsl:call-template>
243
BizTalk Mapping Patterns and Best Practices
How to map values from a repeating node into a single node using conditions
In this scenario we have a repeating node “TimeSeries” and based on Path attribute value of “TimeSeries” node we
will map on some elements of the output message:
This scenario is actually a really example taken from a question that I found on the forums: Reg BizTalk Mapping
(http://social.msdn.microsoft.com/Forums/en-US/799e7a3e-c3c3-4259-86c1-dc467820397c/reg-biztalk-
mapping?forum=biztalkgeneral), which I found interesting.
Input Output
<TimeSeries type="TimeSeriesUpdates" <Quantity>2458.25</Quantity>
Path="1" <NRJQuantity>3458.25</NRJQuantity>
ErrDesc="" <AvgCal>4458.25</AvgCal>
Error="-2147220478" <AvgDens>5458.25</AvgDens>
SeriesID="">
<TimedValues>
<TimedValue Path="1"
Flags="Flags_1"
Time="1999-05-31T13:20:00.000-05:00"
UOM="UOM_3"
Status="Status_4"
PctGood="10"
DataType="DataType_6">2458.25</TimedValue>
</TimedValues>
<Updates></Updates>
</TimeSeries>
<TimeSeries type="TimeSeriesUpdates"
Path="2"
ErrDesc=""
Error="-2147220478"
SeriesID="">
<TimedValues>
<TimedValue Path="2"
Flags="Flags_1"
Time="1999-05-31T13:20:00.000-05:00"
UOM="UOM_3" Status="Status_4"
PctGood="10"
DataType="DataType_6">3458.25</TimedValue>
</TimedValues>
<Updates></Updates>
</TimeSeries>
<TimeSeries type="TimeSeriesUpdates"
Path="3"
ErrDesc=""
Error="-2147220478"
SeriesID="">
<TimedValues>
<TimedValue Path="3"
Flags="Flags_1"
Time="1999-05-31T13:20:00.000-05:00"
UOM="UOM_3" Status="Status_4"
PctGood="10"
DataType="DataType_6">4458.25</TimedValue>
</TimedValues>
244
BizTalk Mapping Patterns and Best Practices
<Updates></Updates>
</TimeSeries>
<TimeSeries type="TimeSeriesUpdates"
Path="4"
ErrDesc=""
Error="-2147220478"
SeriesID="">
<TimedValues>
<TimedValue Path="4"
Flags="Flags_1"
Time="1999-05-31T13:20:00.000-05:00"
UOM="UOM_3"
Status="Status_4"
PctGood="10"
DataType="DataType_6">5458.25</TimedValue>
</TimedValues>
<Updates></Updates>
</TimeSeries>
One Equal Functoid and drag a link from the attribute “Path” in the source schema to this Functoid, this will be the
first input parameter in the Functoid
o And in the second parameter we need to put the number that we want to find, in this case: “1”.
Drag a Value Mapping Functoid to the grid
o Drag a link from the Equal Functoid to this Value Mapping Functoid
o Drag a link from the “TimedValue” element in the source element to the Value Mapping Functoid
Drag a link from the Equal Functoid for the element in question in the destination schema, in this case “Quantity”
element
And finally we need to drag a link from the Value Mapping Functoid to the respective element in the destination
schema, in this case again “Quantity” element as you can see in the picture bellow.
245
BizTalk Mapping Patterns and Best Practices
We need to repeat the above steps for all the element until we get the following map:
This solution is correct and in fact is what’s normally we found in this type of mapping problems however this is not
the best option in terms of performance. If we analyze the XSLT regenerated by the BizTalk mapping engine by:
We will see that for each element in the destination schema it will be one for-each element:
<ns0:Req>
<xsl:for-each select="TimeSeries">
<xsl:variable name="var:v1" select="userCSharp:LogicalEq(string(@Path) , "1")" />
<xsl:if test="$var:v1">
<xsl:variable name="var:v2" select="string(@Path)" />
<xsl:variable name="var:v3" select="userCSharp:LogicalEq($var:v2 , "1")" />
<xsl:if test="string($var:v3)='true'">
<xsl:variable name="var:v4" select="TimedValues/TimedValue/text()" />
<Quantity>
<xsl:value-of select="$var:v4" />
</Quantity>
</xsl:if>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="TimeSeries">
<xsl:variable name="var:v5" select="string(@Path)" />
<xsl:variable name="var:v6" select="userCSharp:LogicalEq($var:v5 , "2")" />
<xsl:if test="$var:v6">
<xsl:if test="string($var:v6)='true'">
246
BizTalk Mapping Patterns and Best Practices
This means that if we have 50 occurrences of “TimeSeries” node, we will have 50 iterations for each element that we
want to map in the destination schema… so this approach may be easy to implement and somewhat acceptable in
small messages is extremely disadvantageous for large message.
Performance: if we are working with large messages and if the source message has many occurrence of this
elements, performing condition using Functoids inside looping records will induce several unnecessary loop
iteration that can induce some lack of performance.
<xsl:for-each select="TimeSeries">
<xsl:if test="string(@Path) = '1' ">
<Quantity>
<xsl:value-of select="TimedValues/TimedValue/text()" />
</Quantity>
</xsl:if>
<xsl:if test="string(@Path) = '2' ">
<NRJQuantity>
<xsl:value-of select="TimedValues/TimedValue/text()" />
</NRJQuantity>
</xsl:if>
<xsl:if test="string(@Path) = '3' ">
<AvgCal>
<xsl:value-of select="TimedValues/TimedValue/text()" />
</AvgCal>
</xsl:if>
<xsl:if test="string(@Path) = '4' ">
<AvgDens>
<xsl:value-of select="TimedValues/TimedValue/text()" />
</AvgDens>
</xsl:if>
</xsl:for-each>
Finally drag a link from the Scripting Functoid to one element in the destination schema, for example “NRJQuantity”
247
BizTalk Mapping Patterns and Best Practices
Performance: May have some lack of performance if we work with large message because some unnecessary
iterations in the cycle, however it is far more efficient than the first solution.
Warnings: Some warnings saying that some required field has no incoming link, but we can solve and prevent these
warnings using several Scripting Functoids (see FOURTH SOLUTION: USING INLINE XSLT ALONG WITH XPATH QUERIES
(AVOIDING WARNINGS)).
Readability: Because we use scripting Functoids we cannot read the entire map visually. We need to open the
Functoids and read, mainly, the XSLT code.
Replace the code of the Scripting Functoid, existing in the previous solution, by:
<xsl:choose>
<xsl:when test="count(//TimeSeries[@Path='1']) > 0">
<Quantity>
<xsl:value-of select="//TimeSeries[@Path='1']/TimedValues/TimedValue/text()" />
</Quantity>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="count(//TimeSeries[@Path='2']) > 0">
<NRJQuantity>
<xsl:value-of select="//TimeSeries[@Path='2']/TimedValues/TimedValue/text()" />
</NRJQuantity>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="count(//TimeSeries[@Path='3']) > 0">
248
BizTalk Mapping Patterns and Best Practices
<AvgCal>
<xsl:value-of select="//TimeSeries[@Path='3']/TimedValues/TimedValue/text()" />
</AvgCal>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="count(//TimeSeries[@Path='4']) > 0">
<AvgDens>
<xsl:value-of select="//TimeSeries[@Path='4']/TimedValues/TimedValue/text()" />
</AvgDens>
</xsl:when>
</xsl:choose>
Readability: Because we use scripting Functoids we cannot read the entire map visually. We need to open the
Functoids and read, mainly, the XSLT code.
Development: Need basic knowledge of XSLT and XPath
Warnings: Some warnings saying that some required field has no incoming link, again, we can solve and prevent
these warnings using several Scripting Functoids (see FOURTH SOLUTION: USING INLINE XSLT ALONG WITH XPATH QUERIES
(AVOIDING WARNINGS)).
Fourth Solution: Using Inline XSLT along with XPath queries (avoiding warnings)
So to avoid warnings saying that some required field has no incoming link we must split the XSLT code that we use in
the last solution (Third Solution) in different blocks for each element in the destination schema
Drag four Scripting Functoid to the map grid and drag a link from each Scripting Functoid to each element in the
destination schema
For each Scripting Functoid:
o In the scripting type select “Inline XSLT” option
o In the Inline script put the code that corresponding to the element in the destination element, for example
in the first:
<xsl:choose>
<xsl:when test="count(//TimeSeries[@Path='1']) > 0">
<Quantity>
<xsl:value-of select="//TimeSeries[@Path='1']/TimedValues/TimedValue/text()" />
</Quantity>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="count(//TimeSeries[@Path='2']) > 0">
<NRJQuantity>
<xsl:value-of select="//TimeSeries[@Path='2']/TimedValues/TimedValue/text()" />
</NRJQuantity>
</xsl:when>
</xsl:choose>
249
BizTalk Mapping Patterns and Best Practices
<xsl:choose>
<xsl:when test="count(//TimeSeries[@Path='3']) > 0">
<AvgCal>
<xsl:value-of select="//TimeSeries[@Path='3']/TimedValues/TimedValue/text()" />
</AvgCal>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="count(//TimeSeries[@Path='4']) > 0">
<AvgDens>
<xsl:value-of select="//TimeSeries[@Path='4']/TimedValues/TimedValue/text()" />
</AvgDens>
</xsl:when>
</xsl:choose>
Readability: Because we use scripting Functoids we cannot read the entire map visually. We need to open the
Functoids and read, mainly, the XSLT code.
Development: Need basic knowledge of XSLT and XPath
XSLT has some limitations and differences in which some functionalities are implemented in a way we are don’t
typically used compared to common procedural programming languages (C#, C++ and so on). One of this example is
250
BizTalk Mapping Patterns and Best Practices
the switch statement. In terms of XSLT language, the <xsl:choose> element works very similarly to the case or switch
statement that you might know from procedural programming languages. The <xsl:choose> element is used in
conjunction with <xsl:when> and <xsl:otherwise> to express multiple conditional tests.
The <xsl:when> statements will specify a set of conditions which, if true, would return a value/values to the
destination schema. In the last part of the statement we have the <xsl:otherwise> condition which could set for
example default values if the previous conditions presented were not valid, for example:
<xsl:choose>
<xsl:when test="condition 1 or expression 1">
... some output ...
</xsl:when>
<xsl:when test="condition 2 or expression 2">
... some output ...
</xsl:when>
<xsl:when test="another condition or expression">
... some output ...
</xsl:when>
<xsl:otherwise>
... some output ....
</xsl:otherwise>
</xsl:choose>
The XSLT function that I used was the <xsl:choose> statement, inside the statement was a set of conditions which, if
true, would return a value/values to the destination schema. In the last part of the statement was the
<xsl:otherwise> condition which could set values if the conditions presented were not valid and you had a default
you wanted to present in that event.
Unfortunately there isn’t any out-of-the-box Functoids or easy feature/functionalities to accomplish this task inside
the mapper, instead we have to use a chain of Functoids to implement nested conditions.
To exemplify better, let’s have a look in this sample: in this scenario we have a message that can contain several
persons (recursive record) described through some elements: Name, the Company, the role and some additional
information (Age and Civil Status) that based on the Role of the person we need to group in (or split into) the right
Record in the destination message, i.e.:
If “Role” element == “CEO″ or == “Director” then we need to map the content of the “Person” record to the
“BusinessManagers” record in the destination schema
If “Role” element == “Business Assistant″ or == “Assistant” then we need to map the content of the “Person” record
to the “BusinessAssistant” record in the destination schema
Otherwise we need to map the content of the “Person” record to the “Employee” record in the destination schema
Input Output
<Person> <BusinessManagers>
<Name>Rui Barbosa</Name> <Name>Rui Barbosa</Name>
<Company>DevScope</Company> <Role>Director</Role>
<Role>Director</Role> </BusinessManagers>
<AdditionalInfo> <BusinessManagers>
<Age>39</Age> <Name>Jose Antonio Silva</Name>
<CivilStatus>M</CivilStatus> <Role>CEO</Role>
</AdditionalInfo> </BusinessManagers>
</Person> <BusinessAssistant>
<Person> <Name>Marcia Teixeira</Name>
<Name>Jose Antonio Silva</Name> <Role>Business Assistant</Role>
251
BizTalk Mapping Patterns and Best Practices
<Company>DevScope</Company> </BusinessAssistant>
<Role>CEO</Role> <Employee>
<AdditionalInfo> <Name>Sandro Pereira</Name>
<Age>39</Age> <Role>Employee</Role>
<CivilStatus>M</CivilStatus> <CivilStatusDescription>
</AdditionalInfo> Single
</Person> </CivilStatusDescription>
<Person> </Employee>
<Name>Marcia Teixeira</Name> <Employee>
<Company>DevScope</Company> <Name>Vania Braziela</Name>
<Role>Business Assistant</Role> <Role>Employee</Role>
<AdditionalInfo> <CivilStatusDescription>
<Age>32</Age> Married
<CivilStatus>S</CivilStatus> </CivilStatusDescription>
</AdditionalInfo> </Employee>
</Person> <Employee>
<Person> <Name>Miguel Silva</Name>
<Name>Sandro Pereira</Name> <Role>Manager</Role>
<Company>DevScope</Company> <CivilStatusDescription>
<Role>Employee</Role> Married
<AdditionalInfo> </CivilStatusDescription>
<Age>34</Age> </Employee>
<CivilStatus>S</CivilStatus>
</AdditionalInfo>
</Person>
<Person>
<Name>Vania Braziela</Name>
<Company>DevScope</Company>
<Role>Employee</Role>
<AdditionalInfo>
<Age>32</Age>
<CivilStatus>M</CivilStatus>
</AdditionalInfo>
</Person>
<Person>
<Name>Miguel Silva</Name>
<Company>DevScope</Company>
<Role>Manager</Role>
<AdditionalInfo>
<Age>36</Age>
<CivilStatus>M</CivilStatus>
</AdditionalInfo>
</Person>
The first phase we will address the mapping rules that will be associated with the “BusinessManagers” and
“BusinessAssistant” records
In the second phase we will address the default (otherwise) mapping rule that will associated with the “Employee”
record.
Drag two Equal Functoids and one Logical OR Functoid to the map grid.
Drag a link from the “Role” element in the source element to each of the Equal Functoid
252
BizTalk Mapping Patterns and Best Practices
o Make double-click in each of the Equal Functoid to show the Properties window and then:
In the first Functoid: Specify the second condition (second input parameter) as “CEO”
In the second Functoid: Specify the second condition (second input parameter) as “Director”
o Drag a link from these two Equal Functoid to the Logical OR Functoid
Drag a link from the Logical OR Functoid to the record “BusinessManagers” in the destination schema
Drag a link from the “Name” element in the source schema to the “Name” element in the destination schema
Drag a link from the “Role” element in the source schema to the “Role” element in the destination schema
Finally we need to apply the same steeps but this time for the “BusinessManagers” record, notice that in this case:
In the first Functoid: Specify the second condition (second input parameter) as “Business Assistant”
In the second Functoid: Specify the second condition (second input parameter) as “Assistant”
The transformation for the first phase in archived relatively easily, with a small number of Functoids and easily
readable. Now we need to accomplish the second phase: the default mapping rule, in other words, if all these
253
BizTalk Mapping Patterns and Best Practices
conditions are false we need to map the values for the “Employee” record, the otherwise branch. To accomplish that
we need to:
Drag four Logical NOT Functoids and one Logical AND Functoid to the map grid.
Drag a link from the first Equal Functoids to the first of the Logical NOT Functoid
o Repeat this steep for the rest of the Equal Functoids
o This will logical negate all the previous equal conditions
Drag a link from each Logical NOT Functoids to the Logical AND Functoid
o This will validate if all the previous equal conditions were false
Drag a link from the Logical AND Functoid to the record “Employee” in the destination schema
Drag a link from the “Name” element in the source schema to the “Name” element in the destination schema
Drag a link from the “Role” element in the source schema to the “Role” element in the destination schema
This solution is correct, in fact is common to find this type of mapping rules and a perfect solution for small messages.
However, if we analyze the XSLT regenerated by the BizTalk mapping engine we will see that this is not the best option
in terms of performance.
<xsl:for-each select="Person">
<xsl:variable name="var:v1" select="userCSharp:LogicalEq(string(Role/text()) , "CEO")"
/>
<xsl:variable name="var:v2" select="string(Role/text())" />
<xsl:variable name="var:v3" select="userCSharp:LogicalEq($var:v2 , "Director")" />
<xsl:variable name="var:v4" select="userCSharp:LogicalOr(string($var:v1) , string($var:v3))" />
<xsl:if test="$var:v4">
<BusinessManagers>
<Name>
<xsl:value-of select="Name/text()" />
</Name>
<Role>
<xsl:value-of select="Role/text()" />
254
BizTalk Mapping Patterns and Best Practices
</Role>
</BusinessManagers>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="Person">
<xsl:variable name="var:v9" select="string(Role/text())" />
<xsl:variable name="var:v10" select="userCSharp:LogicalEq($var:v9 , "CEO")" />
<xsl:variable name="var:v11" select="userCSharp:LogicalNot(string($var:v10))" />
<xsl:variable name="var:v12" select="userCSharp:LogicalEq($var:v9 , "Director")" />
<xsl:variable name="var:v13" select="userCSharp:LogicalNot(string($var:v12))" />
<xsl:variable name="var:v14" select="userCSharp:LogicalEq($var:v9 , "Business
Assistant")" />
<xsl:variable name="var:v15" select="userCSharp:LogicalNot(string($var:v14))" />
<xsl:variable name="var:v16" select="userCSharp:LogicalEq($var:v9 , "Assistant")" />
<xsl:variable name="var:v17" select="userCSharp:LogicalNot(string($var:v16))" />
<xsl:variable name="var:v18" select="userCSharp:LogicalAnd(string($var:v11) , string($var:v13) ,
string($var:v15) , string($var:v17))" />
<xsl:if test="$var:v18">
<Employee>
<Name>
<xsl:value-of select="Name/text()" />
</Name>
<Role>
<xsl:value-of select="Role/text()" />
</Role>
…
</Employee>
</xsl:if>
</xsl:for-each>
Lack of performance:
o We will see that for each record in the destination schema it will be one for-each element. In fact this is
normal, however when using these type of condition inside recursive records this will means that if we
have 50 occurrences of “Person” node, we will have 50 iterations for each record that we want to map in
the destination schema regardless the number of nodes that we have to map, or if indeed there are data
to map.
o As we can see in the XSLT above, what we can easily achieved with more or less 3 conditions for the entire
map, we are in fact using 3 conditions to accomplish the first mapping rule, more 3 conditions for the
second rule and 9 conditions for the third rule, which means a total of 15 conditions for the entire map.
Readability, Development and Maintainability: You should always need to consider that someone, another team
member, another team or even the client, will need to maintain or apply some chain if necessary in “your” maps.
We easily fill the maps with huge amount of Functoid to archive easy tasks and the more complex is the logic in
your maps, more difficult will be to understand and maintain them. Also untangling the logic of a complex Functoid
chain can be time consuming.
So this approach may be easy to implement and somewhat acceptable in small messages is extremely disadvantageous
for large message.
255
BizTalk Mapping Patterns and Best Practices
Second Solution: Using Inline C# Code to simplify the logic of a complex Functoid chain
In this second approach what we will do is to use small pieces of C# code to simplify the complexity of the Functoid
chain. You will notice that instead of using 11 Functoid to accomplish the transformation rule we will reduce it to 7
Functoids. Again we will sub-divide this mapping problem in two same phases.
Drag one Scripting Functoid and one Logical AND Functoid to the map grid.
Drag a link from the “Role” element in the source element to the Scripting Functoid
o Make double-click in the Scripting Functoid to show the Properties window and then:
In the scripting type select “Inline C#” option
In the Inline script put the following code:
Because we cannot link the upcoming of a Scripting Functoid, even if is return a Boolean value, to control the
creation or not of the destination return, this can only be done with a Logical Functoid. We need to additionally
use one a Logical Functoid for support
o Drag a link from the Scripting Functoid to the Logical AND Functoid
Drag a link from the Logical AND Functoid to the record “BusinessManagers” in the destination schema
Drag a link from the “Name” element in the source schema to the “Name” element in the destination schema
Drag a link from the “Role” element in the source schema to the “Role” element in the destination schema
Finally we need to apply the same steeps but this time for the “BusinessManagers” record, notice that in this case:
256
BizTalk Mapping Patterns and Best Practices
Once again, we need to accomplish the second phase: the default mapping rule. And to accomplish that we need to:
Drag two Logical NOT Functoids and one Logical AND Functoid to the map grid.
Drag a link from the first Scripting Functoids to the first of the Logical NOT Functoid
o Repeat this steep for the second Scripting Functoid
o This will logical negate all the previous equal conditions
Drag a link from each Logical NOT Functoids to the Logical AND Functoid
o This will validate if all the previous equal conditions were false
Drag a link from the Logical AND Functoid to the record “Employee” in the destination schema
Drag a link from the “Name” element in the source schema to the “Name” element in the destination schema
Drag a link from the “Role” element in the source schema to the “Role” element in the destination schema
257
BizTalk Mapping Patterns and Best Practices
Comparing to the previous solution and because we are simplifying in the complexity of the Functoid chain this will
become easier to read and to maintain, and also because we are using less condition (<xsl:if> statements) we will
get slight gains in performance. However we still have the same major limitation that the previous one, and for the
exact same reasons: Lack of performance if we are leading with large messages.
To solve this mapping problem and address the performance problems present in the previous approaches we will
XSLT and implement a combination of the grouping pattern, applying the Muenchian Method technic, and the
conditional pattern to solve some particular rules in the map.
Important Note
As we will see, in some scenarios, especially if we are dealing in recursive nodes, some of conditions rules can be
solved by using grouping techniques explained in the GROUPING PATTERN section, and this sample will be a good
example of that.
To stay consistent, we will still sub-divide this mapping problem in the two same phases as the previous approaches.
The second Scripting Functoid will not have any kind of inputs. Although we will link this Functoid to the
“BusinessManagers” record on the destination schema
o In the second Scripting Functoid, configure to an “Inline XSLT” and In the Inline script put the following
code:
<!-- This will loop through our key base on the Role with CEO or Director
And in the for-each select attribute we are filtering the data by adding a criterion
Basically we are solving this condition problem using a grouping pattern -->
<xsl:for-each select="key('roles','CEO') | key('roles','Director')">
<BusinessManagers>
<Name>
<xsl:value-of select="Name/text()" />
</Name>
<Role>
<xsl:value-of select="Role/text()" />
</Role>
</BusinessManagers>
</xsl:for-each>
258
BizTalk Mapping Patterns and Best Practices
This Functoid also will not have any inputs and we will link the output of this Functoid to the “BusinessAssistant”
record on the destination schema
o In the third Scripting Functoid, configure to an “Inline XSLT” and In the Inline script put the following code:
The transformation for the first phase in archived relatively easily with a small number of Functoids and with a clean
XSLT code with a clean XSLT code and easy to read, although we have to use some advanced concepts, and at one
some point uncommon to see inside BizTalk maps like: Muenchian Method and global variables techniques.
Once again, we need to accomplish the second phase: the default mapping rule. And in this case I want to refer an
existing mapping rule that we need to apply only for the Employees that I deliberately omitted in the previous solutions
because we had already discussed earlier in the BASIC IF… THEN… ELSE CONDITION section:
“CivilStatus” element that in this case is a string (not an enumerator) that can may expect to have two values: M
(Married) or S (Single) that we to convert to their full description on the destination message. However if none of
them are present we need to define the destination value as “Unknown”
Sometimes, the problem is not to block output when a condition is false, but to output an alternate value.
<!-- Applying a XPath query to get all the rest of the roles, this time we are not using the Key
that we used before -->
<xsl:for-each select="Person[(Role != 'CEO') and (Role != 'Director') and (Role != 'Business
Assistant') and (Role != 'Assistant')]">
<Employee>
<Name>
<xsl:value-of select="Name/text()" />
</Name>
<Role>
<xsl:value-of select="Role/text()" />
</Role>
<!-- Applying the Condition Pattern - 'Switch representation/implementation' in XSLT to solve
the CivilStatus rule-->
<xsl:choose>
<xsl:when test="string(AdditionalInfo/CivilStatus/text())='M'">
<CivilStatusDescription>Married</CivilStatusDescription>
</xsl:when>
259
BizTalk Mapping Patterns and Best Practices
<xsl:when test="string(AdditionalInfo/CivilStatus/text())='S'">
<CivilStatusDescription>Single</CivilStatusDescription>
</xsl:when>
<xsl:otherwise>
<CivilStatusDescription>Unknown</CivilStatusDescription>
</xsl:otherwise>
</xsl:choose>
</Employee>
</xsl:for-each>
This is the best approach in terms of performance and a good compromise between BizTalk Mapper and XSLT, we still
have all the Mapper capabilities if we had other blocks to map. It is simple to read and to maintain from a developer
perspective, even for new developers.
Development: We need basic knowledge of XSLT and XPath and we need to understand very well how the BizTalk
Mapper works and knowledge of some advance BizTalk Mapper techniques.
TIP
Avoid spending long hours dealing with a complex Functoid chain that keeps failing each time it is modified. Write
script instead.
Resources
Reference to this pattern:
All source code is available in the Microsoft Code gallery here: BizTalk Mapper Patterns: Conditional
Pattern (http://code.msdn.microsoft.com/BizTalk-Mapper-Patterns-38cb722e)
Looping Pattern
When exchanging messages in an Enterprise application integration (EAI) or Business-to-Business (B2B) some
scenarios need to deal with more complicated types of data manipulation can only reasonably be done using recurring
records or elements (type of arrays in XML documents) and loops and they are extremely useful when manipulating
large number of data. A combination of this two types can save you incredible amounts of time when performing
certain types of repetitive transformations.
260
BizTalk Mapping Patterns and Best Practices
An array is a set of records or elements that are linked together because they represent similar things. The purpose
of the array is to provide a single name that can be used by the Mapper to access any of the entire set of elements.
A loop is used to tell the BizTalk Mapper to perform a set of procedures a specified number of times. Often times
we need to perform the same transformation on a large number of values. By using a loop we only need to define
the transformation once, and can tell it to do the same thing to all the elements using a loop.
For example, certain records typically occur many times in an input file. For example, in a weather report, the
“DailySummary” element might occur many times. The “DailySummary” element might include attributes for the
temperature, the barometric pressure, and the wind speed. That need to be transform according to the target system
specifications. Or in other situations we will have different but similar repeating structures, let’s say “Clients” and
“Employees” that we want to convert and aggregate into a single structure “Person”
In terms of BizTalk Schemas we can indicate a recurring/looping records or elements by set the Max Occurs property
to unbounded (basically unlimited) or to a number higher than 1.
261
BizTalk Mapping Patterns and Best Practices
Despite being easy to implement, looping is one of the most complex problems you will encounter when transforming
data.
This topic will describe the most common looping types that we can encountered, how the BizTalk Mapper engine will
handle looping and as always presenting some common problems and common techniques and best practices that
you may use to solve this common problems.
Some high level concepts are described in the below bullet points:
We are not required to use the Looping Functoid to implement loops. The BizTalk Mapper engine will automatically
infer looping based in the source schema structure, by being an optional record or by the Max Occurs property
being setting to a number higher than 1 or unbounded (unlimited/unspecified). This will force the engine to
generate a looping segment. Normally we can see this inferences on the Hide Compiler Links. Your can find more
information about this here: How to Show and Hide Compiler Links (http://msdn.microsoft.com/en-
us/library/aa560549.aspx).
o The value of these compiler-generated links is that they tell you when you have unexpected links between
the source and target nodes and tell you when you do not have an expected link between the two.
So why use the Looping Functoid? Sometimes the presumptions that the engine will make are not correct and the
use of the Looping Functoid will override the inference made by the mapper engine, forcing the mapping engine to
generate the XSLT code based on the Looping functoid rather than the schema structure. A good example of this
situation will be described in the MANY TO ONE section.
However in some complex looping situations, no matter whether we use or not the Looping Functoid, the mapper
engine can be induced by some kind of rules conflict and produce an unexpected XSLT Code. Fortunately these
situations are not so common and one of the best practices in these cases is to use custom XSLT code, in other
situations we can make use of the Table Looping Functoid that we will address in the
FLAT STRUCTURE TO A REPEATING Structure section.
We mentioned and validated in the HOW MAPS WORKS section that the BizTalk mapping engine traverses the
destination schema from beginning to end and will constructed and executed as links are encountered in the
262
BizTalk Mapping Patterns and Best Practices
destination schema. Nevertheless the mapping engine will drive the generation of inferred loops based on the
source nodes that are linked to the target nodes. So regardless of whether the target node may or may not be
recursive, if the source node is a single instance, the mapping engine will not infer that a loop exists. And the
opposite is also true, if the source node is recursive it doesn’t matter if the target node is recursive or not because
the mapping engine will infer a loop in this situations.
We previous talk about the CONDITIONAL PATTERN and some of the performance problems that some techniques will
produce, specially the IF…THEN…ELSE CONDITION. When working with looping segments, any concerns about
performance are increased, one thing is having a condition that is really not optimized but easy to maintain that will
not have much impact because it only occurs once, another is having the same condition that can occur a hundred
times or more. In these cases analyzing the generated XSLT code and take the necessary measures are a key factor to
implement a good or perfect transformation solution.
There are many different approaches that may be used in looping problems, especially if we are using complex
transformation problems, conditional looping problems and/or transforming flat structures to repeating structures, or
the opposite. All of this situations will be address in this chapter, however for now let’s address simple schemas
structures and business rules and focus on how to handle this different structures inside the BizTalk Mapper forcing
and limiting loops sequences and learn how to deal with looping in BizTalk maps.
Looping Types
If we focus on the schemas we can represent a repeating structure in two types: a repeating record or a repeating
element. And of course we can combine these two types. However if we focus on transformations, we can have several
conjugations of looping types.
Simple looping transformation, where we basically want to transform one recurring structure into another simple
recurring structure, map a single recurring structure in more than one recurring structures in the destination or the
opposite, or we want to combine several structure into one destination structure: One to One, One to Many or
Many to One.
Complex looping transformations, where we basically have complex or several recurring structures that we need
to transform to other complex or several recurring structures in the destination. We can have several distinct
combinations: Many to Many, Nested to One or Nested to Nested.
In this scenario we have a source schema representing surveys forms with the general information: person name and
address information; and with the survey information: survey identification and questions results. And want to get all
the addresses information from the source schema and map them to a basic Address structure available in the
destination schema. Although we have two recursive structures: the parent “GeneralSurvey” record and the son
“Question” record, in the source schema, we will only use one of them because in this case the information inside the
“Question” node is irrelevant to this problem.
Input Output
<GeneralSurvey> <Address
<Name>Sandro Pereira</Name> Name="Sandro Pereira"
263
BizTalk Mapping Patterns and Best Practices
Drag the mouse from the record name “GeneralSurvey” in the source schema, and then drop it to record name
“Address” in the destination schema.
On the shortcut menu, click “Link by Structure” option.
If we inspect the generated code produce by the BizTalk Mapper we will see that despite we didn’t use the Looping
Functoid the compiler will automatically infer a looping based on the source schema structure, which in this case is
the “GeneralSurvey” record that has the “Max Occurs” property defined as “unbounded”:
<ns0:MasterAddresses>
<xsl:for-each select="GeneralSurvey">
<Address>
<xsl:attribute name="Name">
<xsl:value-of select="Name/text()" />
</xsl:attribute>
<xsl:attribute name="Street">
<xsl:value-of select="Address/text()" />
</xsl:attribute>
<xsl:attribute name="City">
<xsl:value-of select="City/text()" />
</xsl:attribute>
<xsl:attribute name="State">
<xsl:value-of select="State/text()" />
264
BizTalk Mapping Patterns and Best Practices
</xsl:attribute>
<xsl:attribute name="PostalCode">
<xsl:value-of select="PostalCode/text()" />
</xsl:attribute>
</Address>
</xsl:for-each>
</ns0:MasterAddresses>
Nevertheless, we often use the Looping Functoid in situations like this where the inferred looping is correct even
though the Looping Functoid has no impact. And one of the reasons why we can and should do this is to improve the
visual readability of the map. By using the Looping Functoid we will have a better and clearer idea that we making a
recursive transformation without having to look inside the XSLT or consulting the schemas.
Drag from the Toolbox window one Looping Functoid and then:
o Drag a link from the “GeneralSurvey” record in the source schema to the Looping Functoid
o And drag a link from the Looping Functoid to the record “Address” in the destination schema
However, in this case, this small change will not affect anything in the map, it will not change or improve the XSLT
code. The only advantage in the visual perception that you have while reading the BizTalk Map.
Note
Although not necessary, but from a readability and maintenance perspective I recommend you to always use the
Looping Functoid as a best practice in this scenarios.
Here we will simplify the problem and we will address and focus how we can handler in terms of looping
implementation these type of situations. In this example we will have a similar scenario that the previous were we will
have the same input message but this time we want to map and split the source information in two structures: one
containing all the Addresses information and another containing all the person names who participated in the survey.
265
BizTalk Mapping Patterns and Best Practices
Input Output
<GeneralSurvey> <Address
<Name>Sandro Pereira</Name> Name="Sandro Pereira"
<Address>7890 Broadway</Address> Street="7890 Broadway"
<City>Columbus</City> City="Columbus"
<State>OH</State> State="OH"
<PostalCode>46290</PostalCode> PostalCode="46290" />
<SurveyId>1</SurveyId> <Address
<Question> Name="Jose Antonio Silva"
<Number>Age?</Number> Street="456 1st Ave"
<Response>35</Response> City="Miami"
</Question> State="FL"
</GeneralSurvey> PostalCode="81406" />
<GeneralSurvey> <Person Name="Sandro Pereira" />
<Name>Jose Antonio Silva</Name> <Person Name="Jose Antonio Silva" />
<Address>456 1st Ave</Address>
<City>Miami</City>
<State>FL</State>
<PostalCode>81406</PostalCode>
<SurveyId>2</SurveyId>
<Question>
<Number>Age?</Number>
<Response>40</Response>
</Question>
</GeneralSurvey>
Again we don’t really need to use the Looping Functoid to implement and solve this problem because the mapping
engine will automatically, and correctly, infer the looping’s based on the source schema structure, we can validate this
266
BizTalk Mapping Patterns and Best Practices
by simple check these compiler-generated links between the source and target nodes (in the option “Double-click here
to show/hide compiler links” present in the Error List window)
Or if we look to the generated code produce by the BizTalk Mapper we will see that it automatically generated two
<xsl:for-each> statements for us:
<ns0:Lists>
<!-- Loop to generate the Address Record Structure-->
<xsl:for-each select="GeneralSurvey">
<Address>
<xsl:attribute name="Street">
<xsl:value-of select="Address/text()" />
</xsl:attribute>
<xsl:attribute name="City">
<xsl:value-of select="City/text()" />
</xsl:attribute>
<xsl:attribute name="State">
<xsl:value-of select="State/text()" />
</xsl:attribute>
<xsl:attribute name="PostalCode">
<xsl:value-of select="PostalCode/text()" />
</xsl:attribute>
</Address>
</xsl:for-each>
<!-- Loop to generate the Person Record Structure-->
<xsl:for-each select="GeneralSurvey">
<Person>
<xsl:attribute name="Name">
<xsl:value-of select="Name/text()" />
</xsl:attribute>
</Person>
</xsl:for-each>
</ns0:Lists>
As the previous example, we can improve the visually readable by using the Looping Functoid and once again it will
not affect anything in the map and we can place the transformation rules in different grid pages for a better map
organization and readability.
Drag from the Toolbox window one Looping Functoid and then:
o Drag a link from the “GeneralSurvey” record in the source schema to the Looping Functoid
o And drag a link from the Looping Functoid to the record “Address” in the destination schema
267
BizTalk Mapping Patterns and Best Practices
Drag from the Toolbox window one Looping Functoid and then:
o Drag a link from the “GeneralSurvey” record in the source schema to the Looping Functoid
o And drag a link from the Looping Functoid to the record “Person” in the destination schema
Note
We could use the same Looping Functoid to link both “Address” and “Person” records, but again from a readability
and maintenance perspective, I recommend you in this case to use two Looping Functoid one in each page as a best
practice. Internally they are interpreted in the same way by the BizTalk Mapper compiler, this is just a matter of
visually organization.
In this scenario we have a source schema representing the different participants and proposals candidates to
implement a project, were we will have 3 similar structure in the source schema:
A repeating node “Vendor” representing all the partner who applied to this project;
A mandatory node “Client” that can occurs only one time representing the final customer (note that this is not a
repeating record)
And another repeating node “DecisionMakers” representing the persons responsible for deciding who wins the
project;
268
BizTalk Mapping Patterns and Best Practices
Input Output
<ProjectName>ProjectName_0</ProjectName> <ProjectName>ProjectName_0</ProjectName>
<ProjectReference>ProjectReference_0</ProjectReference> <ProjectReference>ProjectReference_0</ProjectReference>
<Vendor> <Participant>
<Company>Vendor1</Company> <Company>Vendor1</Company>
<ContactName>Sandro Pereira</ContactName> <ContactName>Sandro Pereira</ContactName>
<ContactRole>Architect</ContactRole> <ContactRole>Architect</ContactRole>
<Address>AddressVendor1</Address> <Address>AddressVendor1</Address>
<City>CityVendor1</City> <City>CityVendor1</City>
</Vendor> <Type>Vendor</Type>
<Vendor> </Participant>
<Company>Vendor2</Company> <Participant>
<ContactName>ContactNameVendor2</ContactName> <Company>Vendor2</Company>
<ContactRole>RoleVendor2</ContactRole> <ContactName>ContactNameVendor2</ContactName>
<Address>AddressVendor2</Address> <ContactRole>RoleVendor2</ContactRole>
<City>CityVendor2</City> <Address>AddressVendor2</Address>
</Vendor> <City>CityVendor2</City>
<Client> <Type>Vendor</Type>
<Company>DevScope</Company> </Participant>
<ContactName>Rui Barbosa</ContactName> <Participant>
<ContactRole>CTO</ContactRole> <Company>DevScope</Company>
<Address>Portugal</Address> <ContactName>Rui Barbosa</ContactName>
<City>Porto</City> <ContactRole>CTO</ContactRole>
</Client> <Address>Portugal</Address>
<DecisionMakers> <City>Porto</City>
<Company>DevScope</Company> <Type>Client</Type>
<ContactName>Jose Antonio Silva</ContactName> </Participant>
<ContactRole>RD</ContactRole> <Participant>
<Address>Portugal</Address> <Company>DevScope</Company>
<City>Porto</City> <ContactName>Jose Antonio Silva</ContactName>
</DecisionMakers> <ContactRole>RD</ContactRole>
<DecisionMakers> <Address>Portugal</Address>
<Company>DevScope</Company> <City>Porto</City>
<ContactName>Miguel Silva</ContactName> <Type>DecisionMakers</Type>
<ContactRole>Manager</ContactRole> </Participant>
<Address>Portugal</Address> <Participant>
<City>Porto</City> <Company>DevScope</Company>
</DecisionMakers> <ContactName>Miguel Silva</ContactName>
<ContactRole>Manager</ContactRole>
<Address>Portugal</Address>
<City>Porto</City>
<Type>DecisionMakers</Type>
</Participant>
And we need to map this three structures into one common repeating structure “Participant” that represents all
participants in this project tender. So in this cases, the structure of a message from a source system you are integrating
with contains multiple repeating record types. You must map each of these record types into one record type in the
269
BizTalk Mapping Patterns and Best Practices
destination system. In order for the message to be imported into the destination system, a transformation must be
applied to the source document to consolidate, or standardize, the message structure.
Drag the mouse from the record name “Vendor” in the source schema, and then drop it to record name
“Participant” in the destination schema.
On the shortcut menu, click “Link by Name” option. This will map automatically the following elements: “Company”,
“ContactName”, “ContactRole”, “Address” and “City”
We then have a “Type” element in the destination schema were we need to specify which type of participant it his:
Vendor, Client or a Decision Maker, to implement this rule we need to:
o Drag a link from the record name “Vendor” in the source schema to the “Type” element in the destination
schema
o Select this link and press the “F4” key, in other words, go to the properties of the link and in the “Source
Links” property drop box select the option: “Copy name”
Now let’s for a moment forget the “DecisionMakers” record (the last record) and replay only the same steps described
above to the “Client” record to test our solution and see what happens, at the end the map will look like this:
270
BizTalk Mapping Patterns and Best Practices
We saw in the last two previous samples, ONE TO ONE and ONE TO MANY, we didn't need to use the Looping Functoid to
properly implement the mapping rules because the mapping engine will correctly infer these looping rules for us.
However in this case if we try to test this partial transformation we will notice that the end result is not quite what we
expected:
<ns0:ProjectParticipant xmlns:ns0="http://LoopingPattern.ProjectParticipant">
<ProjectName>ProjectName_0</ProjectName>
<ProjectReference>ProjectReference_0</ProjectReference>
<Participant>
<Company>Company_0</Company>
<Company>Company_0</Company>
<ContactName>ContactName_0</ContactName>
<ContactName>ContactName_0</ContactName>
<ContactRole>ContactRole_0</ContactRole>
<ContactRole>ContactRole_0</ContactRole>
<Address>Address_0</Address>
<Address>Address_0</Address>
<City>City_0</City>
<City>City_0</City>
<Type>Vendor</Type>
<Type>Client</Type>
</Participant>
</ns0:ProjectParticipant>
We can also see that the compiler-generated links between the source and target nodes is not quite what we were
expecting and we can see that is missing links from the “Client” and “DecisionMakers” source nodes to the destination
node “Participant”:
271
BizTalk Mapping Patterns and Best Practices
To understand this behavior we once again need to inspect the XSLT generated code produce by the BizTalk Mapper.
And in this case we notice that the presumptions that the engine will make are not correct. The compiler will only infer
one <xsl:for-each> statement based on the source structure of the first rule that it catch, in this case the “Vendor”
record. And inside of this <xsl:for-each> statement it will add all the remaining rules (see DECONSTRUCTING A MAP
section in HOW MAPS WORKS chapter):
The BizTalk mapping engine traverses the destination schema from beginning to end and the first rule encountered
is the <xsl:for-each> statement, explained above.
The second rule encountered is the “Company” element in which the mapping rules are constructed and executed
for all the links that are encountered in the destination schema;
o And as you can see in the XSLT below, this will generated in two Company elements: one extracted from
the “Vendor” record and the other extracted from the “Client” record in the source schema
And the same behavior will be apply for the rest of the elements.
<xsl:for-each select="Vendor">
<Participant>
<Company>
<xsl:value-of select="Company/text()" />
</Company>
<Company>
<xsl:value-of select="../Client/Company/text()" />
</Company>
<ContactName>
<xsl:value-of select="ContactName/text()" />
</ContactName>
<ContactName>
<xsl:value-of select="../Client/ContactName/text()" />
</ContactName>
<ContactRole>
<xsl:value-of select="ContactRole/text()" />
</ContactRole>
<ContactRole>
<xsl:value-of select="../Client/ContactRole/text()" />
</ContactRole>
<Address>
272
BizTalk Mapping Patterns and Best Practices
When the looping structure in the source does not match the structure in the target, or when we need to map data
from two or more looping nodes in the source to data within a single target node, you may need to override the
compiler-generated looping. In most cases, use of the Looping Functoid will be sufficient. In other cases, you may need
to use custom XSLT or in some cases the Table Looping Functoid.
In this particular situation we must use the Looping Functoid to override the presumptions made by the mapper
engine, forcing it to generate the XSLT code based on the Looping functoid rather than the schema structure.
The first approach that normally comes to mind is two or three Looping Functoids, each one for each different record
in the source schema:
However, by using this approach we are in fact telling it to apply the same bad presumptions that it previous made in
the last approach. If we inspect the XSLT code generated we will see that is exactly the same.
The correct way to deal with these scenarios is actually to use just a single Looping Functoid common to all the source
structures that we need to map.
273
BizTalk Mapping Patterns and Best Practices
Important Tip
When mapping one record from the source schema to two or more different records in the destination schema we
can use two or more Looping Functoids to accomplish these transformation rules, e.g., one for each different record
in the destination schema. However when mapping two or more different records from the source schema to one
single record in the destination schema we can only use one single Looping Functoid to link every source record to
the destination record.
Drag from the Toolbox window one Looping Functoid and then:
o Drag a link from the “Vendor” record in the source schema to the Looping Functoid
o Drag a link from the “Client” record in the source schema to the Looping Functoid
o And drag a link from the Looping Functoid to the record “Participant” in the destination schema
Apply the same steps described above to the “DestinationMakers” record and we have all the mapping rules
implemented. Now if we try to test once again our map, we will see a different and this time a perfect expected result:
<ns0:ProjectParticipant xmlns:ns0="http://LoopingPattern.ProjectParticipant">
<ProjectName>ProjectName_0</ProjectName>
<ProjectReference>ProjectReference_0</ProjectReference>
<Participant>
<Company>Company_0</Company>
<ContactName>ContactName_0</ContactName>
<ContactRole>ContactRole_0</ContactRole>
<Address>Address_0</Address>
<City>City_0</City>
<Type>Vendor</Type>
</Participant>
<Participant>
<Company>Company_0</Company>
<ContactName>ContactName_0</ContactName>
<ContactRole>ContactRole_0</ContactRole>
<Address>Address_0</Address>
<City>City_0</City>
<Type>Client</Type>
</Participant>
</ns0:ProjectParticipant>
274
BizTalk Mapping Patterns and Best Practices
By making use of this “common” Looping Functoids we are in fact telling the engine that for each structure linked to
this Functoid it will need to infer the right rules for each based on their source structure, in this case we will see:
One first <xsl:for-each> statement to apply the rules of the “Vendor” record because this record can occur
several times;
A simple transformation rules, without loop, to map the “Client” record because the this record only occur one
time;
One second <xsl:for-each> statement to apply the rules of the “DecisionMakers” record because this record also
can occur several times;
<xsl:for-each select="Vendor">
<Participant>
<Company>
<xsl:value-of select="Company/text()" />
</Company>
<ContactName>
<xsl:value-of select="ContactName/text()" />
</ContactName>
<ContactRole>
<xsl:value-of select="ContactRole/text()" />
</ContactRole>
<Address>
<xsl:value-of select="Address/text()" />
</Address>
<City>
<xsl:value-of select="City/text()" />
</City>
<Type>Vendor</Type>
</Participant>
</xsl:for-each>
<Participant>
<Company>
<xsl:value-of select="Client/Company/text()" />
</Company>
<ContactName>
<xsl:value-of select="Client/ContactName/text()" />
</ContactName>
<ContactRole>
<xsl:value-of select="Client/ContactRole/text()" />
</ContactRole>
<Address>
<xsl:value-of select="Client/Address/text()" />
</Address>
<City>
<xsl:value-of select="Client/City/text()" />
</City>
<Type>Client</Type>
</Participant>
<xsl:for-each select="DecisionMakers">
<Participant>
…
</Participant>
</xsl:for-each>
275
BizTalk Mapping Patterns and Best Practices
This looping scenario is similar to the previous one (MANY TO ONE LOOPING), the only difference is that we need to split
the content of the input message in two different structures:
“ExternalParticipant”: containing all the external participants who applied to this project, i.e., all the data present
in the “Vendor” source record;
And “InternalParticipant”: containing all the internal participants of the company who are owner and decision
makers of this project: “Client” and “DecisionMakers” source records.
Input Output
<ProjectName>ProjectName_0</ProjectName> <ProjectName>ProjectName_0</ProjectName>
<ProjectReference>ProjectReference_0</ProjectReference> <ProjectReference>ProjectReference_0</ProjectReference>
<Vendor> <ExternalParticipant>
<Company>Vendor1</Company> <Company>Vendor1</Company>
<ContactName>Sandro Pereira</ContactName> <ContactName>Sandro Pereira</ContactName>
<ContactRole>Architect</ContactRole> <ContactRole>Architect</ContactRole>
<Address>AddressVendor1</Address> <Address>AddressVendor1</Address>
<City>CityVendor1</City> <City>CityVendor1</City>
</Vendor> </ExternalParticipant>
<Vendor> <ExternalParticipant>
<Company>Vendor2</Company> <Company>Vendor2</Company>
<ContactName>ContactNameVendor2</ContactName> <ContactName>ContactNameVendor2</ContactName>
<ContactRole>RoleVendor2</ContactRole> <ContactRole>RoleVendor2</ContactRole>
<Address>AddressVendor2</Address> <Address>AddressVendor2</Address>
<City>CityVendor2</City> <City>CityVendor2</City>
</Vendor> </ExternalParticipant>
<Client> <InternalParticipant>
<Company>DevScope</Company> <Company>DevScope</Company>
<ContactName>Rui Barbosa</ContactName> <ContactName>Rui Barbosa</ContactName>
<ContactRole>CTO</ContactRole> <ContactRole>CTO</ContactRole>
<Address>Portugal</Address> <Address>Portugal</Address>
<City>Porto</City> <City>Porto</City>
</Client> <Type>Client</Type>
<DecisionMakers> </InternalParticipant>
<Company>DevScope</Company> <InternalParticipant>
<ContactName>Jose Antonio Silva</ContactName> <Company>DevScope</Company>
<ContactRole>RD</ContactRole> <ContactName>Jose Antonio Silva</ContactName>
<Address>Portugal</Address> <ContactRole>RD</ContactRole>
<City>Porto</City> <Address>Portugal</Address>
</DecisionMakers> <City>Porto</City>
<DecisionMakers> <Type>DecisionMakers</Type>
<Company>DevScope</Company> </InternalParticipant>
<ContactName>Miguel Silva</ContactName> <InternalParticipant>
<ContactRole>Manager</ContactRole> <Company>DevScope</Company>
<Address>Portugal</Address> <ContactName>Miguel Silva</ContactName>
<City>Porto</City> <ContactRole>Manager</ContactRole>
</DecisionMakers> <Address>Portugal</Address>
276
BizTalk Mapping Patterns and Best Practices
<City>Porto</City>
<Type>DecisionMakers</Type>
</InternalParticipant>
277
BizTalk Mapping Patterns and Best Practices
Some of you are familiar with EDI schemas and purchase orders, the EDI schema is a very complex structure with
several Nested recursive segments inside it. In this scenario we will simplify the EDI order schema into a custom
Purchase Order schema were we will have a NAD segment that specify the name/address and their related function
(Code identifying a party involved in a transaction) and an Item segment describing the items involved in this purchase.
And we want to map this EDI Purchase Order into an internal order to be sent to our internal system in which we must:
Separate the different party involved, based on their identifier, to map the different addresses present in the order
in context with the target schema: ship to address, bill to address and ship from address.
We also need to acquire the name of the client, based on their identifier.
And finally map all the Items presented in the order and calculate the number of different items, we should consider
that with don’t have different lines with the same item, so we need to calculate the number of lines present in the
order.
A nested loop occurs when one loop is a child of another loop. In this case the source data contains several parties
(NAD record) and each party may have one or several address defined. So each address (ship to/from and bill) we want
to map are in fact inside two loops segments, one for the NAD and the second for the Address.
Note
In this more complex scenario we are combining two patterns: the looping pattern and the conditional pattern. And
we will address some of the questions you should have when performing this operations.
278
BizTalk Mapping Patterns and Best Practices
Input Output
<OrderDate>2014-05-21 18:00:00</OrderDate> <NAD>
<Client>DevScope</Client> <PartyIdentifier>supplier</PartyIdentifier>
<ShipTo> <Name>Microsoft</Name>
<Contact>Marcia teixeira</Contact> <Address>
<Country>Portugal</Country> <Type>SU</Type>
<Street> <Country>Portugal</Country>
Rua Passos Manuel, 223 - 4 Andar <Street>
</Street> Rua Sinais de Fogo Lote 2.07.02
<City>Porto</City> </Street>
<Zip>4000-385</Zip> <City>Lisboa</City>
</ShipTo> <Zip>1990–110</Zip>
<BillTo> </Address>
<Contact>Sandro Pereira</Contact> </NAD>
<Country>Portugal</Country> <NAD>
<Street> <PartyIdentifier>buyer</PartyIdentifier>
Rua Passos Manuel, 223 - 4 Andar <Name>DevScope</Name>
</Street> <Address>
<City>Porto</City> <Type>VA</Type>
<Zip>4000-385</Zip> <Contact>Marcia teixeira</Contact>
</BillTo> <Country>Portugal</Country>
<ShipFrom> <Street>
<Country>Portugal</Country> Rua Passos Manuel, 223 - 4 Andar
<Street> </Street>
Rua Sinais de Fogo Lote 2.07.02 <City>Porto</City>
</Street> <Zip>4000-385</Zip>
<City>Lisboa</City> </Address>
<Zip>1990–110</Zip> <Address>
</ShipFrom> <Type>BY</Type>
<Items> <Contact>Sandro Pereira</Contact>
<ItemLines>2</ItemLines> <Country>Portugal</Country>
<Item> <Street>
<PartNum>1</PartNum> Rua Passos Manuel, 223 - 4 Andar
<ProductName> </Street>
Microsoft BizTalk Server 2013 Enterprise <City>Porto</City>
279
BizTalk Mapping Patterns and Best Practices
</ProductName> <Zip>4000-385</Zip>
<Quantity>3</Quantity> </Address>
</Item> </NAD>
<Item> <Items>
<PartNum>2</PartNum> <Item>
<ProductName> <PartNum>1</PartNum>
SQL Server 2012 Enterprise <ProductName>
</ProductName> Microsoft BizTalk Server 2013 Enterprise
<Quantity>2</Quantity> </ProductName>
</Item> <Quantity>3</Quantity>
</Items>> </Item>
<Item>
<PartNum>2</PartNum>
<ProductName>
SQL Server 2012 Enterprise
</ProductName>
<Quantity>2</Quantity>
</Item>
</Items>
To map the general info in the destination schema, order date and client name, we need to:
o Drag a link from the “OrderDate” field element in the source schema to the “OrderDate” field element in
the destination schema
o Drag one Equal Functoid from the Toolbox window onto the Grid and then.
Drag a link from the “PartyIdentifier” field element in the source schema to the Equal Functoid
Make double-click in the Equal Functoid to show the Properties window and then:
o Specify the second condition (second input parameter) as “buyer”
And drag a link from the Equal Functoid to the “Client” element in the destination schema
280
BizTalk Mapping Patterns and Best Practices
Note
In this case we don’t use the Looping Functoid because, despite the “Address” occurs several times in the source
schema, the records: “ShipTo”, “BillTo” and “ShipFrom” only occurs one time in the destination schema.
Apply the same previous steps for mapping the records: “BillTo” and “ShipFrom”
o Set the second parameter of the Equal Functoid associated with the “BillTo” as: “BY”
o Set the second parameter of the Equal Functoid associated with the “ShipFrom” as: “SU”
To map the Item Lines info in the destination schema we need to:
o Drag one Record Count Functoid from the Toolbox window onto the Grid, to count the number of records
in the input instance message, and then.
Drag a link from the “Item” record in the source schema to the Record Count Functoid
And drag a link from the Record Count Functoid to the “ItemLines” element in the destination
schema
o Drag from the Toolbox window one Looping Functoid and then:
Drag a link from the “Item” record in the source schema to the Looping Functoid
And drag a link from the Looping Functoid to the record “Item” in the destination schema
o Drag the mouse from the record name “Item” in the source schema, and then drop it to record name “Item”
in the destination schema.
On the shortcut menu, click “Link by Name” option
281
BizTalk Mapping Patterns and Best Practices
Readability: Very easy to visual read the rules, doesn’t requires any experience and is actually very easy to
implement.
Performance: This approach will produce some extra unnecessary code that will force to perform extra steps in the
operations that in the global context of the map can induce some several lack performances in some scenarios
(large messages).
Let’s take a look at the XSLT code generated by the mapper compiler for the “Client” name in the general info page,
we will see that we need to perform a full loop through the NAD record to find the client name associated with
PartyIdentifier: "Buyer".
<!-- Loop through the NAD record to look for the name associated with PartyIdentifier "Buyer" -->
<xsl:for-each select="NAD">
<xsl:variable name="var:v1" select="userCSharp:LogicalEq(string(PartyIdentifier/text()) ,
"buyer")" />
<xsl:if test="$var:v1">
<Client>
<xsl:value-of select="Name/text()" />
</Client>
</xsl:if>
</xsl:for-each>
If we take a look to how the mapper engine will render the mapping rules associated with the records: “ShipTo”,
“BillTo” and “ShipFrom”, we will see that for destination record the engine will create two <xsl:for-each>
statements, one for travelling through all NAD records and the second to travelling through all the Address records. In
fact this is a normal behavior of the BizTalk Mapper Engine, however when using these type of condition approach
inside recursive records it can be a little dangerous when we are dealing with large messages. Because this will mean
282
BizTalk Mapping Patterns and Best Practices
that if we have 100 occurrences of “NAD” node, we will have 100 iterations, and for this 100 iterations we still need
to count and add the number of iterations associated with the number of “Address” occurrence inside each “NAD”
node, for each record that we want to map in the destination schema. So for this simple task we sometimes need to
apply without really knowing several operations or iterations which in the end may cause some performance problems.
<!-- Loop through the Address record in each NAD records to look for the Type "VA" -->
<xsl:for-each select="NAD">
<xsl:for-each select="Address">
<xsl:variable name="var:v2" select="userCSharp:LogicalEq(string(Type/text()) , "VA")"
/>
<xsl:if test="$var:v2">
<ShipTo>
<xsl:if test="Contact">
<Contact>
<xsl:value-of select="Contact/text()" />
</Contact>
</xsl:if>
<Country>
<xsl:value-of select="Country/text()" />
</Country>
<Street>
<xsl:value-of select="Street/text()" />
</Street>
<City>
<xsl:value-of select="City/text()" />
</City>
<Zip>
<xsl:value-of select="Zip/text()" />
</Zip>
</ShipTo>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
<!-- Loop through the Address record in each NAD records to look for the Type "BY" -->
<xsl:for-each select="NAD">
<xsl:for-each select="Address">
<xsl:variable name="var:v3" select="string(Type/text())" />
<xsl:variable name="var:v4" select="userCSharp:LogicalEq($var:v3 , "BY")" />
<xsl:if test="$var:v4">
<BillTo>
…
</BillTo>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
So this approach may be easy to implement and somewhat acceptable in small/medium messages is extremely
disadvantageous for large message.
283
BizTalk Mapping Patterns and Best Practices
In the “Inline script” text box enter the following XSLT code:
<Client>
<xsl:value-of select="NAD[PartyIdentifier/text() = 'buyer']/Name/text()" />
</Client>
o Drag a link from the Scripting Functoid to the “Client” field element in the destination schema
o Drag a link from the Scripting Functoid to the “ShipTo” record in the destination schema
o Apply the same steps for the two remains Functoids
The second Functoid will link to the “BillTo” record in the destination schema and the main
difference is the XPath expression that we need to apply in the <xsl:for-each> statement
<xsl:for-each select="NAD[PartyIdentifier/text() = 'buyer']/Address[Type/text() = 'BY']">
…
284
BizTalk Mapping Patterns and Best Practices
And the third Functoid will link to the “ShipFrom” record in the destination schema, again the
mainly difference is the XPath query that we need to use:
<xsl:for-each select="NAD[PartyIdentifier/text() = 'supplier']/Address[Type/text() = 'SU']">
With this two changes, and despite the need now to access the content of Functoids to fully read and understand the
transformations rules, this approach is still very easy to read and to maintain and we will obtain significant
improvements in the overall performance of the message processing.
Sometimes we wonder why we don't skip the BizTalk Mapper and make the transformation rules in an external XSLT
file fully customized (EXTERNAL CUSTOM XSLT FILE VS. BIZTALK MAPPER). In my personal opinion this is a good example why
I like to use Custom Inline XSLT instead of custom XSLT Files. Inn this example from all the mapping problem we just
only had problems, in which we had to make optimizations to get a better performance, in half of the transformation:
the client name and the address (Bill, ship and from) rules, the other half is quite well implemented: dates and Items.
So instead of losing all the BizTalk Mapper capabilities, that was what would happen if we used a custom XSLT File, we
optimize the section with “problems” by using custom inline XSLT, and we were able to use all of the BizTalk Mapper
capabilities to implement the rest of the transformation rules. By using at what I refer as ““the best of both worlds“
by mixing the BizTalk Mapper capabilities and based Functoids with scripting Functoids with different types of scripts
that will fit better in the rule involved we will gain:
A better Readability, Overview and Maintainability of the mapper and the Level of effort in performing some
changes will be greatly reduced, because using an External XSLT File will need a developer with strong knowledge
of XSLT, and even for them any changes required will take some time: In the other hand by using “the best of both
worlds“ even for a new BizTalk developer or developers from another team it will more easy for them to
troubleshoot and/or change these type of map, because they can visually read the map and they are familiar with
the Mapping tool.
285
BizTalk Mapping Patterns and Best Practices
A nested loop is a loop within a loop, an inner loop within the body of an outer one. How this works is that the first
pass of the outer loop triggers the inner loop, which executes to completion. Then the second pass of the outer loop
triggers the inner loop again. This repeats until the outer loop finishes.
In this case we will have both source and destination schemas with an equal structure, only with a different naming
convention, and we will map all of the data from the source schema to the destination schema without applying any
type of conditions.
Input Output
<Account> <NewAccount>
<AccountName>Sandro Pereira</AccountName> <AccountName>Sandro Pereira</AccountName>
<AccountId>1</AccountId> <AccountId>1</AccountId>
<AccountBuild AccountBuildId="01"> <AccountBuildId>01</AccountBuildId>
<AccountProduct> <AssociatedProduct>
<AccountProductId>AccProd_01</AccountProductId> <AccountProductId>
<ProductId>Prod_01</ProductId> AccProd_01
</AccountProduct> </AccountProductId>
<AccountProduct> <ProductId>Prod_01</ProductId>
<AccountProductId>AccProd_02</AccountProductId> </AssociatedProduct>
<ProductId>Prod_02</ProductId> <AssociatedProduct>
</AccountProduct> <AccountProductId>
</AccountBuild> AccProd_02
</Account> </AccountProductId>
<Account> <ProductId>Prod_02</ProductId>
<AccountName>Celso Renato</AccountName> </AssociatedProduct>
<AccountId>2</AccountId> </NewAccount>
<AccountBuild AccountBuildId="02"> <NewAccount>
<AccountProduct> <AccountName>Celso Renato</AccountName>
<AccountProductId>AccProd_02</AccountProductId> <AccountId>2</AccountId>
<ProductId>Prod_02</ProductId> <AccountBuildId>02</AccountBuildId>
</AccountProduct> <AssociatedProduct>
</AccountBuild> <AccountProductId>
</Account> AccProd_02
</AccountProductId>
<ProductId>Prod_02</ProductId>
</AssociatedProduct>
</NewAccount>
Drag from the Toolbox window one Looping Functoid and then:
o Drag a link from the “Account” record in the source schema to the Looping Functoid
o And drag a link from the Looping Functoid to the record “NewAccount” in the destination schema
286
BizTalk Mapping Patterns and Best Practices
Drag a link from the “AccountName” field element in the source schema to the “AccountName” field element in
the destination schema
Drag a link from the “AccountId” field element in the source schema to the “AccountId” field element in the
destination schema
Drag a link from the “AccountBuildId” field element present in the record “AccountBuild” in the source schema to
the “AccountBuildId” field element in the destination schema
Drag from the Toolbox window one Looping Functoid and then:
o Drag a link from the “AccountProduct” record in the source schema to the Looping Functoid
o And drag a link from the Looping Functoid to the record “AssociatedProduct” in the destination schema
Drag a link from the “AccountProductId” field element in the source schema to the “AccountProductId” field
element in the destination schema
Drag a link from the “ProductId” field element in the source schema to the “ProductId” field element in the
destination schema
When the source and target loop structures are the same, mapping is normally not complicated by their presence.
When the loop structures differ, mapping is often more difficult. But let’s take a look to a more complex scenario.
In this scenario we will have a Family School form describing all families enrolled in school, with the parents and
children information for each family. And we need to map this source schema to a similar internal Application Form
schema in which we need to apply some basic transformation rules:
We need to add a Form line id that is not present in the source schema
In each form, that represents one specific family, we need to calculate the number of children the family has
enrolled in the school
For each parent we need to translate the Sex attribute (M/F) to its parent type full description: Father or Mother
And of course map the parent and the children for their respective structures in the target schema.
Input Output
<Family> <Form>
<Parents> <LineId>1</LineId>
<Name Sex="M">Kevin Nealon</Name> <TotalOfChildren>2</TotalOfChildren>
<Name Sex="F">Bella Thorne</Name> <Parents>
<Child> <Parent>
<Name>Sophia Nealon</Name> <Name>Kevin Nealon</Name>
<Age>6</Age> <Type>Father</Type>
<Sex>F</Sex> </Parent>
</Child> <Parent>
287
BizTalk Mapping Patterns and Best Practices
Drag from the Toolbox window one Looping Functoid and then:
o Drag a link from the “Family” record in the source schema to the Looping Functoid
o And drag a link from the Looping Functoid to the record “Form” in the destination schema
Drag from the Toolbox window one Iteration Functoid and then:
o Drag a link from the “Family” record in the source schema to the Iteration Functoid
o And drag a link from the Iteration Functoid to the “LineId” field element in the destination schema
Drag from the Toolbox window one Record Count Functoid and then:
o Drag a link from the “Child” record in the source schema to the Record Count Functoid
o And drag a link from the Record Count Functoid to the “TotalOfChildren” field element in the destination
schema
288
BizTalk Mapping Patterns and Best Practices
However if we try to analyze the result of this small part of the transformation with a sample file were we have 3
families, one with 2 children’s and the other 2 with only one children, we will see that the result is not what we exactly
expect.
<ns0:ApplicationForm xmlns:ns0="http://LoopingPattern.SchoolApplicationForm">
<Form>
<LineId>1</LineId>
<TotalOfChildren>4</TotalOfChildren>
</Form>
<Form>
<LineId>2</LineId>
<TotalOfChildren>4</TotalOfChildren>
</Form>
<Form>
<LineId>3</LineId>
<TotalOfChildren>4</TotalOfChildren>
</Form>
</ns0:ApplicationForm>
The reason why this happens is that the Record Count Functoid in not bound to the context scope of the looping
sequence. Instead it will returns the total number of a specific record or element appears in the entire message, and
unfortunately it does not allow you to specify a scoping parameter. In this particular sample the result of this Functoid
is translated to the following XSLT rule:
And as you can see, it will query for the entire number of occurrences of the record Child in the entire message. What
we expect to have was a scoped record count translated to the following expression:
In order to archive Scoped Record Counting we should use a different approach and use a combination of Functoids:
289
BizTalk Mapping Patterns and Best Practices
This will scope our counting process and provide us with the expected results of the number of Children per family.
<ns0:ApplicationForm xmlns:ns0="http://LoopingPattern.SchoolApplicationForm">
<Form>
<LineId>1</LineId>
<TotalOfChildren>2</TotalOfChildren>
</Form>
<Form>
<LineId>2</LineId>
<TotalOfChildren>1</TotalOfChildren>
</Form>
<Form>
<LineId>3</LineId>
<TotalOfChildren>1</TotalOfChildren>
</Form>
</ns0:ApplicationForm>
Note
At the end of this exercise we will explain in details for you to understand why the new functoids changed the
underlying behavior of the map and its limitations/disadvantages. To accomplish that we will need inspect the XSLT
generated code produce by the BizTalk Mapper compiler.
Once solved the problem of calculating the total number of children per family, we will address the remaining missing
290
BizTalk Mapping Patterns and Best Practices
transformation rules: translate the Sex attribute (M/F) to its parent type full description: Father or Mother; and of
course map the parent and the children for their respective structures in the target schema.
Drag from the Toolbox window one Looping Functoid and then:
o Drag a link from the “Name” field record in the source schema to the Looping Functoid
o And drag a link from the Looping Functoid to the record “Parent” in the destination schema
Drag a link from the “Name” field record in the source schema to the “Name” field element in the destination
schema
Drag from the Toolbox window:
o One Equal Functoid
o One Logical NOT Functoid
o And two Value Mapping Functoid
Drag a link from the “Sex” field attribute in the source schema to the Equal Functoid
o Make double-click in the Equal Functoid to show the Properties window and then:
Specify the second condition (second input parameter) as “M”
Drag a link from the Equal Functoid to the first Value Mapping Functoid.
o Make double-click in the Value Mapping Functoid to show the Properties window and then:
Specify the second condition (second input parameter) as “Father”
o Drag a link from the Value Mapping to the “Type” field element in the destination schema
Drag a link from the Equal Functoid to the Logical NOT Functoid and then drag a link from the Logical NOT Functoid
to the second Value Mapping Functoid;
o Make double-click in the Value Mapping Functoid to show the Properties window and then:
Specify the second condition (second input parameter) as “Mother”
o Drag a link from the Value Mapping to the “Type” field element in the destination schema
Finally we need to map the Children structure to the destination schema, to accomplish that we need to:
Drag from the Toolbox window one Looping Functoid and then:
291
BizTalk Mapping Patterns and Best Practices
o Drag a link from the “Child” record in the source schema to the Looping Functoid
o And drag a link from the Looping Functoid to the record “Child” in the destination schema
Drag the mouse from the record name “Child” in the source schema, and then drop it to record name “Child” in
the destination schema.
o On the shortcut menu, click “Link by Name” option.
This is quite a good solution, in fact the only problem/limitation that we can point is the rule which makes the
calculation of the number of children per family. And the reason why is that we need to use 3 Functoids to implement
a scope in the record count process. Basically we are travelling all the “Parents” nodes that exists in the specific Family
node, and count them by using the strategy of checking if the record exist, which will be always true since we are
inside a <xsl:for-each> statement through the “Parents” record, just to translate de value to be passed for the
cumulative sum operation to “1” and therefor implement a counter. As we can see in the generated XSLT code:
<xsl:for-each select="Parents">
<!-- For each "Parents" the counter is restarted -->
<xsl:variable name="var:v2" select="userCSharp:InitCumulativeSum(0)" />
<!-- Begin: Calculation of the total number of children per family -->
<xsl:for-each select="Child">
<!-- The Existent Functoids is just used for support to pass a True value for the Value
Mapping Functoid, however unfortunately it creates an unnecessary if condition -->
<xsl:variable name="var:v3" select="userCSharp:LogicalExistence(boolean(.))" />
<xsl:if test="string($var:v3)='true'">
<!-- Value 1 that will be sent by the Value Mapping Functoid to the Cumulative Sum Functoid to
increase the counter -->
<xsl:variable name="var:v4" select=""1"" />
<xsl:variable name="var:v5"
select="userCSharp:AddToCumulativeSum(0,string($var:v4),"1")" />
</xsl:if>
</xsl:for-each>
<!-- End: Calculation of the total number of children per family -->
292
BizTalk Mapping Patterns and Best Practices
To improve the solution in terms of performance, we can replace this Functoid chain with a Scripting Functoid, to
accomplish that you need:
Drag one Scripting Functoid from the Toolbox window onto the Grid.
o Double-click in the Scripting Functoid to show the Properties window, then:
Select the “Script Functoid Configure” tab, and then choose “Inline XSLT” as your selected script
type
In the “Inline script” text box enter the following XSLT code:
<TotalOfChildren>
<xsl:value-of select="count(Parents/Child)" />
</TotalOfChildren>
o Drag a link from the Scripting Functoid to the “TotalOfChildren” field element in the destination schema
TIP
Combining looping mapping problems with other patterns like conditional pattern, grouping pattern or making
calculations operation is in most scenarios a simple task, however the main challenger is trying to combine this type
of operations to be both good in terms of Readability and Maintainability and with a good general Performance.
And this cases I will recommend you to always analyze the compiler-generated XSLT code and apply the changes
you think that are necessary to improve some transformation rules, by mixing based Functoid with custom XSLT
code or in some circumstances apply the transformation rules only with custom XSLT code.
Conditional Looping
We have already discussed this type of pattern in some previous occasions in this book to explain order scenarios or
patterns, for example in the NESTED TO ONE OR MANY LOOPING or SWITCH CONDITION (OR NESTED CONDITIONS) sections.
Conditional looping in most of the common scenarios is a straightforward task, you simply can add conditions to a
293
BizTalk Mapping Patterns and Best Practices
Looping Functoid by linking the output of a Looping Functoid and a Logical Functoid to the same destination record.
This will mean that the destination records are created only when the logical condition is met.
Is this section we will analyze and explain in more details how you can archive this and the concerns you should have
when implementing this type of transformation. To accomplish this we will use the following scenario: we will have a
Survey schema that contains data from Food Survey and Flower Survey, both records have the same structure and we
only want to extract from both records all the address from the state of Florida.
Input Output
<FoodSurvey> <Address
<Name>Sandro Pereira</Name> Name="Vania Braziela"
<Address>7890 Broadway</Address> Street="456 1st Ave"
<City>Columbus</City> City="Miami"
<State>OH</State> State="FL"
<PostalCode>46290</PostalCode> PostalCode="81406" />
</FoodSurvey> <Address
<FoodSurvey> Name="Jose Antonio Silva"
<Name>Vania Braziela</Name> Street="456 1st Ave"
<Address>456 1st Ave</Address> City="Miami"
<City>Miami</City> State="FL"
<State>FL</State> PostalCode="81406" />
<PostalCode>81406</PostalCode> <Address
</FoodSurvey> Name="Rui Barbosa"
<FlowerDurvey> Street="456 1st Ave"
<Name>Jose Antonio Silva</Name> City="Miami"
<Address>456 1st Ave</Address> State="FL"
<City>Miami</City> PostalCode="81406" />
<State>FL</State>
<PostalCode>81406</PostalCode>
</FlowerDurvey>
<FlowerDurvey>
<Name>Rui Barbosa</Name>
<Address>456 1st Ave</Address>
<City>Miami</City>
<State>FL</State>
<PostalCode>81406</PostalCode>
</FlowerDurvey>
Drag from the Toolbox window one Looping Functoid and then:
o Drag a link from the “FoodSurvey” record in the source schema to the Looping Functoid
o Drag a link from the “FlowerSurvey” record in the source schema to the Looping Functoid
o And drag a link from the Looping Functoid to the “Address” record in the destination schema
Drag from the Toolbox window two Equal Functoid and then:
294
BizTalk Mapping Patterns and Best Practices
Drag a link from the “State” field element present in the “FoodSurvey” record from the source schema to first Equal
Functoid.
o Make double-click in the Equal Functoid to show the Properties window and then:
Specify the second condition (second input parameter) as “FL”
o Drag a link from the Equal Functoid to the “Address” record in the destination schema
Drag a link from the “State” field element present in the “FlowerSurvey” record from the source schema to second
Equal Functoid.
o Make double-click in the Equal Functoid to show the Properties window and then:
Specify the second condition (second input parameter) as “FL”
o Drag a link from the Equal Functoid to the “Address” record in the destination schema
Drag the mouse from the record name “FoodSurvey” in the source schema, and then drop it to record name
“Address” in the destination schema.
o On the shortcut menu, click “Link by Structure” option.
And the exact same steps for the “FlowerSurvey”. Drag the mouse from the record name “FlowerSurvey” in the
source schema, and then drop it to record name “Address” in the destination schema.
o On the shortcut menu, click “Link by Structure” option.
295
BizTalk Mapping Patterns and Best Practices
In this scenarios, the advantages and disadvantages will depend on the complexity and size of the source message
instance.
In small messages and simple structures this approach has the following advantages:
Development and Performance: From a developer’s perspective this approach is very simple to implement and
this algorithm has a good efficient in “normal” messages (small and medium).
Readability: Not hard to read and understand in simple structures.
Although this approach is simple to implement, in large structures or in messages with several records structures to
be mapped to the same the same destination structure, it can become quite confusing to read. We have always the
option to ungroup the transformation rules and implement them in for each structure into a different grid page,
however this can also be a bit awkward to read because one of the grid pages must contain all the association to
the Looping Functoid, so we need to read the rules in different grid pages to really understand the transformation
that we want to implement. Let’s take a look to the appearance of the map split in different grid pages, where the
“FoodSurvey” grid look like this:
And the “FlowerSurvey” grid page will have the following appearance:
296
BizTalk Mapping Patterns and Best Practices
Performance is also a key aspect that you need to take in consideration when you are dealing with large messages, in
this case not in terms the number of different records you have to mapped, but in terms of content. If you are expecting
messages instances with 5.000 or 50.000 Surveys for example you may think in optimize your solution. To understand
why, let's examine the code produced by the XSLT solution:
As already explained in some previous patterns and scenarios, like SWITCH CONDITION (OR NESTED CONDITIONS) in the
CONDITIONAL PATTERN, We will see that for each record in the source schema that is mapped to the destination schema,
it will be one <xsl:for-each> statement and inside of it a <xsl:if> statement to check if it’s a valid condition or not,
so far nothing is wrong, however when using these type approach this will means that if we have 5.000 Food Surveys
occurrences, this will means once again that we will have 5.000 iterations to check if it’s a valid condition or not and if
so, map the values into the destination schema. This 5.000 iterations regardless of whether we have, or not, data to
map because, in this approach, the only way to find out is to go through the entire message to try to find, which in
some scenarios can cause a Performance drop in the transformation process.
297
BizTalk Mapping Patterns and Best Practices
Once again to solve this mapping problem and address the performance issues present when dealing with large
messages, we need to use custom XSLT code and apply some XPath query’s that will implement the conditions that
we want without having the needs to travel for the entire message.
Note
Implementing XPath Queries to filter the desired content in recursive structures has a better performance than
traveling the entire nodes with a <xsl:for-each> statement and a <xsl:if> statement to apply the filter condition.
Drag one Scripting Functoid from the Toolbox window onto the Grid.
o Double-click in the Scripting Functoid to show the Properties window, then:
Select the “Script Functoid Configure” tab, and then choose “Inline XSLT” as your selected script
type
In the “Inline script” text box enter the following XSLT code:
<!-- Get all the Food Surveys that have the state defined as FL and map all the occurences -->
<xsl:for-each select="FoodSurvey[State = 'FL']">
<Address>
<xsl:attribute name="Name">
<xsl:value-of select="Name/text()" />
</xsl:attribute>
<xsl:attribute name="Street">
<xsl:value-of select="Address/text()" />
</xsl:attribute>
<xsl:attribute name="City">
<xsl:value-of select="City/text()" />
</xsl:attribute>
<xsl:attribute name="State">
<xsl:value-of select="State/text()" />
</xsl:attribute>
<xsl:attribute name="PostalCode">
<xsl:value-of select="PostalCode/text()" />
</xsl:attribute>
</Address>
</xsl:for-each>
<!-- Get all the Flowers Surveys that have the state defined as FL and map all the occurences -->
<xsl:for-each select="FlowerDurvey[State = 'FL']">
<Address>
<xsl:attribute name="Name">
<xsl:value-of select="Name/text()" />
</xsl:attribute>
<xsl:attribute name="Street">
<xsl:value-of select="Address/text()" />
</xsl:attribute>
<xsl:attribute name="City">
<xsl:value-of select="City/text()" />
</xsl:attribute>
<xsl:attribute name="State">
<xsl:value-of select="State/text()" />
</xsl:attribute>
<xsl:attribute name="PostalCode">
<xsl:value-of select="PostalCode/text()" />
</xsl:attribute>
</Address>
</xsl:for-each>
298
BizTalk Mapping Patterns and Best Practices
o Drag a link from the Scripting Functoid to the “Address” record in the destination schema
This approach will be easier to Implement, Read, Maintain and with better Performance when we are dealing with
complex or several structures or/and with large messages.
The major problem with this type of mapping is that it can be done in many different ways. In most of the common
scenarios is a straightforward task, you simply need to use a single Looping Functoid and link through it all the source
elements to the destination record, equal to what we described in the MANY TO ONE LOOPING section. However in some
scenarios this basic approach can have serious performance problems, other can be very difficult to maintain and in
some specific situations we must use the Table Looping Functoid instead or simply use custom XSLT code. Therefore
it is good to know what alternatives possible as well as their advantages and disadvantages.
We will address in more detail this approach in the NAME-VALUE TRANSFORMATION PATTERN section.
Input Output
<Person> <Person>
<Name>Sandro Pereira</Name> <Name>Sandro Pereira</Name>
<Age>36</Age> <Age>36</Age>
<Address1>Gaia, Portugal</Address1> <Address>
<Address2>Porto, Portugal</Address2> <Description>Gaia, Portugal</Description>
<Address3></Address3> </Address>
</Person> <Address>
<Person> <Description>Porto, Portugal</Description>
<Name>Miguel Silva</Name> </Address>
<Age>38</Age> </Person>
<Address1></Address1> <Person>
<Address2>Porto, Portugal</Address2> <Name>Miguel Silva</Name>
<Address3></Address3> <Age>38</Age>
299
BizTalk Mapping Patterns and Best Practices
</Person> <Address>
<Description>Porto, Portugal</Description>
</Address>
</Person>
Drag from the Toolbox window one Looping Functoid and then:
o Drag a link from the “Address1” element in the source schema to the Looping Functoid
o Drag a link from the “Address2” element in the source schema to the Looping Functoid
o Drag a link from the “Address3” element in the source schema to the Looping Functoid
o And drag a link from the Looping Functoid to the record “Address” in the destination schema
Drag a link from the “Address1” field element in the source schema to the “Description” field element in the
destination schema
Drag a link from the “Address2” field element in the source schema to the “Description” field element in the
destination schema
Drag a link from the “Address3” field element in the source schema to the “Description” field element in the
destination schema
Because we are dealing with mandatory fields (addresses) in the source schema, compiler-generated XSLT code is
actually a very good XSLT code. However this approach will create empty record in the target schema if the Addresses
element in the source have empty values.
<Person>
<Name>Miguel Silva</Name>
<Age>38</Age>
<Address>
<Description></Description>
</Address>
<Address>
<Description>Porto, Portugal</Description>
</Address>
<Address>
<Description></Description>
</Address>
</Person>
If we inspect and analyze the XSLT code generated by the compiler, we notice that this happens because we didn’t
create any validation rule, so it simple tries to map the source elements from the source schema to the destination
regardless if is empty or not.
…
<Address>
<Description>
300
BizTalk Mapping Patterns and Best Practices
To avoid this behavior we must additional use the Logical String Functoid:
Drag from the Toolbox window three Logical String Functoid and then:
o Drag a link from the “Address1” element in the source schema to the Logical String Functoid
o And drag a link from the Logical String Functoid to the record “Address” in the destination schema
Repeat the same steps for the two other Address elements
Although we have to use more Functoids, the mapper compiler will still produce a very good XSLT code to apply all
this rule, the main difference here is that I will be add <xsl:if> statements to validate if we need to map the value or
not. This approach is very simple to implement and read, nevertheless it can became very difficult to maintain if we
have to many elements to map from a flat structure to a repeating structure due to the amount of link and Functoids
that we need to use.
However if we make a small change in the addresses elements in the source schema and make them optional
elements, then we will have a complete different scenario and the XSLT generated by the compiler will be completely
different, as we can see:
<xsl:for-each select="Address1">
<xsl:variable name="var:v1" select="userCSharp:LogicalIsString(string(./text()))" />
<xsl:if test="$var:v1">
<Address>
301
BizTalk Mapping Patterns and Best Practices
<Description>
<xsl:value-of select="./text()" />
</Description>
</Address>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="Address2">
<xsl:variable name="var:v2" select="string(./text())" />
<xsl:variable name="var:v3" select="userCSharp:LogicalIsString($var:v2)" />
<xsl:if test="$var:v3">
<Address>
<Description>
<xsl:value-of select="./text()" />
</Description>
</Address>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="Address3">
<xsl:variable name="var:v4" select="string(./text())" />
<xsl:variable name="var:v5" select="userCSharp:LogicalIsString($var:v4)" />
<xsl:if test="$var:v5">
<Address>
<Description>
<xsl:value-of select="./text()" />
</Description>
</Address>
</xsl:if>
</xsl:for-each>
In this scenario for each address element the compiler will generate also one <xsl:for-each> statement. Again this
approach is very simple to Implement, Read and Maintain in certain conditions and if we work with small messages I
will say that it is the perfect solution, however if we work with large messages or you have several elements that needs
to be mapped, then you should consider to use a different approach. We will address in more detail the advantages
and disadvantages of all the approach in more detail in the NAME-VALUE TRANSFORMATION PATTERN section.
Parameter 1: A link from a repeating node in the source schema. The number of instances of this structure that
occur in a particular input instance message defines the number of times that the associated table looping grid is
processed.
Parameter 2: A constant input parameter that defines the number of columns in the associated table looping grid.
Parameters 3 - 100: A link from a node in the source schema or from another Functoid, such as a Value Extractor
Functoid, or a constant input parameter. The relative order of parameters 3 - 100 is unimportant.
I think, at least for those who know the minimum about Functoid, the last parameter(s), from 3 to 100, does not
present any doubts. They are the values that we want to map from the source to the destination. And the order is not
302
BizTalk Mapping Patterns and Best Practices
important because we need to define the Table Looping Grid property (http://msdn.microsoft.com/en-
us/library/aa559418.aspx) were we will define the order of appearance of these values.
The Table Looping Grid is basically a configurable table containing an arbitrary number of rows, configurable while
editing the table, and a number of columns specified by the second input parameter of the Table Looping Functoid.
Each table cell is configured by using a drop-down list where the entries in the drop-down list are the values from to
third through the last input parameters of the Table Looping Functoid. These input parameters consist of a
combination of the links into the Functoid and any constant input parameters that have been defined. If link input
parameters have been given a Label property value, that value is shown in the drop-down lists; otherwise, the value
of the Link Source property is shown (generally, the former is friendlier than the latter). Constant input parameters
are shown according to their constant value.
Important Note
However the number of rows present in the Table Looping Grid are not defined in any input parameter from the
Table Looping Functoid and in under no circumstances they are dynamic. The number of rows are statically defined
during developing in order to apply a specific transformation rule and resolve a particular transformation problem.
Although people use this functoid correctly, especially if we are using it with a repeating record in the source schema,
we will see in more detail further on in this chapter, if we are trying to use this Functoid to transform a flat structure
to a recursive structure that we realize that many developers don’t properly understand the first input parameter of
this Functoid and to be honest, neither the explanation present in the official documentation will explain it correctly.
Although the Table Looping Functoid states that the first input must be a scoping element linked from a repeating
group, that is not really true, in fact for me this description is complete false.
A link from a repeating node in the source schema – most common used but not entire true, you can also make use
of a constant value, a simple node or an element.
The number of instances of this structure that occur in a particular input instance message defines the number of
times that the associated table looping grid is processed. - I understand and in a way yes, but sometimes developers
understand that this as the number of rows that they have to define in the table Looping Grid, with is not true, or
that this input requires a number and in fact this is also not true.
Parameter 1: the first input parameter defines the action scope of the Table Looping Functoid and it can be defined
by a link from a source tree node, repeating record, simple records or even elements, or by a constant value. This
means:
o If the scope is defined by a repeating record or repeating element, the Table Looping Functoid will be
created/execute in each occurrence of the record or element (in each iteration over the node). We can
define this as multiple scope action.
o If the scope is defined by a simple element or record (only occurs one time), than the Table Looping will be
executed only one time. We can define this as simple scope action.
o If the scope is defined by a simple constant value, regardless if it is an integer, alpha-numeric or string,
than the Table Looping will be executed only one time. Again this is a simple scope action.
Let’s look this very basic example to understand how we can define the scope action of the Table Looping Functoid
sing these 3 different forms.
303
BizTalk Mapping Patterns and Best Practices
In this example were we have a source schema with a flat structure containing 3 properties names, 3 properties values
and one recursive element, which I called “JustToAnnoy”, and we want to transform these 3 names and values into a
recursive record in the target schema that contains two elements: “Name” and “Value”.
Input Output
<PropertyName1>PropertyName1_0</PropertyName1> <Properties>
<PropertyValue1>PropertyValue1_0</PropertyValue1> <Name>PropertyValue1_0</Name>
<PropertyName2>PropertyName2_0</PropertyName2> <Value>PropertyValue1_0</Value>
<PropertyValue2>PropertyValue2_0</PropertyValue2> </Properties>
<PropertyName3>PropertyName3_0</PropertyName3> <Properties>
<PropertyValue3>PropertyValue3_0</PropertyValue3> <Name>PropertyName2_0</Name>
<JustToAnnoy>JustToAnnoy_0</JustToAnnoy> <Value>PropertyValue2_0</Value>
<JustToAnnoy>JustToAnnoy_1</JustToAnnoy> </Properties>
<Properties>
<Name>PropertyName3_0</Name>
<Value>PropertyValue3_0</Value>
</Properties>
304
BizTalk Mapping Patterns and Best Practices
Now we have to link all node values representing the properties values and the names in the source schema to the
Table Looping. The order in we will make the association it’s not important, because we will define the structure of
the table data grid later on.
o Drag a link from the “PropertyName1” field element in the source schema to the Table Looping Functoid
o Drag a link from the “PropertyValue1” field element in the source schema to the Table Looping Functoid
o Perform the same steps for the Property Name and Values 2 and 3 presents in the source schema.
The next step is to configure the Table Looping Grid on the Table Looping Functoid. To defined this correct value
for the Table Looping Grid we need to:
o Make double-click in the Table Looping Functoid to show the Properties window and then select the tab
“Table Looping Grid” and set the following table structure:
First column the name of element: “PropertyName1”
And in the second column the value of the element: “PropertyValue1”
Make the same configuration for the remaining elements in line 2 and 3.
The next step is to drag two Table Extractor Functoid and configure them to read the first and the second column
of the table:
o Drag a link from the Table Looping Functoid to the first Table Extractor Functoid
Make double-click in the Table Extractor Functoid to show the Properties window and then:
Specify the second input parameter as “1”
305
BizTalk Mapping Patterns and Best Practices
Drag a link from the Table Extractor to the “Name” field element in the destination schema
o Drag a link from the Table Looping Functoid to the second Table Extractor Functoid
Make double-click in the Table Extractor Functoid to show the Properties window and then:
Specify the second input parameter as “2”
Drag a link from the Table Extractor to the “Value” field element in the destination schema
Finally we need to drag a link from the Table Looping Functoid Extractor to the “Properties” record in the
destination schema
Make double-click in the Table Looping Functoid to show the Properties window and then:
o Delete the first input parameter, by selecting the first input parameter and click in the delete button
present in the Table Looping Functoid property window
o Then specify the first input parameter with a constant value that correctly described the scope action: “1”
or “SimpleScope”
306
BizTalk Mapping Patterns and Best Practices
<ns0:Output xmlns:ns0="http://LoopingPattern.OutputScopeTableFunctoid">
<Properties>
<Name>PropertyValue1_0</Name>
<Value>PropertyValue1_0</Value>
</Properties>
<Properties>
<Name>PropertyName2_0</Name>
<Value>PropertyValue2_0</Value>
</Properties>
<Properties>
<Name>PropertyName3_0</Name>
<Value>PropertyValue3_0</Value>
</Properties>
</ns0:Output>
Because the element occurs two times, what will happen is that the final result of the message will have the values
duplicated.
<ns0:Output xmlns:ns0="http://LoopingPattern.OutputScopeTableFunctoid">
<Properties>
<Name>PropertyValue1_0</Name>
<Value>PropertyValue1_0</Value>
</Properties>
<Properties>
<Name>PropertyName2_0</Name>
<Value>PropertyValue2_0</Value>
</Properties>
<Properties>
<Name>PropertyName3_0</Name>
<Value>PropertyValue3_0</Value>
</Properties>
<Properties>
<Name>PropertyValue1_0</Name>
<Value>PropertyValue1_0</Value>
</Properties>
<Properties>
<Name>PropertyName2_0</Name>
307
BizTalk Mapping Patterns and Best Practices
<Value>PropertyValue2_0</Value>
</Properties>
<Properties>
<Name>PropertyName3_0</Name>
<Value>PropertyValue3_0</Value>
</Properties>
</ns0:Output>
Now let’s look to a slightly more elaborate example. In this sample we will have the exact same properties names and
values, but they are inside of a recursive record “Line” and two additional elements.
Input Output
<Line> <Line Item="1">
<Item>1</Item> <Service>Breaking Bad</Service>
<Service>Breaking Bad</Service> <Properties>
<PropertyName1>The journey</PropertyName1> <Name>The journey</Name>
<PropertyValue1>Walter White</PropertyValue1> <Value>Walter White</Value>
<PropertyName2>Rise and fall</PropertyName2> </Properties>
<PropertyValue2> <Properties>
One of TVs great anti-heroes <Name>Rise and fall</Name>
</PropertyValue2> <Value>One of TVs great anti-heroes</Value>
<PropertyName3>5 Seasons</PropertyName3> </Properties>
<PropertyValue3>2008–2013</PropertyValue3> <Properties>
</Line> <Name>5 Seasons</Name>
<Line> <Value>2008–2013</Value>
… </Properties>
</Line> </Line>
<Line Item="2">
…
</Line>
To accomplish this we need to apply the exact same steps described in the previous examples, however this time we
need to defined as the first input parameter the “Line” record so:
308
BizTalk Mapping Patterns and Best Practices
At first glance, it may seem that the BizTalk Mapper will generate a practical but complex XSLT code which is not. I was
already preparing myself to implement what would have been my first approach: using a custom XSLT code to perform
this transformation rules, however when I examine the code produced by the engine I notice almost perfect code:
<xsl:for-each select="Line">
<xsl:variable name="var:v1" select="PropertyName1" />
<xsl:variable name="var:v2" select="PropertyValue1" />
<xsl:variable name="var:v3" select="PropertyName2" />
<xsl:variable name="var:v4" select="PropertyValue2" />
<xsl:variable name="var:v5" select="PropertyName3" />
<xsl:variable name="var:v6" select="PropertyValue3" />
<Line>
<xsl:attribute name="Item">
<xsl:value-of select="Item/text()" />
</xsl:attribute>
<Service>
<xsl:value-of select="Service/text()" />
</Service>
<Properties>
<Name>
<xsl:value-of select="$var:v1" />
</Name>
<Value>
<xsl:value-of select="$var:v2" />
</Value>
</Properties>
<Properties>
<Name>
<xsl:value-of select="$var:v3" />
</Name>
<Value>
<xsl:value-of select="$var:v4" />
</Value>
</Properties>
<Properties>
<Name>
<xsl:value-of select="$var:v5" />
</Name>
<Value>
<xsl:value-of select="$var:v6" />
</Value>
</Properties>
</Line>
309
BizTalk Mapping Patterns and Best Practices
</xsl:for-each>
All the transformation rules apply to the Table Looping Functoid where translated in 3 sequences of the record
properties, the same as the 3 rows defined in the table grid. The only thing that we could improve here is not using
support variables and get the values directly by XPath query but it is something so insignificant that no one should be
concerned with it.
The benefits you will gain when you try to improve something as insignificant (Performance) are smaller than the
disadvantages (Development, Maintainability and Readability).
Both Functoids will cause a new record to be created in the destination for every record in the source based on the
logical condition evaluation to true or false. And both require 2 inputs parameters:
A Boolean value;
And the node element to be mapped;
If the Boolean is true, the value of the incoming field will be mapped, otherwise not.
Determine when to use the Value Mapping Functoid or the Value Mapping (Flattening) Functoid can sometimes be a
little confused and it really depend on what you want to archive, but there are some guidelines that can help you
based on the following characteristics of the source and destination schemas structures decide:
Use Value Mapping Functoid: When both the source and the destination schemas define parallel repeating
structures between which the relevant data is mapped or when you want to change the attributes of a field from
the source into the attributes of a record in the destination.
Use the Value Mapping (Flattening) Functoid: When the source schema defines a repeating structure and we want
to flatten the structure to the destination by converting multiple records into a single record
Sample:
Input Output
<ns0:Root> <ns0:Root>
<Record> <Record Param1="1000" />
<Field Name="Param1" Value="1000"/> <Record Param2="2000" />
<Field Name="Param2" Value="2000"/> <Record Param3="3000" />
<Field Name="Param3" Value="3000"/> <Record Param1="1001" />
</Record> <Record Param2="2002" />
<Record> <Record Param3="3003" />
<Field Name="Param1" Value="1001"/> <Record Param1="1100" />
<Field Name="Param2" Value="2002"/> <Record Param2="2200" />
<Field Name="Param3" Value="3003"/> <Record Param3="3300" />
</Record> </ns0:Root>
310
BizTalk Mapping Patterns and Best Practices
<Record>
<Field Name="Param1" Value="1100"/>
<Field Name="Param2" Value="2200"/>
<Field Name="Param3" Value="3300"/>
</Record>
</ns0:Root>
Drag three Equal Functoids and three Value Mapping Functoids from the Toolbox window onto the Grid.
Drag a link from the “Name” field element in the source schema to the Equal Functoid
o Make double-click in the Equal Functoid to show the Properties window and then:
Specify the second input parameter as “Param1”
Drag a link from the Equal Functoid to the Value Mapping Functoid
Drag a link from the “Value” field element in the source schema to the Value Mapping Functoid
And finally, drag a link from the Value Mapping Functoid to the “Param1” attribute in the destination schema
Apply the same steps for the “Param2” and the “Param3”, the only difference is that you need to apply the second
input parameter of the Equal Functoid equal to the parameter that you are trying to map: “Param2” or “Param3”.
The advantages and disadvantages of using this type of conditions inside a loop statement are described in detail in
the HOW TO MAP VALUES FROM A REPEATING NODE INTO A SINGLE NODE USING CONDITIONS section. I will not get in details again
but basically using this technique may have some performance problems when dealing with large message because
it will produce some unnecessary iterations – basically it will make 3 validations for each “Name” inside the Field
record. However this is not a bad solution and actually is a good solution for most of the scenarios that we normally
have to address.
To improve this solution we could use a Scripting Functoid with the following code, but specially by using the
<xsl:choose> expression, this way avoid several unnecessary conditions validations:
<xsl:for-each select="Record/Field">
<Record>
<xsl:choose>
<xsl:when test="string(@Name)='Param1'">
<xsl:attribute name="Param1">
<xsl:value-of select="@Value" />
</xsl:attribute>
</xsl:when>
<xsl:when test="string(@Name)='Param2'">
311
BizTalk Mapping Patterns and Best Practices
<xsl:attribute name="Param2">
<xsl:value-of select="@Value" />
</xsl:attribute>
</xsl:when>
<xsl:when test="string(@Name)='Param3'">
<xsl:attribute name="Param3">
<xsl:value-of select="@Value" />
</xsl:attribute>
</xsl:when>
</xsl:choose>
</Record>
</xsl:for-each>
Sample:
Input Output
<ns0:Root> <ns0:Root>
<Record> <Record Param1="1000" Param2="2000"
<Field Name="Param1" Value="1000"/> Param3="3000" />
<Field Name="Param2" Value="2000"/> <Record Param1="1001" Param2="2002"
<Field Name="Param3" Value="3000"/> Param3="3003" />
</Record> <Record Param1="1100" Param2="2200"
<Record> Param3="3300" />
<Field Name="Param1" Value="1001"/> </ns0:Root>
<Field Name="Param2" Value="2002"/>
<Field Name="Param3" Value="3003"/>
</Record>
<Record>
<Field Name="Param1" Value="1100"/>
<Field Name="Param2" Value="2200"/>
<Field Name="Param3" Value="3300"/>
</Record>
</ns0:Root>
To accomplish that we need to the exact same steps described in the Value Mapping Functoid but in this case we will
use the Value Mapping (Flattening) Functoid.
312
BizTalk Mapping Patterns and Best Practices
This approach has the same limitations of the previous but even more severe and with more performance impact.
Again I will not get in details but basically using this technique may have some performance problems when dealing
with large message because it will produce several unnecessary iterations and loops – basically it will make 3
<xsl:for-each> statements, one for each condition present in the map inside the loop that are dealing with the
records. Despite being and acceptable solution for small messages this solution must be approached and
implemented in a different way.
To improve this solution we should consider using a Scripting Functoid with the following XSLT code inside:
<xsl:for-each select="Record">
<Record>
<xsl:for-each select="Field">
<xsl:choose>
<xsl:when test="string(@Name)='Param1'">
<xsl:attribute name="Param1">
<xsl:value-of select="@Value" />
</xsl:attribute>
</xsl:when>
<xsl:when test="string(@Name)='Param2'">
<xsl:attribute name="Param2">
<xsl:value-of select="@Value" />
</xsl:attribute>
</xsl:when>
<xsl:when test="string(@Name)='Param3'">
<xsl:attribute name="Param3">
<xsl:value-of select="@Value" />
</xsl:attribute>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</Record>
</xsl:for-each>
Once again we are improving the overall performance of the map by only use <xsl:for-each> statement to travel the
“Field” node (instead of 3) and again by using the <xsl:choose> expression, this way avoid several unnecessary
conditions validations.
When to apply Looping Functoid, Table Looping Functoid or Scripting Functoid - Real X1 EDI Scenario
There are no specifically rules that we can follow to know in which circumstances should we use or apply the Looping
Functoid, the Table Looping Functoid or when we must turn to and rely on custom XSLT code to solve one or a group
of transformation rules. The only thing I can offer is some basic guidelines:
1. In basic scenarios the BizTalk Mapper engine will automatically infer looping based in the source schema
structure and we actually don’t need to use any Functoid, however in the majority of the scenarios the use of
the Looping Functoid should be sufficient to solve your transformation problem and to correctly apply the
necessary rules inside recursive nodes. The Looping Functoid can be useful in a number of ways, but it is
somewhat more complicated to set up correctly than many other Functoids, under certain conditions some
313
BizTalk Mapping Patterns and Best Practices
Functoids might not behave as expected when they are used in a map with a Looping Functoid and may not
produce the expected results, especially in this two particular situations:
a. Two or more of the Functoid input links are linked to child fields of the input records to the Looping
Functoid, where the child fields are not siblings.
b. The Functoid has an output link that is linked to a child field of the output record of the Looping
Functoid.
c. The Looping Functoid should not be used with the Value Mapping (Flattening) Functoid. If both are
used together, it results in a compiled map that assumed there is no source looping dependency for
the target nodes that are below the Looping Functoid.
And of course this Functoid should be used when we are dealing with recursive nodes both in the source as in
the target schema.
2. We should use the Table Looping Functoid basically in three particular situations:
a. When we want to transform a flat structure from the source schema to a recursive node in the target
schema
b. Or when one iteration in the source node will generate 2 or more node iterations in the target schema,
this is also true inside a recursive structure.
c. When we want to join several non-recursive structures from the source schema in a specific logic
transformation rule that will generate a recursive node, or siblings nodes in the target schema.
3. When it's impossible, too complex or in situation that the compiler-generated a very complex transformation
logic that will induce loss of performance in your maps, you should skip the use of Functoids and replace them
by custom XSLT Code, by using custom inline XSLT inside a Scripting Functoid Code or in some situations by
entirely replace the BizTalk Mapper by an custom XSLT file.
In this EDI scenario we will not address the entire mapping transformation, instead we will focus on a small problem,
which will occur within a huge transformation, and try to solve it and explain it and at the same time trying to avoid
custom coding.
In the source schema we have a repeating node “Enrollment” that contain two sibling records: “Subscriber” and
“Dependents” each one containing a “MemberId” field element that we need to map to the target schema only if they
have a valid “MemberId” field element. The output is an EDI (Healthcare) X125 5010 834 message with looping
requirement that we need to fulfill:
The Subscriber node in the inbound message should generate a field like this:
o INS02*Y
The Dependent nodes are a repeating node and should generate a field like this:
o INS02*N
Enrollments
Enrollment
Subscriber[A] -> Should generate one INS02*Y
Dependents[of A]
Dependent[1] -> Should generate a new INS02*N
Enrollment
Subscriber[B] -> Should generate third INS02*Y
Dependents[of B]
Dependent[1] -> Should generate a fourth INS02*N
314
BizTalk Mapping Patterns and Best Practices
Should generate the follow output message (for each Enrollment, loop the subscriber and then the dependents under
them:
Drag from the Toolbox window one Looping Functoid and then:
o Drag a link from the “Subscriber” record in the source schema to the Looping Functoid
o Drag a link from the “Dependent” record in the source schema to the Looping Functoid
o And drag a link from the Looping Functoid to the record “TS834_2000_Loop” in the destination schema
Drag one Logical String Functoid from the Toolbox window onto the Grid.
o Drag a link from the “MemberId” field element present in the “Subscriber” record in the source schema to
the Logical String Functoid
Drag one Value Mapping Functoid from the Toolbox window onto the Grid.
o Drag a link from the Logical String Functoid to the Value Mapping Functoid
o Make double-click in the Value Mapping Functoid to show the Properties window and then:
Specify the second input parameter as “Y”
o Drag a link from the Value Mapping Functoid to the “INS02_IndividualRelationshipCode” field element in
the destination schema
Drag one Logical String Functoid from the Toolbox window onto the Grid.
o Drag a link from the “MemberId” field element present in the “Dependent” record in the source schema to
the Logical String Functoid
Drag one Value Mapping Functoid from the Toolbox window onto the Grid.
o Drag a link from the Logical String Functoid to the Value Mapping Functoid
o Make double-click in the Value Mapping Functoid to show the Properties window and then:
Specify the second input parameter as “N”
o Drag a link from the Value Mapping Functoid to the “INS02_IndividualRelationshipCode” field element in
the destination schema
315
BizTalk Mapping Patterns and Best Practices
However this approach has a problem because it won’t produce the expected out. Instead it will give us all the first
“Y” element and then all the “N”:
The problem with this solution is that even though we are using a Looping functoid to try to create this transformation
rule, the record that we want to map are inside others recursive or optional records: “EnrollmentsBySubscriber” and
“Enrollment”. And in this cases the BizTalk Mapper engine will also automatically infer looping based in the source
schema structure:
316
BizTalk Mapping Patterns and Best Practices
<xsl:for-each select="s0:EnrollmentsBySubscriber">
<!-- Loop to all Enrollment and validate if it's a valid Subscriber -->
<xsl:for-each select="s0:Enrollment">
</xsl:if>
</ns0:INS_MemberLevelDetail>
</ns0:TS834_2000_Loop>
</xsl:for-each>
</xsl:for-each>
<xsl:for-each select="s0:EnrollmentsBySubscriber">
<!-- Loop to all Enrollment and validate if it's a valid Dependent -->
<xsl:for-each select="s0:Enrollment">
</xsl:if>
</ns0:INS_MemberLevelDetail>
</ns0:TS834_2000_Loop>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
To try to solve this problem and to force the map to apply the rules based on the Looping Functoid and to override the
inference made by the mapper engine I add an additional Looping Functoid as we can see in the picture bellow:
317
BizTalk Mapping Patterns and Best Practices
This will give us a closer result for what you try to archive, nevertheless not the same:
318
BizTalk Mapping Patterns and Best Practices
Drag one Logical String Functoid from the Toolbox window onto the Grid.
o Drag a link from the “MemberId” field element present in the “Subscriber” record in the source schema to
the Logical String Functoid
Drag one Value Mapping Functoid from the Toolbox window onto the Grid.
o Drag a link from the Logical String Functoid to the Value Mapping Functoid
o Make double-click in the Table Looping Functoid to show the Properties window and then:
Specify the second input parameter as “Y”
o Drag a link from the Value Mapping Functoid to the Table Looping Functoid
To be easier to read in the Table Looping Functoid, specify a label to this link called: “Y rule”
Drag one Logical String Functoid from the Toolbox window onto the Grid.
o Drag a link from the “MemberId” field element present in the “Dependent” record in the source schema to
the Logical String Functoid
Drag one Value Mapping Functoid from the Toolbox window onto the Grid.
o Drag a link from the Logical String Functoid to the Value Mapping Functoid
o Make double-click in the Table Looping Functoid to show the Properties window and then:
Specify the second input parameter as “N”
o Drag a link from the Value Mapping Functoid to the Table Looping Functoid
To be easier to read in the Table Looping Functoid, specify a label to this link called: “N rule”
The next step is to configure the Table Looping Grid on the Table Looping Functoid. As we defined in the input
parameters of this Functoid, the table will only have one column, but we still need to configure all the lines that we
want it to have. To defined this correct value for the Table Looping Grid we need to:
o Make double-click in the Table Looping Functoid to show the Properties window and then select the tab
“Table Looping Grid” and set the following table structure:
In the first line specify the column to have the element: “Y rule”
In the second line specify the column to have the element: “N rule”
Drag a link from the Table Looping Functoid Extractor to the “TS834_2000_Loop” record in the destination schema
319
BizTalk Mapping Patterns and Best Practices
The next step is to drag one Table Extractor Functoid and configure them to read the only column of the table:
o Drag a link from the Table Looping Functoid to the Table Extractor Functoid
Make double-click in the Table Extractor Functoid to show the Properties window and then:
Specify the second input parameter as “1”
Drag a link from the Table Extractor to the “INS02_IndividualRelationshipCode” field element in the
destination schema
This solution will solve our transformation problem without having the necessity to use custom XSLT code and actually
after you understand how and when to use the Table Looping Functoid, this solution is simple to Implement, Read
and Maintain and although it generating some unnecessary code, that’s nothing too severe that actually will affect
the final performance of the map.
<ns0:TS834_2000_Loop>
<ns0:INS_MemberLevelDetail>
<INS02_IndividualRelationshipCode>Y</INS02_IndividualRelationshipCode>
</ns0:INS_MemberLevelDetail>
</ns0:TS834_2000_Loop>
<ns0:TS834_2000_Loop>
<ns0:INS_MemberLevelDetail>
<INS02_IndividualRelationshipCode>N</INS02_IndividualRelationshipCode>
</ns0:INS_MemberLevelDetail>
</ns0:TS834_2000_Loop>
<ns0:TS834_2000_Loop>
<ns0:INS_MemberLevelDetail>
<INS02_IndividualRelationshipCode>Y</INS02_IndividualRelationshipCode>
</ns0:INS_MemberLevelDetail>
</ns0:TS834_2000_Loop>
<ns0:TS834_2000_Loop>
<ns0:INS_MemberLevelDetail>
<INS02_IndividualRelationshipCode>N</INS02_IndividualRelationshipCode>
</ns0:INS_MemberLevelDetail>
</ns0:TS834_2000_Loop>
<ns0:TS834_2000_Loop>
<ns0:INS_MemberLevelDetail>
<INS02_IndividualRelationshipCode>Y</INS02_IndividualRelationshipCode>
</ns0:INS_MemberLevelDetail>
</ns0:TS834_2000_Loop>
<ns0:TS834_2000_Loop>
<ns0:INS_MemberLevelDetail>
320
BizTalk Mapping Patterns and Best Practices
<INS02_IndividualRelationshipCode>N</INS02_IndividualRelationshipCode>
</ns0:INS_MemberLevelDetail>
</ns0:TS834_2000_Loop>
However if we modify a little the structure of the source schema and configure it to allow several Dependent nodes
(convert it to a recursive record) than this same solution will fail. We will focus in this case in the next solution.
Enrollments
Enrollment
Subscriber[A] -> Should generate one INS02*Y
Dependents[of A]
Dependent[1] -> Should generate a new INS02*N
Dependent[2] -> Should generate a new INS02*N
Enrollment
Subscriber[B] -> Should generate third INS02*Y
Dependents[of B]
Dependent[1] -> Should generate a fourth INS02*N
The main reason for that is that we now have a complex mix of nested recursive record and sibling record, most of
them are recursive nodes and we need base on this complex source generate note a simple record node but also a
nested recursive record. You may think that so far nothing is too different from what we have seen in the previous
solutions used before… However the main problem is that for each iteration on the father (Enrollment) the sibling
records that you want to transform (Subscriber and Dependent) will produce not only 2 but 2 or more nodes on the
target schema. We solved the inference problems in the previous approach because the “Dependent” node was non-
recursive. In this scenario the “Dependent” node is recursive and it will add an additional inference in the mapping
transformation. And with all the inference cause by the source schema structure is insane to solve this map problem
using base Functoids.
I spent several hours trying to find a way to solve this solution without having the necessity to use custom code and
when you are in this situation of losing too much time in a problem that we probably solve in a question of minutes
using custom XSLT, this means that even if you find a solution to solve the problem, there will likely be with serious
performance problems and likely hard to maintain. According to some of the best practices addressed in the BEST
PRACTICES chapter, if it is too difficult or complex to apply using base Functoid or will it take too much time… then you
should use custom XSLT.
Drag one Scripting Functoid from the Toolbox window onto the Grid.
o Double-click in the Scripting Functoid to show the Properties window, then:
Select the “Script Functoid Configure” tab, and then choose “Inline XSLT” as your selected script
type
In the “Inline script” text box enter the following XSLT code:
321
BizTalk Mapping Patterns and Best Practices
<!-- EnrollmentsBySubscriber and Enrollment are recursive records they need a for-each statement -->
<xsl:for-each select="s0:EnrollmentsBySubscriber">
<xsl:for-each select="s0:Enrollment">
<!-- Because both Dependents and Dependent are recursive records, they need a for-each statement
-->
<xsl:for-each select="s0:Dependents">
<xsl:for-each select="s0:Dependent">
<!-- The if statement is to check if it has a valid MemberId -->
<xsl:if test="s0:MemberId/text()!=''">
<TS834_2000_Loop>
<INS_MemberLevelDetail>
<!-- add the N role -->
<INS02_IndividualRelationshipCode>
<xsl:value-of select=""N"" />
</INS02_IndividualRelationshipCode>
</INS_MemberLevelDetail>
</TS834_2000_Loop>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
In case when you want to implement complex transformation rules or you are dealing with complex repeating
structures, using custom XSLT code is in my opinion the best option. However this does mean that you should skip
322
BizTalk Mapping Patterns and Best Practices
entirely the map and solved the whole transformation problem using only custom XSLT, in this example we have a
BGN page grid with very simple transformation rules: setting default values to some of the target element:
So try to use “the best of both worlds” by dividing your mapping problem in several small problems contextualized,
always use the page grids to separate and organize this small problems and for each one you should choose the best
resources or languages to solve it: using base Functoids, using advance Functoids with custom code, you main solve
some rules easier with C# and other with XSLT code. Of course there are always exceptions and in some scenarios you
should skip entire the BizTalk Mapper and solve your problem using only XSLT code with and External Custom XSLT file
or even with an inline XSLT code inside a Scripting Functoid.
Resources
Reference to this pattern:
All source code is available in the Microsoft Code gallery here: BizTalk Mapper Patterns: Looping Pattern
(http://code.msdn.microsoft.com/BizTalk-Mapper-Patterns-fde13dfa)
323
BizTalk Mapping Patterns and Best Practices
When several applications need to work together through Messaging and each application has its own internal data
format, most of the times semantically equivalent, we sometimes want or need to minimize all these dependencies
and implement an additional mechanism of indirection between the data formats for each individual application.
In an Enterprise application integration (EAI) scenario it is quite common for an enterprise to receive messages from
different systems that may have the same meaning but follow different formats but were developed independently
based on incompatible or different data models, yet they must share information efficiently and accurately in order
to effectively support the business. Different systems can have different terms for the same concept, leading to
miscommunication and errors of interpretation (i.e. a bundle product can be named also as a pack product or a
compose product). Canonical Data Modeling is a technique for developing and maintaining a logical model of the data
required to support the needs of the business for a subject area and it is intended to reduce costs and standardize on
agreed data definitions associated with integrating business systems.
The Canonical Data Model (CMD) will ensures loose-coupling between applications and if a new application is added
to the integration solution, only transformation between the Canonical Data Model has to created, independent from
the number of applications that already participate. This pattern is widely used.
Here is an excerpt from the White Paper Using canonical formats with BizTalk Server (http://www.motion10.nl/wij-
delen-onze-kennis/whitepapers/canonical-formats-biztalk) by Richard Sargeant about the overall structure of the
canonical format:
"The overall structure of the canonical format can be designed in one of three ways:
o Application driven
o B2B driven
o Generic (build from scratch)
Application driven is useful where a single back-office application is used to generate all outgoing messages and
process all incoming messages. As such, the canonical format could match the format used by the back-office
application (for example: an SAP IDOC). However, this does make the complete system more sensitive to changes in
324
BizTalk Mapping Patterns and Best Practices
requirements or business logic. Also any changes may need to be implemented within the back-office and that is
often more labor intensive than modifying a BizTalk map.
B2B driven takes the other extreme and bases the structure on the B2B format being used by the partners such as
EDIFACT or xCBL, etc. The disadvantage with this is that the structure tends to be very large and sometimes overly
complex.
I personally prefer the generic approach to build a schema from scratch. This allows the schema to exactly match
the requirements of both the business and IT. The structure can also be created to make the mapping as easy as
possible by avoiding large differences in structures."- Richard Sargeant
In this scenario we will see how to develop integration applications which receive documents from two different
systems, A and B, each one with different functionalities/actions and different message structures. That requires to
be transform to a common internal schema, the canonical schema, to be handle by the external system or
orchestration, by using a set of maps and ports (Receive and Send Ports).
As I mentioned, we will have two systems that need to send information to a final system that is responsible to handle
network user access information:
The System A will have the following functionalities/actions to be sent to the Final System
o Add User
o Change User Info
o Change User Password
o Remove User
The System B is a new system that is being built, but for now only have the following functionalities implemented:
o Add User
o Remove User
And we are planning to have a third system soon, but all of this systems have practically the same information, but
represented differently or even being slightly different, the target system is prepared to support them, most of the
times are optional information.
325
BizTalk Mapping Patterns and Best Practices
o Drag a link from the following field element in the source schema to the target schema according to this
table
To map the Add User to the canonical schema we need to make similar steps described above but in this case we
only need to map the following elements:
326
BizTalk Mapping Patterns and Best Practices
To map the Change User Info to the canonical schema we need to make similar steps described above but in this
case we need to:
o Specify the “OperationType” in the String Constant Functoid as “P019”
o And map the following elements:
327
BizTalk Mapping Patterns and Best Practices
And you still need to make similar steps to the Change User Password and Remove User functionalities but I will
not get in details about that ones.
Now we have five functionalities implemented and translated to our canonical schema, which we need to deploy to
our BizTalk Server environment. To understand and learn how to deploy a BizTalk Solution check the following articles:
After the BizTalk Solution is deployed into a BizTalk Application on the server in our environment, we need to configure
the receive ports and its underlying receive locations as well as the send ports using the BizTalk Server Administration
tool:
In the BizTalk Server Administration console tree, expand the BizTalk group and the BizTalk application for which
you want to create a receive port, in our case the “CanonicalDataModelPattern” application.
Right-click “Receive Ports”, point to “New”, and then click “One-way Receive Port…”
o In the Receive Port Properties window, do the following:
In the “General” tab specify the following properties
Name: SystemA
Authentication: No authentication
In the “Receive Locations” tab you need to create a new receive location for this receive port that
read the files from your local file system. Is not the goal from this book to teach how to accomplish
this so for instructions, see How to Create a Receive Location (http://msdn.microsoft.com/en-
us/library/aa561757.aspx)
The “Inbound Maps” tab is the most important tab to implement this pattern because it will be
here that specify and standardizing all the incoming messages on this receive port to our Canonical
schema. To accomplish this we need to specify the following inbound maps from the drop-down
list available in the “Map” column of the table grid available in this panel:
AddUserToCanonicalMap
328
BizTalk Mapping Patterns and Best Practices
ChangeUserInfoToCanonicalMap
ChangeUserPasswordToCanonicalMap
RemoveUserToCanonicalMap
Right-click “Send Ports”, point to “New”, and then click “Static One-Way Send Port…”
o In the Send Ports Properties window, do the following:
329
BizTalk Mapping Patterns and Best Practices
We will use filters to create simple messaging or content-based routing (CBR) in this application
and to accomplish this we need to specify on the “Filters” tab the following filters:
BTS.ReceivePortName == SystemA
Or
BTS.ReceivePortName == SystemB
Your can find more information about this here: How to Configure Filters for a Send Port Group
(http://msdn.microsoft.com/en-us/library/aa560032.aspx)
330
BizTalk Mapping Patterns and Best Practices
Now we need to start our BizTalk Application by right-click the BizTalk application name and then click “Start…” option.
And test it.
Resources
Reference to this pattern:
All source code is available in the Microsoft Code gallery here: BizTalk Mapper Patterns: Canonical Data
Model Pattern (http://code.msdn.microsoft.com/BizTalk-Mapper-Patterns-0fa3f29b)
331
BizTalk Mapping Patterns and Best Practices
This pattern is widely used when the number of required elements in the messages is very large, unknown, or changing
over time which leads to constant changes and makes it quite difficult to maintain. In this scenarios this pattern it's
remarkably flexible and adaptable. This can also be known as a Dynamic Data Denormalization. Nevertheless, the
Name/Value Pairs approach has very significant and inherent drawbacks:
Name/value pairs handle all data as strings (text). Since the attribute value can contain arbitrary data values, it
cannot be type as integer, decimal or date. Handling all data as strings leads to data quality issues because proper
data types cannot be enforced.
Defining business rules and constraints for Name/Value Pairs is very difficult and often impossible. You cannot
define an effective XML Schema to control and constrain this type of XML data (this type of XML Schema does not
allow you to specify that if there is an attribute called “name” with the value “price” then the value of the attribute
“value” in the same field element must be greater than zero)
Writing XPath queries against Name/Values Pair data can be very complex in certain scenarios. For example you
need to retrieve all the elements price that have a value greater than 5000.
332
BizTalk Mapping Patterns and Best Practices
The major problem with this type of mapping is that it can be done in many different ways: some ways quite simple
to implement, but with serious performance problems or difficult to maintain; other difficult to implement; dynamic
mapping and so on. Therefore it is good to know what alternatives possible as well as their advantages and
disadvantages.
So to reach our goal we need to link for the source to the destination schema:
The link to the “Name” element set with “Copy name” in the “Source Links” property
And the link to the “Value” element set with “Copy text value” (the default value) in the “Source Links” property
Before I start the solution for this problem we need to notice that two element are mapped directly:
Drag a link from the “NProcesso” (means process number) element in the source schema to the “Id” element in
the destination schema
333
BizTalk Mapping Patterns and Best Practices
Drag a link from the “ServiceName” element in the source schema to the “ServiceName” element in the destination
schema
And one element is not mapped “Tipo_Operacao” (means operation type). All other elements need to be mapped in
the Name/Value Pair record.
However this approach have a problem because don’ the produce a valid message, instead of creating a record for
each different element mapped he gathers all the Names and Values in a single record:
<ns0:Provisioning xmlns:ns0="http://SandroPereira.MappingToNameValueRecord.Provisioning">
<Id>Nprocesso_0</Id>
<Properties>
<Property>
<Name>IPRoute</Name>
<Name>Type</Name>
<Name>Protocol</Name>
<Name>Pool</Name>
<Name>VPNName</Name>
<Name>IPAddress</Name>
<Name>IPNetmask</Name>
<Name>Profile</Name>
<Name>VirtualRouter</Name>
<Name>IdleTimeout</Name>
<Name>SessionTimeout</Name>
<Name>TunnelType</Name>
<Value>IPRoute_0</Value>
<Value>Type_0</Value>
<Value>Protocol_0</Value>
<Value>Pool_0</Value>
<Value>VPNName_0</Value>
<Value>IPAddress_0</Value>
<Value>IPNetmask_0</Value>
334
BizTalk Mapping Patterns and Best Practices
<Value>Profile_0</Value>
<Value>VirtualRouter_0</Value>
<Value>IdleTimeout_0</Value>
<Value>SessionTimeout_0</Value>
<Value>TunnelType_0</Value>
</Property>
</Properties>
<ServiceName>ServiceName_0</ServiceName>
</ns0:Provisioning>
To solve this problem we need to add a Looping Functoid and map all the elements in this Functoid:
Second Solution: Using only Links and validate the existence of optional elements
So to avoid warnings of optional elements in the first approach we need to use additional Functoids. For each element
mapped in the Name/Value Pair we need to drag:
One Logical Existence Functoid and drag a link from the source element to this Functoid
And two Value Mapping Functoids:
Drag a link from the Logical Existence Functoid to the first Value Mapping Functoid
Drag a link from the Logical Existence Functoid to the second Value Mapping Functoid
Drag a link from the source element to the first Value Mapping Functoid and in the link properties set with “Copy
name” the “Source Links” property
335
BizTalk Mapping Patterns and Best Practices
Drag a link from the source element to the second Value Mapping Functoid and in the link properties set with “Copy
text value” the “Source Links” property
Drag a link from the first Value Mapping Functoid to the element “Name” in the destination schema
Drag a link from the second Value Mapping Functoid to the element “Value” in the destination schema
The first scripting Functoid is for create a C# function to validate the existence of the element.
o In the scripting type select “Inline C#” option
o In the Inline script put the following code:
336
BizTalk Mapping Patterns and Best Practices
<xsl:element name="Properties">
<xsl:for-each select="/s0:Request/Body/*">
<xsl:variable name="var:v2">
<xsl:value-of select="."/>
</xsl:variable>
<!-- Invoke the C# function created in the first Scripting Functoid -->
<xsl:variable name="var:v1" select="userCSharp:EmptyOrNull(string($var:v2))" />
<!-- Check if the element is different of this described here: ServiceName is not to map and LAN
will be handle different -->
<xsl:if test="local-name()!='ServiceName' and local-name()!='LAN' and $var:v1='true'">
<xsl:element name="Property">
<xsl:element name="Name">
<!-- Name of the element -->
<xsl:value-of select="local-name()"/>
</xsl:element >
<xsl:element name="Value">
<!-- Value of the element -->
<xsl:value-of select="."/>
</xsl:element >
</xsl:element>
</xsl:if>
</xsl:for-each>
<!-- This code will apply the rules for the record LAN. The rules are the same as previous
explained -->
<xsl:for-each select="/s0:Request/Body/LAN/*">
<xsl:variable name="var:v2">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:variable name="var:v1" select="userCSharp:EmptyOrNull(string($var:v2))" />
<xsl:if test="$var:v1='true'">
<xsl:element name="Property">
<xsl:element name="Name">
<xsl:value-of select="local-name()"/>
</xsl:element >
<xsl:element name="Value">
<xsl:value-of select="."/>
</xsl:element >
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:element>
Finally drag a ling from the second scripting Functoid to the “Properties” record in the destination schema:
337
BizTalk Mapping Patterns and Best Practices
Readability: Because we use scripting Functoids we cannot read the entire map visually. We need to open the
Functoids to read, mainly, the XSLT code.
Level of effort/Development: Requires XSLT knowledge, therefore it requires “geeky” coding skills. Also the
Scripting Functoid editor doesn't have IntelliSense which makes slightly hard the development of XSLT code.
Instead of using the Looping Functoid and drag all links from the source directly to the destination schema, we will
drag the links all the links from the source schema to the Table Looping Functoid… but because you cannot drag to link
from the same element to the Table Looping Functoid (To map the name and the value) you need to use a workaround:
In the Table looping Functoid configuration we need to set the first to inputs:
The first with the number of element mapped in the Table looping Functoid
The second with the number of columns, in this case 2
338
BizTalk Mapping Patterns and Best Practices
And in the Table Looping grid we need to manually associate the first column the name of element and in the
second the value of the element:
Finally we need to drag to Table Extractor Functoid and configure them to read the first and the second column of
the table:
339
BizTalk Mapping Patterns and Best Practices
Resources
All source code is available in the Microsoft Code gallery here: BizTalk Mapper Patterns: How to Map
Hierarchical Schema to a Name Value Pair
(http://code.msdn.microsoft.com/windowsdesktop/BizTalk-Mapper-Patterns-4041242c)
When I decided to implement this mapping I really thought it would be extremely simple and almost not worth talking
about… how I was wrong. It became really complicated, and exciting, as I tried to find a solution to optimize and
improve the map.
As a developer the first approach we think is to try to solve this mapping problem using only the available Functoids,
i.e. without custom XSLT. I quickly discarded this option and you will see why.
Before I start the solution for this problem we need to notice that two element are mapped directly:
Drag a link from the Id element in the source schema to the “NProcesso” (means process number) element in the
destination schema
340
BizTalk Mapping Patterns and Best Practices
Drag a link from the “ServiceName” element in the source schema to the “ServiceName” element in the destination
schema
One Equal Functoid and drag a link from the element “Name” in the source schema to this Functoid, this will be
the first condition in the Functoid
o And in the second condition we need to put the element name of the destination schema that we try to
map, for example “Type”.
Drag a Value Mapping (Flattening) Functoid to the grid
o Drag a link from the Equal Functoid to this Value Mapping (Flattening) Functoid
o Drag a link from the “Value” element in the source element to the Value Mapping (Flattening) Functoid
o And finally we need to drag a link from the Value Mapping (Flattening) Functoid to the respective element
in the destination schema, in this case “Type” element as you can see in the picture bellow:
341
BizTalk Mapping Patterns and Best Practices
We need to repeat the above steps for all the element except the “IPRoute” element, until we get the following
map:
And this is it, it seems simple and it is. However, this approach suffers from a serious problem that we can only detect
by analyzing the XSLT regenerated by the BizTalk mapping engine: Performance.
342
BizTalk Mapping Patterns and Best Practices
In the Output windows, press CRTL key and click on the link of “The file in the output XSLT is stored in the following
file”, it will open this file in a new windows
Right-click and select “View Source” option
We will see that for each element in the destination schema it will be one for-each element:
<Header>
<Nprocesso>
<xsl:value-of select="Id/text()" />
</Nprocesso>
</Header>
<Body>
<ServiceName>
<xsl:value-of select="ServiceName/text()" />
</ServiceName>
<!-- For each segment to map the element Type. It need to travel all the element of the message to
get the desired element -->
<xsl:for-each select="Properties/Property">
<xsl:variable name="var:v1" select="userCSharp:LogicalEq(string(Name/text()) ,
"Type")" />
<xsl:if test="string($var:v1)='true'">
<xsl:variable name="var:v2" select="Value/text()" />
<Type>
<xsl:value-of select="$var:v2" />
</Type>
</xsl:if>
</xsl:for-each>
<!-- For each segment to map the element Protocol. It need to travel all the element of the
message to get the desired element -->
<xsl:for-each select="Properties/Property">
<xsl:variable name="var:v3" select="string(Name/text())" />
<xsl:variable name="var:v4" select="userCSharp:LogicalEq($var:v3 , "Protocol")" />
<xsl:if test="string($var:v4)='true'">
<xsl:variable name="var:v5" select="Value/text()" />
<Protocol>
<xsl:value-of select="$var:v5" />
</Protocol>
</xsl:if>
</xsl:for-each>
<!-- For each segment to map the element Pool. It need to travel all the element of the message to
get the desired element -->
<xsl:for-each select="Properties/Property">
<xsl:variable name="var:v6" select="string(Name/text())" />
<xsl:variable name="var:v7" select="userCSharp:LogicalEq($var:v6 , "Pool")" />
<xsl:if test="string($var:v7)='true'">
<xsl:variable name="var:v8" select="Value/text()" />
<Pool>
<xsl:value-of select="$var:v8" />
</Pool>
</xsl:if>
</xsl:for-each>
…
This means that if we have 50 occurrences of “Property” record, each filled with the elements Name and Value, we
will have 50 iterations for each element that we want to map in the destination schema… in this scenario we have 12
343
BizTalk Mapping Patterns and Best Practices
elements, this means 600 iterations and will be worse if we are working with large maps or with high amounts of
“Property” record occurrence.
Performance: Lack of performance due to the high number of unnecessary iterations to go read the elements
Development, Readability, Reusability and Level of effort:
o If the destination schema has many elements it takes to much work to do this kind of mapping and because
we need many links and Functoids to do this simple task it may become difficult to read the map.
o If we add a new element in the destination schema, it requires that we have to rectify the mapping
And the second approach that I thought was trying to make a dynamic mapping, similarly to the third solution that I
have accomplished in the THIRD SOLUTION: USING INLINE XSLT of HOW TO MAP HIERARCHICAL SCHEMA TO A NAME VALUE PAIR
problem
Finally drag a link from the Scripting Functoid to the “Type” element in the destination schema:
344
BizTalk Mapping Patterns and Best Practices
This looked like be my favorite approach because is complete dynamic. If another element was added to the
destination schema I didn’t need to fix the mapping.
The script only work well if all the elements contained in the “Properties” record, are coming filled in the correct
order of the elements in the destination schema.
Don’t work with nested records (or sub-records), if you notice in the script I ignore all “IPRoute” names
I could probably find other limitations but for me these two are enough to discard this approach.
Replace the code of the Scripting Functoid, existing in the previous solution, by:
<Type>
<xsl:value-of select="//Properties/Property[Name='Type']/Value/text()" />
</Type>
<Protocol>
<xsl:value-of select="//Properties/Property[Name='Protocol']/Value/text()" />
</Protocol>
<Pool>
<xsl:value-of select="//Properties/Property[Name='Pool']/Value/text()" />
</Pool>
<VPNName>
<xsl:value-of select="//Properties/Property[Name='VPNName']/Value/text()" />
</VPNName>
<IPAddress>
<xsl:value-of select="//Properties/Property[Name='IPAddress']/Value/text()" />
</IPAddress>
<IPNetmask>
<xsl:value-of select="//Properties/Property[Name='IPNetmask']/Value/text()" />
</IPNetmask>
<LAN>
<xsl:for-each select="Properties/Property[Name='IPRoute']">
<IPRoute>
<xsl:value-of select="./Value/text()" />
</IPRoute>
</xsl:for-each>
</LAN>
<VirtualRouter>
<xsl:value-of select="//Properties/Property[Name='VirtualRouter']/Value/text()" />
</VirtualRouter>
<IdleTimeout>
<xsl:value-of select="//Properties/Property[Name='IdleTimeout']/Value/text()" />
</IdleTimeout>
<SessionTimeout>
<xsl:value-of select="//Properties/Property[Name='SessionTimeout']/Value/text()" />
345
BizTalk Mapping Patterns and Best Practices
</SessionTimeout>
<TunnelType>
<xsl:value-of select="//Properties/Property[Name='TunnelType']/Value/text()" />
</TunnelType>
In this first approach, I tried to keep the code simple, but there is an important limitation in this code … I’m not validate
the existence of optional fields. To do that we need to put the code a little more elaborate:
<xsl:choose>
<xsl:when test="count(//Properties/Property[Name='Type']) > 0">
<Type>
<xsl:value-of select="//Properties/Property[Name='Type']/Value/text()" />
</Type>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="count(//Properties/Property[Name='Protocol']) > 0">
<Protocol>
<xsl:value-of select="//Properties/Property[Name='Protocol']/Value/text()" />
</Protocol>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="count(//Properties/Property[Name='Pool']) > 0">
<Pool>
<xsl:value-of select="//Properties/Property[Name='Pool']/Value/text()" />
</Pool>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="count(//Properties/Property[Name='VPNName']) > 0">
<VPNName>
<xsl:value-of select="//Properties/Property[Name='VPNName']/Value/text()" />
</VPNName>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="count(//Properties/Property[Name='IPAddress']) > 0">
<IPAddress>
<xsl:value-of select="//Properties/Property[Name='IPAddress']/Value/text()" />
</IPAddress>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="count(//Properties/Property[Name='IPNetmask']) > 0">
<IPNetmask>
346
BizTalk Mapping Patterns and Best Practices
Readability: Because we use scripting Functoids we cannot read the entire map visually. We need to open the
Functoids and read, mainly, the XSLT code.
Level of effort/Development: Need basic knowledge of XSLT and XPath. If we add a new element in the destination
schema, it requires that we have to rectify the mapping.
Resources
All source code is available in the Microsoft Code gallery here: BizTalk Mapper Patterns: How to Map
Name Value Pair to a Hierarchical Schema
(http://code.msdn.microsoft.com/windowsdesktop/BizTalk-Mapper-Patterns-dd10187b)
347
BizTalk Mapping Patterns and Best Practices
348
BizTalk Mapping Patterns and Best Practices
This chapter covers the most misunderstood and unknown properties available in BizTalk Mapper UI, that you can
access through the properties of the background of a grid page, and hidden attributes that you can modify directly in
the mapsource element present in the map file and change certain default behaviors of BizTalk Mapper. Whenever
possible it will be provide examples for better understanding the properties and how they work.
The aim is not to explain all the properties available, only those which probably have more impact on the maps, which
are a bit unknown and unused most of the times. However I will provide link for additional resources whenever I find
it interesting so that you can acquire and strengthening your knowledge in certain topics.
True: Specifies that the links in the map do not contain any references to the namespaces used in the source or
destination schemas, thereby protecting the links from changes made to those schema namespaces outside the
map. (Default Value)
False: Specifies that the links in the map contain references to the namespaces used in the source and destination
schemas, thereby making the links sensitive to changes made to those schema namespaces outside the map.
So what that this means? Let’s imagine that we have this very simple map:
349
BizTalk Mapping Patterns and Best Practices
If you have the need for some reason to change the namespace of source or destination schemas, the rules
implemented in the map will not break and everything will look the same and work properly. This happens because
the default value of this property is set to “True” and this means that the changes to the namespaces in the source
and destination schemas will not invalidate its links because the transformation rules will not contain any references
to them.
However if this property is set to “False”, the map will make use of the namespaces in the transformation rules and if
we try to make, for example the namespace of the source schema this is the final result:
All the rules containing references to the source schema are brooked because the map cannot find the expected source
namespace and we need to relink them.
Two field element from the same type (string) called “Field” each one with different namespaces
And two record with a different structure called “Operation” again each one with different namespaces
350
BizTalk Mapping Patterns and Best Practices
The only way you have to apply this transformation rules is to set the “Ignore Namespaces for Links” property to
“False” otherwise the map will not allow you to link the different elements. If you try to link the “GL:Field” from the
source to the “AnotherField” in the destination schema, the mapper will link instead the “Field” element from the
source to the “AnotherField” in the destination schema.
TIP
This behavior only happens when you have different nodes on the same level with the same name and different
namespaces. This behavior in not true
If you have different nodes with the same name and different namespaces on different levels
If you have different nodes on the same level with the same name and same namespaces
Resources
Reference to this property:
All source code is available in the Microsoft Code gallery here: BizTalk Mapper: When to use the Ignore
Namespaces for Links property (http://code.msdn.microsoft.com/BizTalk-Mapper-When-to-use-
8b364c14)
False: Specifies that the output of the transformation should include an XML declaration.
351
BizTalk Mapping Patterns and Best Practices
True: Specifies that the output of the transformation should not include an XML declaration. This is the Default
Value.
Inside Visual Studio IDE if we change the following BizTalk Mapper properties:
And if we test our map we will see that this changes have effect and produce the transformation output with a XML
Declaration according to the encoding specified.
However this options has no kind of impact at runtime. Let’s imagine the following scenario where we have an
Outbound map, with the Omit Xml Declaration property as false, specify in a send port that writes the XML file to our
file system.
If we apply the default XML Transmit pipeline the output will have the encoded as UTF-16:
If we change the AddXmlDeclaration property of the default XML Transmit pipeline to “False” the output will not
contain the XML Declaration:
<ns0:Output xmlns:ns0="http://OmitXMLDeclaration.Output">
<FullName>Sandro Pereira</FullName>
</ns0:Output>
If we apply the default PassThru Transmit pipeline the output will also not contain the XML Declaration
<ns0:Output xmlns:ns0="http://OmitXMLDeclaration.Output">
<Fullname>Sandro Pereira</Fullname>
</ns0:Output>
At Runtime, this property seems to have no impact. As a result, I draw the conclusion that this property is obsolete.
352
BizTalk Mapping Patterns and Best Practices
Resources
Reference to this property:
All source code is available in the Microsoft Code gallery here: BizTalk Mapper: Omit XML Declaration
(Grid Property) explained (http://code.msdn.microsoft.com/BizTalk-Mapper-Omit-XML-b8942842)
xml: The mapper will produce the output of the transformation as XML. (Default Value)
html: The mapper will produce the output of the transformation as HTML (not entirely true).
Text: The mapper will produce the output of the transformation as text.
If we look at this simple scenario were we 3 elements in the source schema that we need to map and transform in two
element in the destination schema:
With the method property set to “xml” the output instance will look like the following:
<ns0:Output xmlns:ns0="http://MethodGridProperty.Output">
<FullName>Sandro Pereira</FullName>
<Age>36</Age>
</ns0:Output>
With the method property set to “html” although defined to e HTML the output instance will look exactly as if we had
defined as XML:
<ns0:Output xmlns:ns0="http://MethodGridProperty.Output">
<FullName>Sandro Pereira</FullName>
<Age>36</Age>
</ns0:Output>
With the method property set to “text” then we have a completely different behavior and the output instance will
look like the following:
Sandro Pereira36
353
BizTalk Mapping Patterns and Best Practices
Unfortunately I cannot find any practical scenario where we really have to change this property. This property it
sounds similar to flat file stuff but your just better off using the flat file assemble.
Resources
Reference to this property:
All source code is available in the Microsoft Code gallery here: BizTalk Mapper: Method (Grid Property)
explained (http://code.msdn.microsoft.com/BizTalk-Mapper-Method-Grid-3292833f)
False: Specifies that processing instructions should not be copied from the input instance message to the output
instance message. (Default Value)
True: Specifies that processing instructions should be copied from the input instance message to the output
instance message.
A processing instruction is an item in an XML file that is used to provide instructions to an application that processes
the XML file. Within an XML file, processing instructions are delimited by "<?" and "?>".
Note
The Copy Processing Instructions property copies instructions only from one message to another, single message.
Processing instructions cannot be copied from or to all of the parts in multi-part mappings (one-to-many or many-
to-one).
This property is extremely useful when we are dealing with InfoPath or similar technologies with BizTalk, This type of
messages have always a XML processing header and BizTalk Mapper will not copy them to the output messages by
default, so we have to set this property manually to accomplish that.
Let’s take a look to a dummy sample, where we have the following input message:
With the Copy Processing Instructions (PIs) property set to “False” the output instance will look like the following:
<ns0:Output xmlns:ns0="http://MappingProcessingInstructions.Output">
<Result>This is a test of text</Result>
</ns0:Output>
354
BizTalk Mapping Patterns and Best Practices
With the Copy Processing Instructions (PIs) property set to “True” the output instance will look like the following:
Resources
Reference to this property:
All source code is available in the Microsoft Code gallery here: BizTalk Mapper: Copy Processing
Instructions (PIs) (Grid Property) explained (http://code.msdn.microsoft.com/BizTalk-Mapper-Copy-
57a84a2a)
TreatElementsAsRecords
OptimizeValueMapping
GenerateDefaultFixedNodes
PreserveSequenceOrder
This properties are represented as attributes of the mapsource element (Managing Default Mapper Behavior Using
<mapsource> (http://msdn.microsoft.com/en-us/library/aa561485.aspx)) directly in a map source file that you can
access by editing the file in a text editor (like notepad) or inside Visual Studio by right-click on the map name in the
Solution window and select the option “Open With…”, and select the option “XML (Text) Editor”.
...
TreatElementsAsRecords attribute
This is probably one of the most undocumented attributes, and the most difficult to explain and understand, present
in the BizTalk Mapper. The official documentation states that when you use a Looping Functoid, a Conditional Functoid,
or a Value Mapping Functoid, an <xsl:for-each> statement is generated in the compiled map. If the child field of the
destination schema has unbounded maximum occurrences, the <xsl:for-each> statement is put at the child field. If
355
BizTalk Mapping Patterns and Best Practices
the child field does not have unbounded maximum occurrences, the <xsl:for-each> statement is put at the parent
field of the child field.
However, because the location of the <xsl:for-each> statement affects the map result, you may want the <xsl:for-
each> statement to be put at the child field of the destination schema, regardless of whether the maximum occurrence
of the child field is set to 1.
You can control the placement of the <xsl:for-each> statement by modifying the value of the
TreatElementsAsRecords attribute in the map (.btm) file.
When this attribute is set to Yes, the <xsl:for-each> statement is put at the child field of the destination schema,
regardless of whether the maximum occurrence of the child field is set to 1.
Let’s imagine that we have a repeating parent node in the source schema with a mandatory child element that only
occurs one time and we want to map these to the exact same structure in the destination schema. For testing
purposes, we only want to map the elements that has a valid string:
With the TreatElementsAsRecords attribute set to “No” the generated code will look like this:
<xsl:for-each select="RepeatingParent">
<xsl:variable name="var:v12" select="userCSharp:LogicalIsString(string(Child/text()))" />
<Parent>
<xsl:if test="string($var:v12)='true'">
<xsl:variable name="var:v13" select="Child/text()" />
<Child>
<xsl:value-of select="$var:v13" />
</Child>
</xsl:if>
</Parent>
</xsl:for-each>
<Parent>
<Child>RChild_1</Child>
</Parent>
<Parent>
<Child>RChild_2</Child>
</Parent>
<Parent>
<Child>RChild_3</Child>
356
BizTalk Mapping Patterns and Best Practices
</Parent>
However if we set the TreatElementsAsRecords attribute as “Yes” the generated code will be slightly different:
<Parent>
<xsl:for-each select="RepeatingParent">
<xsl:variable name="var:v12" select="userCSharp:LogicalIsString(string(Child/text()))" />
<xsl:if test="string($var:v12)='true'">
<xsl:variable name="var:v13" select="Child/text()" />
<Child>
<xsl:value-of select="$var:v13" />
</Child>
</xsl:if>
</xsl:for-each>
</Parent>
In this case we forced the map to put the <xsl:for-each> statement in the child field of the destination schema,
regardless of whether the maximum occurrence of the child field is set to 1.
And as we can see it will generate multiple child elements, which will translate to an invalid message:
<Parent>
<Child>RChild_1</Child>
<Child>RChild_2</Child>
<Child>RChild_3</Child>
</Parent>
And of course this can be resolved if we add a Looping Functoid to force the correct looping statement:
In this case regardless if the TreatElementsAsRecords attribute is set to “Yes” or “No” the <xsl:for-each> statement
will be respected and the output will be exactly the same.
However the TreatElementsAsRecords has another “feature” that for me is even more interesting.
When we have an optional parent in in the source schema a <xsl:for-each> statement will be added in the XSLT
code, even though it is not a recursive node. So let’s look to this sample were we have an optional parent node with a
repeating child element that we will map again to the same structure in the destination but only the elements that
have a valid string:
357
BizTalk Mapping Patterns and Best Practices
With the TreatElementsAsRecords attribute set to “No” the generated code will look like this:
<OptionalParent>
<xsl:for-each select="OptionalParent">
<xsl:for-each select="Child">
<xsl:variable name="var:v9" select="string(./text())" />
<xsl:variable name="var:v10" select="userCSharp:LogicalIsString($var:v9)" />
<xsl:if test="string($var:v10)='true'">
<xsl:variable name="var:v11" select="./text()" />
<Child>
<xsl:value-of select="$var:v11" />
</Child>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</OptionalParent
As we can see it will generate two <xsl:for-each> statements, one for the optional parent node and another for the
repeating child.
However if we set the TreatElementsAsRecords attribute as “Yes” the generated code will be again slightly different:
<OptionalParent>
<xsl:for-each select="OptionalParent/Child">
<xsl:variable name="var:v9" select="string(./text())" />
<xsl:variable name="var:v10" select="userCSharp:LogicalIsString($var:v9)" />
<xsl:if test="string($var:v10)='true'">
<xsl:variable name="var:v11" select="./text()" />
<Child>
<xsl:value-of select="$var:v11" />
</Child>
</xsl:if>
</xsl:for-each>
</OptionalParent>
In this case it will generate a more efficient code with only one <xsl:for-each> statement for the repeating child
field, which is really what we want and need.
So the use of the TreatElementsAsRecords attribute as “Yes” can produce a better XSLT code but again you need to
be very careful when you use it.
358
BizTalk Mapping Patterns and Best Practices
Resources
All source code is available in the Microsoft Code gallery here: BizTalk Mapper:
TreatElementsAsRecords attribute of the mapsource element
(http://code.msdn.microsoft.com/BizTalk-Mapper-TreatElement-fa449245)
OptimizeValueMapping attribute
This attribute will decide whether or not the BizTalk Mapper automatically optimize the Value Mapping Functoid Code
Generation.
When the Mapper generates XSLT code to call the Value Mapping Functoid, a variable is used to store the result. You
can use the OptimizeValueMapping flag to optimize the Value Mapping Functoid so that a variable is generated only
when the <xsl:if> statement evaluates to True. For example if we have the following scenario:
With the OptimizeValueMapping attribute set to “No” the generated code will look like this:
<!-- Copy the the uppercase of SimpleCondition field element value to another variable -->
<xsl:variable name="var:v4" select="string($var:v3)" />
<SimpleConditionResult>
<!-- Set the value in the output message -->
<xsl:value-of select="$var:v4" />
</SimpleConditionResult>
</xsl:if>
359
BizTalk Mapping Patterns and Best Practices
This code could be optimized by moving the Value Mapping Functoid invocation into the body of the <xsl:if>
statement, ensuring that invocation occurs only when it is required. Setting OptimizeValueMapping to Yes yields the
following code:
<SimpleConditionResult>
<!-- Set the value in the output message -->
<xsl:value-of select="$var:v3" />
</SimpleConditionResult>
</xsl:if>
The Mapper does this optimization automatically if you set the OptimizeValueMapping attribute of the mapsource
element in the map source (.btm) file to “Yes”.
This behavior is particularly true if we have previous actions (transformations rules) that are linked to the Value
Mapping Functoid, nevertheless if don’t have previous actions (transformations rules) linked to the Functoid:
The generated code, regardless if this attribute set to "Yes" or "No", will be exactly the same.
Fortunately for us, we do not have to worry too much with this attribute because by default is set to “Yes”.
Resources
All source code is available in the Microsoft Code gallery here: BizTalk Mapper:
OptimizeValueMapping attribute of the mapsource element
(http://code.msdn.microsoft.com/BizTalk-Mapper-OptimizeValu-1e750dc0)
360
BizTalk Mapping Patterns and Best Practices
GenerateDefaultFixedNodes attribute
When the Mapper is using a schema that has a very large instance footprint with deep complex structures and/or
recursive nodes, testing the map, validating the map, or compiling the map could take a long time or, in the worst
case, result in an "out of memory" error. This could happen with small, complex schemas as well as with large schemas.
The problem with complex schemas is due to the fact that the Mapper has to recursively load the entire schema tree
looking for nodes that either have links connected to them or have the Value property set on them. You can alleviate
this problem by setting the GenerateDefaultFixedNodes flag of the mapsource element in the .btm files to “No”.
With this setting, the Mapper does not need to create internal compiler nodes associated with each schema node of
a target schema. Only linked nodes are taken into account by the compiler. This significantly reduces the memory
consumption and speeds up the process when doing a "test map" or "validate map" operation, compiling the map, or
saving the map.
However, when the GenerateDefaultFixedNodes flag is set to “No”, the default field values set in the target schema
are not preserved in the instance produced by the map. This is a problem when these values are required in the target
instance. Of course describing this behavior with a large message or with a message that has this problem is a
challenger, so we will use a small example for demonstration, for example if we have a mandatory field element in the
destination schema with a default value specify, in this case the field element “Type” has a default value specify as
“Person”:
And if we do not specify any transformation rule in the map, with the GenerateDefaultFixedNodes flag is set to “No”:
361
BizTalk Mapping Patterns and Best Practices
It will generate an invalid message and will raise an error if we validate the output schema:
Important Note
This behavior is also true at runtime, if you deploy a map with the GenerateDefaultFixedNodes flag is set to “No”
we will not take in consideration the default values defined in the destination schema and will only apply the
transformation rules described in the Mapper.
Specify the required values have to be set again explicitly in the map by using for example a Functoid or by using
the Value property in the destination Schema Properties (see WORKING WITH CONSTANT VALUES INSIDE MAPS section in
the BIZTALK MAPPER PATTERNS chapter)
Or you can set the GenerateDefaultFixedNodes flag to “RequiredDefaults”, which means that all required nodes
are taken into account. This covers linked nodes, nodes that have default values, nodes with the MinOccurs
property set to greater than or equal to one, and nodes whose parents are required.
Resources
All source code is available in the Microsoft Code gallery here: BizTalk Mapper:
GenerateDefaultFixedNodes attribute of the mapsource element
(http://code.msdn.microsoft.com/BizTalk-Mapper-GenerateDefa-11aeb2f5)
PreserveSequenceOrder attribute
Sequence groups in XSD schemas do not provide a looping context because they are not represented in the message
instance. Without looping possibilities on the sequence group, the Mapper compiler does not generate the
appropriate XSLT to maintain the segment order. As a result, relative context that is present in the input instance is
lost, which makes the output instances useless for further processing that depends on the relative context.
You can use the PreserveSequenceOrder flag to maintain record order when mapping a repeating sequence to another
repeating sequence. By default, the value of the flag is set to No to preserve the functionality of existing maps created
in earlier BizTalk Server versions where the flag is not present. In the newly created maps, the flag will be present with
its value set to No. To maintain segment order, you must explicitly set the value to Yes in the .btm files.
Let’s take a look to a small example where we have an unbounded choice element where we can have Football Players
or Hockey Players information and we need to translate to another this to a unique node “Player” in the destination
schema.
362
BizTalk Mapping Patterns and Best Practices
<ns0:Input xmlns:ns0="http://PreserveSequenceOrder.Input">
<FootballPlayers>
<Name>Cristiano Ronaldo</Name>
<Gender>Male</Gender>
<Team>Real Madrid</Team>
</FootballPlayers>
<HockeyPlayers>
<Name>Wayne Gretzky</Name>
<Gender>Male</Gender>
<Team>New York Rangers</Team>
</HockeyPlayers>
<FootballPlayers>
<Name>Vitor Baia</Name>
<Gender>Male</Gender>
<Team>FC Porto</Team>
</FootballPlayers>
<HockeyPlayers>
<Name>Mario Lemieux</Name>
<Gender>Male</Gender>
<Team>Washington Capitals</Team>
</HockeyPlayers>
</ns0:Input>
With the PreserveSequenceOrder flag set to “No”, all the football player will be mapped first and then all the hockey
players. The output instance will look like the following:
ns0:Output xmlns:ns0="http://PreserveSequenceOrder.AnotherOutput">
<Player>
<Name>Cristiano Ronaldo</Name>
<Gender>Male</Gender>
<Team>Real Madrid</Team>
</Player>
<Player>
<Name>Vitor Baia</Name>
<Gender>Male</Gender>
<Team>FC Porto</Team>
</Player>
363
BizTalk Mapping Patterns and Best Practices
<Player>
<Name>Wayne Gretzky</Name>
<Gender>Male</Gender>
<Team>New York Rangers</Team>
</Player>
<Player>
<Name>Mario Lemieux</Name>
<Gender>Male</Gender>
<Team>Washington Capitals</Team>
</Player>
</ns0:Output>
With the PreserveSequenceOrder flag set to “Yes”, the map will respect the order of the player from the source
message. The output instance will look like the following:
<ns0:Output xmlns:ns0="http://PreserveSequenceOrder.AnotherOutput">
<Player>
<Name>Cristiano Ronaldo</Name>
<Gender>Male</Gender>
<Team>Real Madrid</Team>
</Player>
<Player>
<Name>Wayne Gretzky</Name>
<Gender>Male</Gender>
<Team>New York Rangers</Team>
</Player>
<Player>
<Name>Vitor Baia</Name>
<Gender>Male</Gender>
<Team>FC Porto</Team>
</Player>
<Player>
<Name>Mario Lemieux</Name>
<Gender>Male</Gender>
<Team>Washington Capitals</Team>
</Player>
</ns0:Output>
This is useful because in some scenarios we want to preserve the order of the elements.
Resources
Reference to this property:
All source code is available in the Microsoft Code gallery here: BizTalk Mapper:
PreserveSequenceOrder attribute of the mapsource element
(http://code.msdn.microsoft.com/BizTalk-Mapper-PreserveSequ-7537650d)
364
BizTalk Mapping Patterns and Best Practices
Wrapping up
Due to the countless number of different existing systems and applications in organizations, it is imperative to use
good tools and techniques to produce solutions that work for many years in a controlled and easy way to maintain. At
the same time, new processes are added and existing ones will suffer minor improvements, all this without losing track
of what is happening in production environment.
BizTalk Server helps us solve many of these problems, offering numerous features "out of the box" with the product.
The purpose of this is book is to explain in an intuitive and practical way the main concepts of maps, the best practices
that a developer or team should have and implement inside the maps and especially to explain how and when we
should apply some dominant types of patterns in our transformations.
With this book, as we explore some of the common mappings scenarios, we will try to dismantle the options that the
BizTalk Map engine has taken to fulfill with the original intent of the visual map and explain the advantages,
disadvantages of each technique implemented and provide alternatives.
When you begin to explore the world of maps, there are some important questions that should evaluate carefully
What is the best way to solve a problem? I will guaranteed that there are several approaches to solve a common
problem. Often deciding which the best way turns out to be the most difficult. Compile and analyze the code
generated can be a good start to begin to understand the impact of certain options.
What solution fits best into the problem and my team? Usually the mindset of the developer is focused on his
passions and technical expertise a problem that occurs in all technologies/languages and BizTalk Server is no
different. However they should start thinking not only on the problem but also the skills of the team as a whole
and implement a map solution to fits best in the problem but also in the skill of the team. The BizTalk Mapper is a
simple interface that new and expert developers now how to use it and read, even if another team take the solution
implemented they with minimum knowledge will understand the transformation, by passing the map and use only
XSLT files needs expert users with advance XSLT knowledge that most members of the team probably don’t have.
How can I test my maps? Very often we are tempted to try to solve a mapping problem from start to finish and
only then we test solution. Leave it to the end can make it extremely difficult to detect problems in complex
mappings. Limit the scope of testing should be a continuous and incremental process during the creation of maps,
tests must be carried out as soon as a significant block is completed.
I hope this kind of hacking can help you to understand the behavior and debugging techniques for this type of
elementary problems.
365
BizTalk Mapping Patterns and Best Practices