XSLT Trying to split an XML input document based on number of nodes - xslt

I'm trying to split an xml input document for every 5 elements. Using the below sample input doc, I would like to split it for every 5 JournalEntry elements. I've also provided a sample output document.
XML Input
<?xml version="1.0" encoding="UTF-8"?>
<JournalFileData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:js="urn:com.journal/JournalSource" js:Add="false">
<AccountingData>
<Locked>0</Locked>
<Company js:type="Organization_Reference_ID">Some Company</Company>
<Currency>USD</Currency>
<Ledger>ACTUALS</Ledger>
<Date>12-15-2021</Date>
<Journal>Manual</Journal>
<JournalEntry>
<LineCompany js:type="Company">Widget Company</LineCompany>
<LedgerAccount js:type="Ledger_Account_ID">1000</LedgerAccount>
<CreditAmount>100</CreditAmount>
<Currency>USD</Currency>
</JournalEntry>
<JournalEntry>
<LineCompany js:type="Organization">Global Company</LineCompany>
<LedgerAccount js:type="Ledger_Account_ID">9999</LedgerAccount>
<DebitAmount>100</DebitAmount>
<Currency>USD</Currency>
</JournalEntry>
<JournalEntry>
<LineCompany js:type="Company">JAG Company</LineCompany>
<LedgerAccount js:type="Ledger_Account_ID">1000</LedgerAccount>
<DebitAmount>100</DebitAmount>
<Currency>USD</Currency>
</JournalEntry>
<JournalEntry>
<LineCompany js:type="Organization">Resource Company</LineCompany>
<LedgerAccount js:type="Ledger_Account_ID">9999</LedgerAccount>
<DebitAmount>100</DebitAmount>
<Currency>USD</Currency>
</JournalEntry>
<JournalEntry>
<LineCompany js:type="Organization">Supply Company</LineCompany>
<LedgerAccount js:type="Ledger_Account_ID">9999</LedgerAccount>
<DebitAmount>100</DebitAmount>
<Currency>USD</Currency>
</JournalEntry>
<JournalEntry>
<LineCompany js:type="Company">Plain Company</LineCompany>
<LedgerAccount js:type="Ledger_Account_ID">1000</LedgerAccount>
<DebitAmount>100</DebitAmount>
<Currency>USD</Currency>
</JournalEntry>
<JournalEntry>
<LineCompany js:type="Organization">Gnome Company</LineCompany>
<LedgerAccount js:type="Ledger_Account_ID">9999</LedgerAccount>
<DebitAmount>100</DebitAmount>
<Currency>USD</Currency>
</JournalEntry>
</AccountingData>
</JournalFileData>
XML Output
<?xml version="1.0" encoding="UTF-8"?>
<FileList>
<File>
<JournalFileData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:js="urn:com.journal/JournalSource" js:Add="false">
<AccountingData>
<Locked>0</Locked>
<Company js:type="Organization_Reference_ID">Some Company</Company>
<Currency>USD</Currency>
<Ledger>ACTUALS</Ledger>
<Date>12-15-2021</Date>
<Journal>Manual</Journal>
<JournalEntry>
<LineCompany js:type="Company">Widget Company</LineCompany>
<LedgerAccount js:type="Ledger_Account_ID">1000</LedgerAccount>
<CreditAmount>100</CreditAmount>
<Currency>USD</Currency>
</JournalEntry>
<JournalEntry>
<LineCompany js:type="Organization">Global Company</LineCompany>
<LedgerAccount js:type="Ledger_Account_ID">9999</LedgerAccount>
<DebitAmount>100</DebitAmount>
<Currency>USD</Currency>
</JournalEntry>
<JournalEntry>
<LineCompany js:type="Company">JAG Company</LineCompany>
<LedgerAccount js:type="Ledger_Account_ID">1000</LedgerAccount>
<DebitAmount>100</DebitAmount>
<Currency>USD</Currency>
</JournalEntry>
<JournalEntry>
<LineCompany js:type="Organization">Resource Company</LineCompany>
<LedgerAccount js:type="Ledger_Account_ID">9999</LedgerAccount>
<DebitAmount>100</DebitAmount>
<Currency>USD</Currency>
</JournalEntry>
</AccountingData>
</JournalFileData>
</File>
<File>
<JournalFileData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:js="urn:com.journal/JournalSource" js:Add="false">
<AccountingData>
<Locked>0</Locked>
<Company js:type="Organization_Reference_ID">Some Company</Company>
<Currency>USD</Currency>
<Ledger>ACTUALS</Ledger>
<Date>12-15-2021</Date>
<Journal>Manual</Journal>
<JournalEntry>
<LineCompany js:type="Company">Plain Company</LineCompany>
<LedgerAccount js:type="Ledger_Account_ID">1000</LedgerAccount>
<DebitAmount>100</DebitAmount>
<Currency>USD</Currency>
</JournalEntry>
<JournalEntry>
<LineCompany js:type="Organization">Gnome Company</LineCompany>
<LedgerAccount js:type="Ledger_Account_ID">9999</LedgerAccount>
<DebitAmount>100</DebitAmount>
<Currency>USD</Currency>
</JournalEntry>
</AccountingData>
</JournalFileData>
</File>
</FileList>
Here is my last xslt attempt (Please excuse any typos. I had to type this out). I've had various results but none have gotten me the output I need. I'm having trouble finding the correct syntax to get the format outlined in the xml output. Also having trouble trying to copy the child nodes for each AccountingData node. I don't work with xslt frequent enough and still consider myself a novice so any help is appreciated. This is just my last try.:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:js="urn:com.journal/JournalSource" js:Add="false"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="JournalFileData/AccountingData">
<FileList>
<xsl:copy>
<xsl:for-each-group select="JournalEntry" group-adjacent="(position() -1) idiv 5">
<File>
<JournalFileData xmlns:js="urn:com.journal/JournalSource" js:Add="false">
<AccountingData>
<xsl:copy-of select="current-group()"/>
</AccountingData>
</JournalFileData>
</File>
</xsl:for-each-group>
</xsl:copy>
</FileList>
</xsl:template>
</xsl:stylesheet>

