简体   繁体   中英

How to remove nodes from XML based on conditions?

I need to remove duplicate nodes from below XML based on a condition. Can someone please help me fix the XSLT I have written? Or suggest a workaround?

My requirement: Remove entire nodes if below conditions are met.

  1. If employee id has duplicate entries
  2. If above condition is 'true', retain Worker node where in 'Type' is 'Employee'. Other duplicate 'worker' node entry with same employee id will have 'Type' as 'Contingent'.

XML File:

 <?xml version="1.0" encoding="UTF-8"?>
 <Workers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Header>
        <File>22.0</File>
        <Date>2014-05-31T16:20:07.000-07:00</Date>
        <Worker_Count>2</Worker_Count>
    </Header>
    <Worker>
        <Summary>
            <Employee_ID>12345800</Employee_ID>
            <Name>John Davis (12345800)</Name>
            <Type>Employee</Type>
        </Summary>
    </Worker>
    <Worker>
        <Summary>
            <Employee_ID>12345800</Employee_ID>
            <Name>John Davis (12345800)</Name>
            <Type>Contingent</Type>
        </Summary>
    </Worker>
    <Worker>
        <Summary>
            <Employee_ID>32451854</Employee_ID>
            <Name>Felix (32451854)</Name>
            <Type>Employee</Type>
        </Summary>
    </Worker>
    <Worker>
        <Summary>
            <Employee_ID>23471732</Employee_ID>
            <Name>David (23471732)</Name>
            <Type>Contingent</Type>
        </Summary>
    </Worker>
    <Worker>
        <Summary>
            <Employee_ID>38741297</Employee_ID>
            <Name>Sam Daniel (38741297)</Name>
            <Type>Employee</Type>
        </Summary>
    </Worker>
    <Worker>
        <Summary>
            <Employee_ID>38741297</Employee_ID>
            <Name>Sam Daniel (38741297)</Name>
            <Type>Contingent</Type>
        </Summary>
    </Worker>
</Workers>

Above XML need be transformed as below.

<?xml version="1.0" encoding="UTF-8"?>
<Workers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Header>
        <File>22.0</File>
        <Date>2014-05-31T16:20:07.000-07:00</Date>
        <Worker_Count>2</Worker_Count>
    </Header>
    <Worker>
        <Summary>
            <Employee_ID>12345800</Employee_ID>
            <Name>John Davis (12345800)</Name>
            <Type>Employee</Type>
        </Summary>
    </Worker>
    <Worker>
        <Summary>
            <Employee_ID>32451854</Employee_ID>
            <Name>Felix (32451854)</Name>
            <Type>Employee</Type>
        </Summary>
    </Worker>
    <Worker>
        <Summary>
            <Employee_ID>23471732</Employee_ID>
            <Name>David (23471732)</Name>
            <Type>Contingent</Type>
        </Summary>
    </Worker>
    <Worker>
        <Summary>
            <Employee_ID>38741297</Employee_ID>
            <Name>Sam Daniel (38741297)</Name>
            <Type>Employee</Type>
        </Summary>
    </Worker>
</Workers>

I have written below XSLT. Not sure how to add conditions in below XSLT to remove nodes contain duplicate employee id where in type is 'Contingent'

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ws="urn:com.workday/workersync">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="/Workers/Worker[Summary/Type='Contingent']"/>
</xsl:stylesheet>

Above XSLT removes all Type which has value as 'Contingent'. But, what I need is remove nodes which has Type as Contingent only when 'Employee id' has duplicate entries in the XML?

Consider using a key to look up Worker elements by their Employee_ID

<xsl:key name="Worker" match="Worker" use="Summary/Employee_ID" />

This then means you can write your template match to remove Worker elements as so:

<xsl:template match="Worker[Summary/Type='Contingent'][count(key('Worker', Summary/Employee_ID)) > 1]"/>

Or maybe like so (ie Check there is a second Worker with the same Employee_ID

<xsl:template match="Worker[Summary/Type='Contingent'][key('Worker', Summary/Employee_ID)[2]]"/>

Try this XSLT

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ws="urn:com.workday/workersync">
    <xsl:output method="xml" indent="yes"/>

    <xsl:key name="Worker" match="Worker" use="Summary/Employee_ID" />

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

     <xsl:template match="Worker[Summary/Type='Contingent'][key('Worker', Summary/Employee_ID)[2]]"/>
</xsl:stylesheet>

Note, there is no need to match on the full /Workers/Worker path. You would only really need to do this in this case if there were Worker elements at different levels in your XML.

Add another predicate (here: [Summary/Employee_ID = preceding-sibling::Worker/Summary/Employee_ID or Summary/Employee_ID = following-sibling::Worker/Summary/Employee_ID] ) to your match expression for the dummy template.

The following template produces the desired output:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="/Workers/Worker[Summary/Type='Contingent'][Summary/Employee_ID = preceding-sibling::Worker/Summary/Employee_ID or Summary/Employee_ID = following-sibling::Worker/Summary/Employee_ID]"/>
</xsl:stylesheet>

If predicates are chained this way, all of them have to be fulfilled for a match, as in a logical AND.

In addition to adding the extra predicate, I also changed the XSLT version to 1.0 since the template uses no version 2.0 features. Additionally, I removed the unnecessary namespace declaration.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM