Home > Software design >  XSLT Mapping - combining multiple related XML
XSLT Mapping - combining multiple related XML

Time:10-11

I am trying to explore and learn XSLT mapping with a pretty basic requirement though I am not sure on how to proceed.

Basically I have multiple payloads.

Payload 1

<?xml version="1.0" encoding="UTF-8" ?>
<root>
  <header>
    <quoteType>YQT</quoteType>
    <salesOrg>5010</salesOrg>
    <distributionChannel>00</distributionChannel>
    <division>00</division>
    <deliveryDateHeader>2022-09-29T00:00Z</deliveryDateHeader>
    <shippingCondition>01</shippingCondition>
  </header>
  <partner>
    <partnerNumber>100193</partnerNumber>
    <partnerFunction>SP</partnerFunction>
  </partner>
  <partner>
    <partnerNumber>100193</partnerNumber>
    <partnerFunction>WE</partnerFunction>
  </partner>
  <partner>
    <partnerNumber>100193</partnerNumber>
    <partnerFunction>RE</partnerFunction>
  </partner>
  <materialsAvailibility>
    <itemNumber>110</itemNumber>
    <materialNumber>188521</materialNumber>
  </materialsAvailibility>
</root>

Payload 2

<?xml version="1.0" encoding="UTF-8" ?>
<root>
  <header>
    <quoteType>YQT</quoteType>
    <salesOrg>5010</salesOrg>
    <distributionChannel>00</distributionChannel>
    <division>00</division>
    <deliveryDateHeader>2022-09-29T00:00Z</deliveryDateHeader>
    <shippingCondition>01</shippingCondition>
  </header>
  <partner>
    <partnerNumber>100193</partnerNumber>
    <partnerFunction>SP</partnerFunction>
  </partner>
  <partner>
    <partnerNumber>100193</partnerNumber>
    <partnerFunction>WE</partnerFunction>
  </partner>
  <partner>
    <partnerNumber>100193</partnerNumber>
    <partnerFunction>RE</partnerFunction>
  </partner>
  <materialsAvailibility>
    <itemNumber>10</itemNumber>
    <materialNumber>115517</materialNumber>
  </materialsAvailibility>
</root>

Expected Output

<?xml version="1.0" encoding="UTF-8" ?>
<root>
  <header>
    <quoteType>YQT</quoteType>
    <salesOrg>5010</salesOrg>
    <distributionChannel>00</distributionChannel>
    <division>00</division>
    <deliveryDateHeader>2022-09-29T00:00Z</deliveryDateHeader>
    <shippingCondition>01</shippingCondition>
  </header>
  <partner>
    <partnerNumber>100193</partnerNumber>
    <partnerFunction>SP</partnerFunction>
  </partner>
  <partner>
    <partnerNumber>100193</partnerNumber>
    <partnerFunction>WE</partnerFunction>
  </partner>
  <partner>
    <partnerNumber>100193</partnerNumber>
    <partnerFunction>RE</partnerFunction>
  </partner>
 <materialsAvailibility>
    <itemNumber>110</itemNumber>
    <materialNumber>188521</materialNumber>
  </materialsAvailibility>
  <materialsAvailibility>
    <itemNumber>10</itemNumber>
    <materialNumber>115517</materialNumber>
  </materialsAvailibility>
</root>

The header and partner nodes are always identical and I just need to collate the materialAvailibility together. Can someone help provide a working XSLT mapping for this and I will try to study what does the specific lines do. Thanks in advance.

CodePudding user response:

Try following powershell script. Code works without the root node.

using assembly System.Collections
using assembly System.Xml
using assembly System.Xml.Linq 

$inputFilename1 = "C:\temp\test.xml"
$inputFilename2 = "C:\temp\test1.xml"
$outputFilename = "C:\temp\test2.xml"


$rSettings = New-Object System.Xml.XmlReaderSettings
$rSettings.ConformanceLevel = [System.Xml.ConformanceLevel]::Fragment

$reader1 = [System.Xml.XmlReader]::Create($inputFilename1,$rSettings)
$nodes1 = New-Object System.Collections.Generic.List[System.Xml.Linq.XElement]
while($reader1.EOF -eq $False)
{
   if($reader1.IsStartElement() -eq $False) {$reader2.MoveToContent()}

   $nodes1.Add([System.Xml.Linq.XElement]::ReadFrom($reader1));
}

$reader2 = [System.Xml.XmlReader]::Create($inputFilename2,$rSettings)
$nodes2 = New-Object System.Collections.Generic.List[System.Xml.Linq.XElement]
while($reader2.EOF -eq $False)
{
   if($reader2.IsStartElement() -eq $False) {$reader2.MoveToContent()}

   $nodes2.Add([System.Xml.Linq.XElement]::ReadFrom($reader2));
}

$materialsAvailibility2 = [System.Linq.Enumerable]::Where($nodes2, [Func[object,bool]]{ param($x) $x.Name.LocalName -eq "materialsAvailibility"})
$materialsAvailibility2 = [System.Linq.Enumerable]::First($materialsAvailibility2)
$materialsAvailibility2 = [System.Xml.Linq.XElement]$materialsAvailibility2
#Write-Host $materialsAvailibility2
$nodes1.Add($materialsAvailibility2)

$sWriter = New-Object System.IO.StreamWriter($outputFilename)
$sWriter.WriteLine("<?xml version=""1.0"" encoding=""UTF-8"" ?>");

$wSettings = New-Object System.Xml.XmlWriterSettings
$wSettings.ConformanceLevel = [System.Xml.ConformanceLevel]::Fragment
$wSettings.Indent = $True;

$xWriter = [System.Xml.XmlWriter]::Create($sWriter,$wSettings);
foreach ($node1 in $nodes1)
{
#Write-Host $node1
   $node1.WriteTo($xWriter);     
#Write-Host "end"
}
            
$xWriter.Flush();
$xWriter.Close();

CodePudding user response:

The simplest is probably

<xsl:template match="/*">
  <xsl:copy>
    <xsl:copy-of select="*, doc('payload2.xml')//materialsAvailability"/>
  </xsl:copy>
</xsl:template>
  • Related