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

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

问题描述:

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

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

  1. 如果雇员ID具有重复条目
  2. 如果上述条件是“真”,保持工作节点其中“类型”是“雇员”。其他具有相同员工ID的重复“工人”节点条目将具有'类型'作为'或然'。

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其中的类型是“权变”

<?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删除所有类型的具有价值的“或有”。但是,我需要的是只有当'Employee id'在XML中有重复条目时才删除Type为Contingent的节点?

将另一个谓词(在这里:[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> 

如果谓词是链接这种方式,个个中必须满足的比赛,如在逻辑与。

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

考虑使用一个密钥由他们Employee_ID

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

查找Worker元素这就意味着你可以写你的模板匹配去除Worker元素像这样:

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

或者,也许像这样(即检查是否有第二个WorkerEmployee_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元素,则只需在此情况下执行此操作。

+0

在处理大量输入数据时,此解决方案比我的解决方案更快。最重要的是它更易于阅读。 – Burkart 2014-09-26 21:56:46