1

I have 2 xml file and requirement is to merge both file into one by matching node. Below are the files.

First XML is (the original one):

    <EF_Candidate_List>
    <EF_Candidate>
    <candidate_id>1</candidate_id>
    <field_1>foo</field_1>
    </EF_Candidate>
    <EF_Candidate>
    <candidate_id>2</candidate_id>
    <field_1>bar</field_1>
    </EF_Candidate>
    </EF_Candidate_List>

Second XML need to merge based on node

<EF_Candidate_List>
<EF_Candidate>
<candidate_id>1</candidate_id>
<account_number>10</account_number>
<account_number>50</account_number>
<EF_Candidate>
<candidate_id>2</candidate_id>
<account_number>20</account_number>
</EF_Candidate>
</EF_Candidate_List>

Expecting xml result file.

   <EF_Candidate_List>
    <EF_Candidate>
    <candidate_id>1</candidate_id>
    <field_1>foo</field_1>
    <column>10</column>
    <column>50</column>
    </EF_Candidate>
    <EF_Candidate>
    <candidate_id>2</candidate_id>
    <field_1>bar</field_1>
    <column>20</column>
    </EF_Candidate>
    </EF_Candidate_List>

I have created below xsl.

    <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:variable name="val" select="document('test2.xml')/EF_Candidate_List/EF_Candidate/account_number" />

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="EF_Candidate">
    <xsl:copy>
        <xsl:apply-templates/>
        <column>
            <xsl:value-of select="$val" />
        </column>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

it result into below xml file.

 <?xml version="1.0" encoding="UTF-8"?>
<EF_Candidate_List>
   <EF_Candidate>
      <candidate_id>1</candidate_id>
      <field_1>foo</field_1>
      <column>10</column>
   </EF_Candidate>
   <EF_Candidate>
      <candidate_id>2</candidate_id>
      <field_1>bar</field_1>
      <column>10</column>
   </EF_Candidate>
</EF_Candidate_List>

I'm fairly new to XSLT so please excuse the potentially novice question. Any guidance would be appreciated here. Thanks in advance.

  • Well, try to write an XPath expression with a predicate where you compare the `candidate_id` from an `EF_Candidate` of one document with the one of the other document, either making use of the `current()` XSLT function or by storing the id from one document in a variable. If there is any chance to move to XSLT 2 or 3, use a key. – Martin Honnen Jul 16 '21 at 08:31
  • See an example here: https://stackoverflow.com/a/68005242/3016153 – michael.hor257k Jul 16 '21 at 09:38

1 Answers1

0

you can create a variable with the current candidate id when you match EF_Candidate. And then get all account numbers from test2.xml where EF_Candidate contains candidate_id with the same value as current candidate id. And then for each account-number create a column element with its value.

<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="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="EF_Candidate">
    <xsl:variable name="current_candidate_id" select="candidate_id"/>
    <xsl:variable name="account-numbers" select="document('test2.xml')/EF_Candidate_List/EF_Candidate[candidate_id = $current_candidate_id]/account_number" />

    <xsl:copy>
        <xsl:apply-templates/>
        <xsl:for-each select="$account-numbers">
            <column>
                <xsl:value-of select="."/>
            </column>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>
Vasyl Krupa
  • 211
  • 1
  • 9