You only need to make a few minor adjustments to get the result you show:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/JournalFileData">
<FileList>
<xsl:for-each select="AccountingData">
<xsl:variable name="common" select="* except JournalEntry" />
<xsl:for-each-group select="JournalEntry" group-adjacent="(position() -1) idiv 5">
<File>
<JournalFileData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:js="urn:com.journal/JournalSource" js:Add="false">
<AccountingData>
<xsl:copy-of select="$common"/>
<xsl:copy-of select="current-group()"/>
</AccountingData>
</JournalFileData>
</File>
</xsl:for-each-group>
</xsl:for-each>
</FileList>
</xsl:template>
</xsl:stylesheet>

Related

Use map function to change field value using xslt 3.0

I need to map field value from hash table only in Debtor field and other values remains same.
I want the all other fields to be as it is and only change the map the debtor fields.
P_BPMapping - {"BANK1":"1","BANK2":"2","BANK3":"3","BANK4":"4"}
My input xml
<?xml version="1.0" encoding="UTF-8"?>
<JECreateRequest>
<MessageHeader>
</MessageHeader>
<JournalEntryCreateRequest>
<MessageHeader>
<JournalEntry>
<DebtorItem>
<Debtor>BANK1</Debtor>
</DebtorItem>
</JournalEntry>
</MessageHeader>
</JournalEntryCreateRequest>
<JournalEntryCreateRequest>
<MessageHeader>
<JournalEntry>
<DebtorItem>
<Debtor>BANK2</Debtor>
</DebtorItem>
<DebtorItem>
<Debtor>BANK1</Debtor>
</DebtorItem>
</JournalEntry>
</MessageHeader>
</JournalEntryCreateRequest>
<JournalEntryCreateRequest>
<MessageHeader>
<JournalEntry>
<DebtorItem>
<Debtor>BANK4</Debtor>
</DebtorItem>
<DebtorItem>
<Debtor>BANK3</Debtor>
</DebtorItem>
<DebtorItem>
<Debtor>BANK1</Debtor>
</DebtorItem>
</JournalEntry>
</MessageHeader>
</JournalEntryCreateRequest>
</JournalEntryBulkCreateRequest>
Hash Table
BANK1 - 1
BANK2 - 2
BANK3 - 3
BANK4 - 4
My XSLT code - I have tried with this XSLT code and getting error.
<xsl:stylesheet
version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- Start of enhancement - ValueMapping for Payloution Customer -->
<xsl:param name="P_BPMapping" />
<xsl:param name="MapDebitor" as="map(*)" select="parse-json($P_BPMapping)" />
<!-- End of enhancement -->
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!--
<xsl:for-each select ="MessageHeader/JournalEntryCreateRequest/JournalEntry/DebtorItem">
-->
<xsl:template match="MessageHeader">
<xsl:for-each select ="JournalEntryCreateRequest/JournalEntry/DebtorItem">
<xsl:template match="Debtor">
<xsl:copy>
<xsl:choose>
<xsl:when test="map:get($MapDebitor,Debtor)">
<xsl:value-of select="map:get($MapDebitor,Debtor)" />
</xsl:when>
<xsl:otherwise>
<error>
<xsl:text>Error in BusinessPartner mapping. Please maintain the mapping for the following debtor: </xsl:text>
<xsl:value-of select="Debtor"/>
</error>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
</xsl:for-each>
</xsl:template>
<!--
</xsl:for-each>
-->
</xsl:stylesheet>
Expected output
<?xml version="1.0" encoding="UTF-8"?>
<JECreateRequest>
<MessageHeader>
</MessageHeader>
<JournalEntryCreateRequest>
<MessageHeader>
<JournalEntry>
<DebtorItem>
<Debtor>1</Debtor>
</DebtorItem>
</JournalEntry>
</MessageHeader>
</JournalEntryCreateRequest>
<JournalEntryCreateRequest>
<MessageHeader>
<JournalEntry>
<DebtorItem>
<Debtor>2</Debtor>
</DebtorItem>
<DebtorItem>
<Debtor>1</Debtor>
</DebtorItem>
</JournalEntry>
</MessageHeader>
</JournalEntryCreateRequest>
<JournalEntryCreateRequest>
<MessageHeader>
<JournalEntry>
<DebtorItem>
<Debtor>4</Debtor>
</DebtorItem>
<DebtorItem>
<Debtor>3</Debtor>
</DebtorItem>
<DebtorItem>
<Debtor>1</Debtor>
</DebtorItem>
</JournalEntry>
</MessageHeader>
</JournalEntryCreateRequest>
</JournalEntryBulkCreateRequest>
I would use e.g.
<xsl:param name="map-data" as="xs:string" expand-text="no">{"BANK1":"1","BANK2":"2","BANK3":"3","BANK4":"4"}</xsl:param>
<xsl:param name="map" select="parse-json($map-data)"/>
<xsl:template match="Debtor[map:contains($map, .)]">
<xsl:copy>{$map(.)}</xsl:copy>
</xsl:template>
<xsl:mode on-no-match="shallow-copy"/>
(with xmlns:map="http://www.w3.org/2005/xpath-functions/map" and expand-text="yes" being declared in the XSLT).
Your code also seems to try to find non-matching Debtors and output some error so perhaps an additional template
<xsl:template match="Debtor[not(map:contains($map, .))]">
<xsl:copy>
<error>Error in BusinessPartner mapping. Please maintain the mapping for the following debtor: {.}</error>
</xsl:copy>
</xsl:template>
is needed, though the input/output samples don't show that case.
Online sample demo.

XSLT total per unique value

Apologies. I asked a question just a few days ago and it was already answered by Sir michael.hor257k.
I have a new requirement though.
The TOTAL field needs to count the sgtin fields per unique value like the sample below.
<xsl:template match="/*">
<MESSAGE>
<PALLET>
<xsl:for-each select="//*[local-name()='ObjectEvent'][substring(epcList/epc,1,16) = 'urn:epc:id:sgtin']">
<MATERIAL>
<BOX>
<TOTAL>
<xsl:value-of select="count(./epcList/epc[substring(.,1,16) = 'urn:epc:id:sgtin'])"/>
</TOTAL>
<xsl:for-each select="./epcList/epc[substring(.,1,16) = 'urn:epc:id:sgtin']">
<SERIES>
<ITEM>
<xsl:value-of select="substring-after(substring-after(.,'.'),'.')"/>
</ITEM>
</SERIES>
</BOX>
</MATERIAL>
</PALLET>
</MESSAGE>
This is a sample input file:
<?xml version="1.0" encoding="UTF-8"?>
<n0:EPCISDocument xmlns:n0="urn:epcglobal:epcis:xsd:1" xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" schemaVersion="1.1">
<ObjectEvent>
<epcList>
<epc>urn:epc:id:sgtin:999999999.0000.0000000001</epc>
<epc>urn:epc:id:sgtin:999999999.0000.0000000002</epc>
</epcList>
<Extension>
<obj>
<BATCH>ABCD_00</BATCH>
</obj>
</Extension>
</ObjectEvent>
<ObjectEvent>
<epcList>
<epc>urn:epc:id:sgtin:999999999.0000.0000000003</epc>
<epc>urn:epc:id:sgtin:999999999.0000.0000000004</epc>
<epc>urn:epc:id:sgtin:999999999.0000.0000000005</epc>
</epcList>
<Extension>
<obj>
<BATCH>ABCD_00</BATCH>
</obj>
</Extension>
</ObjectEvent>
<ObjectEvent>
<epcList>
<epc>urn:epc:id:sgtin:999999999.1111.0000000006</epc>
<epc>urn:epc:id:sgtin:999999999.1111.0000000007</epc>
<epc>urn:epc:id:sgtin:999999999.1111.0000000008</epc>
</epcList>
<Extension>
<obj>
<BATCH>EFGH_11</BATCH>
</obj>
</Extension>
</ObjectEvent>
<ObjectEvent>
<epcList>
<epc>urn:epc:id:sgtin:999999999.2222.0000000009</epc>
</epcList>
<Extension>
<obj>
<BATCH>IJKL_22</BATCH>
</obj>
</Extension>
</ObjectEvent>
</n0:EPCISDocument>
The TSERIES will be counted per GTIN (0000, 1111, 2222).
The expected should be:
<?xml version="1.0" encoding="UTF-8"?>
<MESSAGE>
<PALLET>
<MATERIAL>
<BOX>
<TOTAL>5</TOTAL>
<SERIES>
<ITEM>0000000001</ITEM>
</SERIES>
<SERIES>
<ITEM>0000000002</ITEM>
</SERIES>
</BOX>
</MATERIAL>
<MATERIAL>
<BOX>
<TOTAL>5</TOTAL>
<SERIES>
<ITEM>0000000003</ITEM>
</SERIES>
<SERIES>
<ITEM>0000000004</ITEM>
</SERIES>
<SERIES>
<ITEM>0000000005</ITEM>
</SERIES>
</BOX>
</MATERIAL>
<MATERIAL>
<BOX>
<TOTAL>3</TOTAL>
<SERIES>
<ITEM>0000000006</ITEM>
</SERIES>
<SERIES>
<ITEM>0000000007</ITEM>
</SERIES>
<SERIES>
<ITEM>0000000008</ITEM>
</SERIES>
</BOX>
</MATERIAL>
<MATERIAL>
<BOX>
<TOTAL>1</TOTAL>
<SERIES>
<ITEM>0000000009</ITEM>
</SERIES>
</BOX>
</MATERIAL>
</PALLET>
</MESSAGE>
Is this possible Masters?
edit:
I'm not sure if this can help. I edited the source payload to add BATCH field. that is unique per GTIN. Can it be used for the TSERIES total?
As I said in the comment, this is a grouping problem and the preferred solution in XSLT 1.0 is to use the Muenchian grouping method:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="batch" match="ObjectEvent" use="Extension/obj/BATCH" />
<xsl:template match="/*">
<MESSAGE>
<PALLET>
<!-- for each distinct batch -->
<xsl:for-each select="ObjectEvent[count(. | key('batch', Extension/obj/BATCH)[1]) = 1]">
<xsl:variable name="current-group" select="key('batch', Extension/obj/BATCH)" />
<xsl:variable name="group-total" select="count($current-group/epcList/epc)"/>
<!-- for each ObjectEvent in this batch -->
<xsl:for-each select="$current-group">
<MATERIAL>
<BOX>
<TOTAL>
<xsl:value-of select="$group-total"/>
</TOTAL>
<xsl:for-each select="epcList/epc">
<SERIES>
<ITEM>
<xsl:value-of select="substring(., 33)"/>
</ITEM>
</SERIES>
</xsl:for-each>
</BOX>
</MATERIAL>
</xsl:for-each>
</xsl:for-each>
</PALLET>
</MESSAGE>
</xsl:template>
</xsl:stylesheet>
Note that this assumes all SGTINs have the same number of characters.

