xsltxslt-1.0oxygenxml

How to use Key in XSLT Oxygen


I am trying to get the output based on two separate nodes in XML using key concept of XSLT I have below XML

<?xml version="1.0" encoding="UTF-8"?>
<mdti:Input xmlns:mdti="urn:com.workday/multiDocumentTransform/Input">
    <mdti:Files xmlns:mdti="urn:com.workday/multiDocumentTransform/Input">
        <mdti:EventFiles>
            <mdti:File mdti:filename="first.xml" mdti:contentType="text/xml">
                <wd:Report_Data xmlns:wd="urn:com.workday/bsvc">
                    <wd:Report_Entry>
                        <wd:key>1234</wd:key>
                        <wd:comp>ABC</wd:comp>
                        <wd:asof>2021-03-24T04:59:32.179-07:00</wd:asof>
                        <wd:emplid>33333333</wd:emplid>
                        <wd:worker_type>EMP</wd:worker_type>
                        <wd:emp_type>Regular</wd:emp_type>
                        <wd:orig_hire_dt>2021-11-27</wd:orig_hire_dt>
                        <wd:rehire_dt>2019-04-01</wd:rehire_dt>
                        <wd:home_host_class>M</wd:home_host_class>
                        <wd:service_dt>2014-11-27</wd:service_dt>
                    </wd:Report_Entry>
                </wd:Report_Data>
            </mdti:File>
            <mdti:File mdti:filename="second.xml" mdti:contentType="text/xml">
                <wd:Report_Data xmlns:wd="urn:com.workday/bsvc">
                    <wd:Report_Entry>
                        <wd:key>1234</wd:key>
                        <wd:supervisor_lname>xyz</wd:supervisor_lname>
                        <wd:hr_status>A</wd:hr_status>
                        <wd:hr_status_descr>Active</wd:hr_status_descr>
                        <wd:empl_status>A</wd:empl_status>
                        <wd:empl_status_descr>Active</wd:empl_status_descr>
                        <wd:ben_status>A</wd:ben_status>
                        <wd:home_address_change_dt>2019-07-30</wd:home_address_change_dt>
                        <wd:location>444</wd:location>
                        <wd:location_descr>Ind</wd:location_descr>
                    </wd:Report_Entry>
                </wd:Report_Data>
            </mdti:File>
        </mdti:EventFiles>
    </mdti:Files>
</mdti:Input>

**I am using below XSLT for my data. Please let me know if I am missing something and way to do it. The only identifier in each node is the mdti:filename **

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:mdti="urn:com.workday/multiDocumentTransform/Input"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:wd="urn:com.workday/bsvc"
    exclude-result-prefixes="#all">
    
    <xsl:key name="share" match="mdti:Input/mdti:Files/mdti:EventFiles/mdti:File/wd:Report_Data/wd:Report_Entry" use="mdti:Input/mdti:Files/mdti:EventFiles/mdti:File/wd:Report_Data/wd:Report_Entry/wd:key"/> 
    
    <xsl:template match="/">        
        <data>
            <key>1234</key>
            <xsl:copy-of select="key('share', wd:key)/wd:hr_status"/>      
            <emp_type>Regular</emp_type>
            <supervisor_lname>xyz</supervisor_lname>
            <hr_status>A</hr_status>
            <location>444</location>
        </data>
    </xsl:template>    
</xsl:stylesheet>

Solution

  • You have several mistakes.

    First, <xsl:template match="/"> puts you in the context of the root node; from this context, the expression wd:key selects nothing - so your instruction <xsl:copy-of select="key('share', wd:key)/wd:hr_status"/> does nothing.

    Next, if you want your key to match nodes in the second file, you should restrict it to match only nodes in the second file. Also, the use attribute must be relative to the matched node.

    Furthermore, if you want the result to be in no-namespace, you cannot copy nodes from the input - at least not in XSLT 1.0.

    There is more, but these are the ones that stand out immediately.

    Consider the following example:

    XSLT 1.0

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:mdti="urn:com.workday/multiDocumentTransform/Input"
    xmlns:wd="urn:com.workday/bsvc"
    exclude-result-prefixes="mdti wd">
    <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
     
    <xsl:key name="entry2" match="mdti:File[@mdti:filename='second.xml']/wd:Report_Data/wd:Report_Entry" use="wd:key"/> 
        
    <xsl:template match="/mdti:Input">   
        <root> 
            <xsl:for-each select="mdti:Files/mdti:EventFiles/mdti:File[@mdti:filename='first.xml']/wd:Report_Data/wd:Report_Entry"> 
                <data>
                    <!-- data from file1 -->    
                    <key>
                        <xsl:value-of select="wd:key"/>      
                    </key>
                     <emplid>
                        <xsl:value-of select="wd:emplid"/>      
                    </emplid>
                
                    <!-- data from file2 -->
                    <xsl:variable name="entry2" select="key('entry2', wd:key)" />
                    <supervisor_lname>
                        <xsl:value-of select="$entry2/wd:supervisor_lname"/>      
                    </supervisor_lname>
                    <hr_status>
                        <xsl:value-of select="$entry2/wd:hr_status"/>      
                    </hr_status>
                
                </data>
            </xsl:for-each> 
        </root>  
    </xsl:template> 
       
    </xsl:stylesheet>
    

    Applied to your input example, this will produce:

    Result

    <?xml version="1.0" encoding="utf-8"?>
    <root>
      <data>
        <key>1234</key>
        <emplid>33333333</emplid>
        <supervisor_lname>xyz</supervisor_lname>
        <hr_status>A</hr_status>
      </data>
    </root>
    

    You can add fields from both branches as required.