如何根据条件从XML中删除节点?

时间:2014-09-26 20:24:37

标签: xml xslt xslt-1.0

我需要根据条件从下面的XML中删除重复的节点。有人可以帮我修一下我写的XSLT吗?或建议一个解决方法?

我的要求:如果满足以下条件,则删除整个节点。

  1. 如果员工ID有重复的条目
  2. 如果上述条件为“true”,请保留“工作人员”节点,其中“类型”为“员工”。具有相同员工ID的其他重复“worker”节点条目将“Type”作为“Contingent”。
  3. XML文件:

     <?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>
    

    上面的XML需要转换如下。

    <?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>
    

    我在XSLT下面写过。不确定如何在XSLT下面添加条件以删除包含重复员工ID的节点,其中类型为'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>
    

    在XSLT之上删除所有值为'Contingent'的Type。但是,我需要的是只有当'Employee id'在XML中有重复的条目时才删除具有Type为Contingent的节点?

2 个答案:

答案 0 :(得分:3)

考虑使用密钥按Worker

查找Employee_ID个元素
<xsl:key name="Worker" match="Worker" use="Summary/Employee_ID" />

这意味着您可以编写模板匹配以删除Worker元素,如下所示:

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

或者可能是这样(即检查第二个Worker具有相同的Employee_ID

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

试试这个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>

注意,无需在完整的/Workers/Worker路径上进行匹配。如果XML中的不同级别有Worker个元素,那么在这种情况下你真的只需要这样做。

答案 1 :(得分:1)

将另一个谓词(此处为:[Summary/Employee_ID = preceding-sibling::Worker/Summary/Employee_ID or Summary/Employee_ID = following-sibling::Worker/Summary/Employee_ID])添加到虚拟模板的匹配表达式中。

以下模板生成所需的输出:

<?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>

如果谓词是以这种方式链接的,那么所有必须满足匹配,就像在逻辑AND中一样。

除了添加额外的谓词之外,我还将XSLT版本更改为1.0,因为模板不使用版本2.0功能。另外,我删除了不必要的名称空间声明。