Nested Conditional Looping (One to Many )

The Input has two xml in it , The InputMessagePart_0 have Multiple Location id and InputMessagePart_1 have Multiple ItemMaster then i need to create an Output where for every location id i need to have the Item Master.
I have written the Xslt where its not looping on the InputMessagePart_0(Record) level and its taking only the first Location id ,
XSlT1.0 :
<?xml version="1.0" encoding="UTF-16"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" exclude-result-prefixes="msxsl var s0 s2 s1" version="1.0" xmlns:s0="http://Test.ItemMaster" xmlns:s2="http://schemas.microsoft.com/BizTalk/2003/aggschema" xmlns:s1="http://Test.Lookup" xmlns:ns0="http://Test.Out">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
<xsl:template match="/">
<xsl:apply-templates select="/s2:Root" />
</xsl:template>
<xsl:template match="/s2:Root">
<ns0:Root>
<xsl:for-each select="InputMessagePart_1/s0:Root/ItemMaster">
<xsl:variable name="var:v1" select="../../../InputMessagePart_0/s1:Root/Record/LocationId" />
<xsl:variable name="var:v2" select="ItemId" />
<xsl:variable name="var:v3" select="ItemName" />
<xsl:variable name="var:v4" select="Quantity" />
<Detail>
<LocationId>
<xsl:value-of select="$var:v1" />
</LocationId>
<ItemId>
<xsl:value-of select="$var:v2" />
</ItemId>
<ItemName>
<xsl:value-of select="$var:v3" />
</ItemName>
<Qty>
<xsl:value-of select="$var:v4" />
</Qty>
</Detail>
</xsl:for-each>
</ns0:Root>
</xsl:template>
</xsl:stylesheet>
Input XML :
<ns0:Root xmlns:ns0="http://schemas.microsoft.com/BizTalk/2003/aggschema">
<InputMessagePart_0>
<ns0:Root xmlns:ns0="http://Test.Lookup">
<Record>
<LocationId>12</LocationId>
</Record>
<Record>
<LocationId>13</LocationId>
</Record>
<Record>
<LocationId>14</LocationId>
</Record>
</ns0:Root>
</InputMessagePart_0>
<InputMessagePart_1>
<ns0:Root xmlns:ns0="http://Test.ItemMaster">
<ItemMaster>
<ItemId>123</ItemId>
<ItemName>Knife</ItemName>
<Quantity>1</Quantity>
</ItemMaster>
<ItemMaster>
<ItemId>1234</ItemId>
<ItemName>Knife1</ItemName>
<Quantity>1</Quantity>
</ItemMaster>
<ItemMaster>
<ItemId>1235</ItemId>
<ItemName>Knife3</ItemName>
<Quantity>1</Quantity>
</ItemMaster>
</ns0:Root>
</InputMessagePart_1>
</ns0:Root>
Current OutPut:
<ns0:Root xmlns:ns0="http://Test.Out">
<Detail>
<LocationId>12</LocationId>
<ItemId>123</ItemId>
<ItemName>Knife</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>12</LocationId>
<ItemId>1234</ItemId>
<ItemName>Knife1</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>12</LocationId>
<ItemId>1235</ItemId>
<ItemName>Knife3</ItemName>
<Qty>1</Qty>
</Detail>
</ns0:Root>
Desired OutPut :
<ns0:Root xmlns:ns0="http://Test.Out">
<Detail>
<LocationId>12</LocationId>
<ItemId>123</ItemId>
<ItemName>Knife</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>12</LocationId>
<ItemId>1234</ItemId>
<ItemName>Knife1</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>12</LocationId>
<ItemId>1235</ItemId>
<ItemName>Knife3</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>13</LocationId>
<ItemId>123</ItemId>
<ItemName>Knife</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>13</LocationId>
<ItemId>1234</ItemId>
<ItemName>Knife1</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>13</LocationId>
<ItemId>1235</ItemId>
<ItemName>Knife3</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>14</LocationId>
<ItemId>123</ItemId>
<ItemName>Knife</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>14</LocationId>
<ItemId>1234</ItemId>
<ItemName>Knife1</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>14</LocationId>
<ItemId>1235</ItemId>
<ItemName>Knife3</ItemName>
<Qty>1</Qty>
</Detail>
</ns0:Root>
Desired OutPut :
<ns0:Root xmlns:ns0="http://Test.Out">
<Detail>
<LocationId>12</LocationId>
<ItemId>123</ItemId>
<ItemName>Knife</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>12</LocationId>
<ItemId>1234</ItemId>
<ItemName>Knife1</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>12</LocationId>
<ItemId>1235</ItemId>
<ItemName>Knife3</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>13</LocationId>
<ItemId>123</ItemId>
<ItemName>Knife</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>13</LocationId>
<ItemId>1234</ItemId>
<ItemName>Knife1</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>13</LocationId>
<ItemId>1235</ItemId>
<ItemName>Knife3</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>14</LocationId>
<ItemId>123</ItemId>
<ItemName>Knife</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>14</LocationId>
<ItemId>1234</ItemId>
<ItemName>Knife1</ItemName>
<Qty>1</Qty>
</Detail>
<Detail>
<LocationId>14</LocationId>
<ItemId>1235</ItemId>
<ItemName>Knife3</ItemName>
<Qty>1</Qty>
</Detail>
</ns0:Root>
You need to have an xsl:for-each (or xsl:apply-templates) to get the Record elements with the locations. (And this xsl:for-each would contain the current xsl:for-each on the ItemMaster)
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" exclude-result-prefixes="msxsl var s0 s2 s1" version="1.0" xmlns:s0="http://Test.ItemMaster" xmlns:s2="http://schemas.microsoft.com/BizTalk/2003/aggschema" xmlns:s1="http://Test.Lookup" xmlns:ns0="http://Test.Out">
<xsl:output omit-xml-declaration="yes" method="xml" indent="yes" version="1.0" />
<xsl:template match="/s2:Root">
<ns0:Root>
<xsl:for-each select="InputMessagePart_0/s1:Root/Record">
<xsl:variable name="var:v1" select="LocationId" />
<xsl:for-each select="../../../InputMessagePart_1/s0:Root/ItemMaster">
<Detail>
<LocationId>
<xsl:value-of select="$var:v1" />
</LocationId>
<ItemId>
<xsl:value-of select="ItemId" />
</ItemId>
<ItemName>
<xsl:value-of select="ItemName" />
</ItemName>
<Qty>
<xsl:value-of select="Quantity" />
</Qty>
</Detail>
</xsl:for-each>
</xsl:for-each>
</ns0:Root>
</xsl:template>
</xsl:stylesheet>
Note, the template matching / wasn't really necessary here, as XSLT's built-in template does the same thing.

