如何根据条件从 XML 中删除节点?
Posted
技术标签:
【中文标题】如何根据条件从 XML 中删除节点?【英文标题】:How to remove nodes from XML based on conditions? 【发布时间】:2014-11-21 22:45:43 【问题描述】:我需要根据条件从下面的 XML 中删除重复节点。有人可以帮我修复我写的 XSLT 吗?或者建议一个解决方法?
我的要求:如果满足以下条件,则删除整个节点。
-
如果员工 ID 有重复条目
如果上述条件为“真”,则保留“类型”为“员工”的 Worker 节点。其他具有相同员工 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 的节点,其中类型为“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 之上删除所有具有“条件”值的类型。但是,我需要的是仅当“Employee id”在 XML 中有重复条目时才删除类型为 Contingent 的节点?
【问题讨论】:
【参考方案1】:考虑使用键通过Employee_ID
查找Worker
元素
<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
元素时,您才真正需要这样做。
【讨论】:
这个解决方案在处理大输入数据时比我的要快。最重要的是,它更易于阅读。【参考方案2】:在虚拟模板的匹配表达式中添加另一个谓词(此处为:[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 版本的功能。此外,我删除了不必要的命名空间声明。
【讨论】:
以上是关于如何根据条件从 XML 中删除节点?的主要内容,如果未能解决你的问题,请参考以下文章