There is a subset of tasks that require substitution of several placeholders by provided values. Solving such tasks in XSLT is rather nonelegant.
<xsl:variable name="bodyText1" select="str:replace($bodyText, '$CustomerFirstName', @CustomerFirstName)" />
<xsl:variable name="bodyText2" select="str:replace($bodyText1, '$CustomerName', @CustomerName)" />
<xsl:variable name="bodyText3" select="str:replace($bodyText2, '$RentingStartDate', AS:FormatDate(@RentingStartDate, 'dd.MM.yyyy HH:mm'))" />
<xsl:variable name="bodyText4" select="str:replace($bodyText3, '$Object', AS:LookupValue('9b4c18af-12ad-4e05-8668-1cf448f899e7', @refRentalObjectId))" />
<xsl:variable name="bodyText5" select="str:replace($bodyText4, '$LocationAddress'
, concat(AS:LookupValue('651cff99-00b2-461c-a792-1a766c865c54', @refBusinessUnitId)
, ', ', AS:LookupValue('9d632a90-0470-4678-8516-977c69402143', @refBusinessUnitId)))" />
<xsl:variable name="bodyText6" select="str:replace($bodyText5, '$Location', AS:LookupValue('a392d1dc-519c-48b1-9f24-a3b8d9857337', @refBusinessUnitId))" />
<xsl:variable name="bodyText7" select="str:replace($bodyText6, '$TransactionNumber', @Number)" />
<xsl:variable name="bodyText8" select="str:replace($bodyText7, '$LesseeNote2', @LesseeNote2)" />
<xsl:variable name="bodyText9" select="str:replace($bodyText8, '$LesseeNote', @LesseeNote)" />
<xsl:variable name="bodyText10" select="str:replace($bodyText9, '$Logo', concat('<img src="'
,AS:GetConstant('Url'),'api/Organization/',@refOrganizationId,'/GetLogo" alt="Logo" width="200">'))" />
<xsl:variable name="bodyText11" select="str:replace($bodyText10, '$Last6DigitsOfTransactionNumber', substring(@Number, string-length(@Number) -5))" />
Having an access to a templating engine in form of a workflow service could make solutions for such tasks easier/more readable/more elegant.