XSLT to check content prior to mapping

I need some help with XSLT to check each of the Source <Info> elements with #Type="bar".
If their child <Ref> elements are contained in the child <Ref> elements of the <Info> elements with #Type="foo",
I want a <Info> with #Type="foo" created in the target with the same <Refs>.
I struggle with the lack of dynamically updatebale variables in XSLT !
See source and expected target below
Source
<?xml version="1.0" encoding="UTF-8"?>
<Infos>
<Info Type="foo">
<Refs>
<Ref>1</Ref>
<Ref>2</Ref>
<Ref>3</Ref>
</Refs>
<Content>FOO CONTENT</Content>
</Info>
<Info Type="bar">
<Refs>
<Ref>1</Ref>
<Ref>2</Ref>
</Refs>
<Content>BAR 1 CONTENT</Content>
</Info>
<Info Type="bar">
<Refs>
<Ref>3</Ref>
</Refs>
<Content>BAR 2 CONTENT</Content>
</Info>
<Info Type="bar">
<Refs>
<Ref>4</Ref>
</Refs>
<Content>BAR 3 CONTENT</Content>
</Info>
</Infos>
Expected Target
<?xml version="1.0" encoding="UTF-8"?>
<Infos>
<Info Type="foo">
<Refs>
<Ref>1</Ref>
<Ref>2</Ref>
</Refs>
<Content>FOO CONTENT</Content>
</Info>
<Info Type="foo">
<Refs>
<Ref>3</Ref>
</Refs>
<Content>FOO CONTENT</Content>
</Info>
<Info Type="bar">
<Refs>
<Ref>1</Ref>
<Ref>2</Ref>
</Refs>
<Content>BAR 1 CONTENT</Content>
</Info>
<Info Type="bar">
<Refs>
<Ref>3</Ref>
</Refs>
<Content>BAR 2 CONTENT</Content
</Info>
<Info Type="bar">
<Refs>
<Ref>4</Ref>
</Refs>
<Content>BAR 3 CONTENT</Content
</Info>
</Infos>
So note two foo elements created as the original had refs 1,2,3 and there is a bar with 1,2 and a bar with 3.
Also the original bar elements get mapped exactly as per source .
If I understand this correctly (which is not at all certain), you want to do:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="foo" match="Info[#Type='foo']" use="Refs/Ref" />
<xsl:template match="/Infos">
<xsl:copy>
<xsl:apply-templates select="Info[#Type='bar'][key('foo', Refs/Ref)]" mode="foo"/>
<xsl:copy-of select="Info[#Type='bar']"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Info" mode="foo">
<Info Type="foo">
<xsl:copy-of select="Refs"/>
<xsl:copy-of select="key('foo', Refs/Ref)/*[not(self::Refs)]"/>
</Info>
</xsl:template>
</xsl:stylesheet>
Basically, this takes all bar nodes that have a match with one of the references listed under foo, recreates them as foo nodes and copies the content from the matching foo node. Then it copies all the bar nodes as is.

Need to merge 2 xml in xslt based on a common key

I have 2 source variables which need to be merged based on a common key in XSLT
Variable 1:I have added few properties for each employee.
<EmpDetails>
<Emp>
<ID>1</ID>
<Name>A</Name>
<Address>abc 123</Address>
<Contact>1234567890</Contact>
<DOB>01/01/1989</DOB>
<Emp>
<Emp>
<ID>2</ID>
<Name>B</Name>
<Address>ASDF</Address>
<Contact>123456</Contact>
<DOB>02/02/1990</DOB>
<Emp>
</EmpDetails>
Variable 2:
<EmpAgeDetails>
<EmpAge>
<ID>1</ID>
<Age>27</Age>
<EmpAge>
<EmpAge>
<ID>2</ID>
<Age>26</Age>
<EmpAge>
</EmpAgeDetails>
Expected output:
<EmpDetails>
<Emp>
<ID>1</ID>
<Name>A</Name>
<Address>abc 123</Address>
<Contact>1234567890</Contact>
<DOB>01/01/1989</DOB>
<Age>27</Age>
<Emp>
<Emp>
<ID>2</ID>
<Name>B</Name>
<Address>ASDF</Address>
<Contact>123456</Contact>
<DOB>02/02/1990</DOB>
<Age>26</Age>
<Emp>
</EmpDetails>
I am using a template to copy all elements from Variable 1 which is working fine.
But now I need to merge that extra element of Age.
Any help is appreciated
Using XSLT 3.0 and xsl:merge, as supported in the latest Altova XMLSpy/Raptor or Saxon 9.7 EE, you can use
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:math="http://www.w3.org/2005/xpath-functions/math" xmlns:array="http://www.w3.org/2005/xpath-functions/array" xmlns:map="http://www.w3.org/2005/xpath-functions/map" exclude-result-prefixes="array fn map math xs">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="doc1">
<EmpDetails>
<Emp>
<ID>1</ID>
<Name>A</Name>
<Address>abc 123</Address>
<Contact>1234567890</Contact>
<DOB>01/01/1989</DOB>
</Emp>
<Emp>
<ID>2</ID>
<Name>B</Name>
<Address>ASDF</Address>
<Contact>123456</Contact>
<DOB>02/02/1990</DOB>
</Emp>
</EmpDetails>
</xsl:param>
<xsl:param name="doc2">
<EmpAgeDetails>
<EmpAge>
<ID>1</ID>
<Age>27</Age>
</EmpAge>
<EmpAge>
<ID>2</ID>
<Age>26</Age>
</EmpAge>
</EmpAgeDetails>
</xsl:param>
<xsl:template match="/" name="xsl:initial-template">
<EmpDetails>
<xsl:merge>
<xsl:merge-source select="$doc1/EmpDetails/Emp">
<xsl:merge-key select="ID"></xsl:merge-key>
</xsl:merge-source>
<xsl:merge-source select="$doc2/EmpAgeDetails/EmpAge">
<xsl:merge-key select="ID"></xsl:merge-key>
</xsl:merge-source>
<xsl:merge-action>
<xsl:copy>
<xsl:apply-templates select="current-merge-group()[1]/*, fn:current-merge-group()[2]/Age"/>
</xsl:copy>
</xsl:merge-action>
</xsl:merge>
</EmpDetails>
</xsl:template>
</xsl:stylesheet>
Using XSLT 2.0 you could group:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:param name="doc1">
<EmpDetails>
<Emp>
<ID>1</ID>
<Name>A</Name>
<Address>abc 123</Address>
<Contact>1234567890</Contact>
<DOB>01/01/1989</DOB>
</Emp>
<Emp>
<ID>2</ID>
<Name>B</Name>
<Address>ASDF</Address>
<Contact>123456</Contact>
<DOB>02/02/1990</DOB>
</Emp>
</EmpDetails>
</xsl:param>
<xsl:param name="doc2">
<EmpAgeDetails>
<EmpAge>
<ID>1</ID>
<Age>27</Age>
</EmpAge>
<EmpAge>
<ID>2</ID>
<Age>26</Age>
</EmpAge>
</EmpAgeDetails>
</xsl:param>
<xsl:template match="/" name="main">
<EmpDetails>
<xsl:for-each-group select="$doc1/EmpDetails/Emp, $doc2/EmpAgeDetails/EmpAge" group-by="ID">
<xsl:copy>
<xsl:copy-of select="current-group()[1]/*, current-group()[2]/Age"/>
</xsl:copy>
</xsl:for-each-group>
</EmpDetails>
</xsl:template>
</xsl:stylesheet>