我有一个关于根据子节点删除父节点的问题。
XML文件具有以下结构:
<PlmXmlData xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:plm="http://www.plmxml.org/Schemas/PLMXMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:an="">
<ItemList>
<Item>
<ID>1</ID>
<Group>Group1</Group>
<Projekt>Projekt1</Projekt>
<DatasetList>
<Dataset>
<Name>Name1</Name>
<Type>TXT</Type>
<Template>None</Template>
<RelativeFilePath>FilePath1</RelativeFilePath>
<PropertyList>
<Property>
<Title>item_name</Title>
<Value>ITEM_Name</Value>
</Property>
<Property>
<Title>item_name</Title>
<Value>ITEM_Name</Value>
</Property>
</PropertyList>
</Dataset>
<Dataset>
<Name>Name1</Name>
<Type>PDF</Type>
<Template>Template1</Template>
<RelativeFilePath>FilePath1/Name1.pdf</RelativeFilePath>
<PropertyList>
<Property>
<Title>item_name</Title>
<Value>CAR1</Value>
</Property>
<Property>
<Title>item_name</Title>
<Value>CAR1</Value>
</Property>
<Property>
<Title>item_name2</Title>
<Value>CAR2</Value>
</Property>
<Property>
<Title>item_name2</Title>
<Value>CAR2</Value>
</Property>
</PropertyList>
</Dataset>
</DatasetList>
</Item>
</ItemList>
</PlmXmlData>
正如您所看到的,此示例TXT和PDF中有不同的<Type>
个节点。
在此节点中,有节点<Property>
和子节点<Title>
和<Value>
。
我希望为每个<Property>
中的每个重复条目删除整个<Title>
节点及其子节点<Value>
和<Type>
。
所需的输出应该是这样的:
<PlmXmlData xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:plm="http://www.plmxml.org/Schemas/PLMXMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:an="">
<ItemList>
<Item>
<ID>1</ID>
<Group>Group1</Group>
<Projekt>Projekt1</Projekt>
<DatasetList>
<Dataset>
<Name>Name1</Name>
<Type>TXT</Type>
<Template>None</Template>
<RelativeFilePath>FilePath1</RelativeFilePath>
<PropertyList>
<Property>
<Title>item_name</Title>
<Value>ITEM_Name</Value>
</Property>
</PropertyList>
</Dataset>
<Dataset>
<Name>Name1</Name>
<Type>PDF</Type>
<Template>Template1</Template>
<RelativeFilePath>FilePath1/Name1.pdf</RelativeFilePath>
<PropertyList>
<Property>
<Title>item_name</Title>
<Value>CAR1</Value>
</Property>
<Property>
<Title>item_name2</Title>
<Value>CAR2</Value>
</Property>
</PropertyList>
</Dataset>
</DatasetList>
</Item>
</ItemList>
我搜索了论坛,但无法找到合适的解决方案。感谢您的帮助!
答案 0 :(得分:1)
这是XSLT 1.0中的解决方案。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="property" match="Property" use="concat(generate-id(parent::*), Title, '|', Value)" />
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="PropertyList">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="Property[generate-id(.) = generate-id(key('property', concat(generate-id(parent::*), Title, '|', Value))[1])]" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
它使用一种称为&#34; Muenchian分组&#34;的技术,它使用key
函数在特定条件下查找XMl上的匹配,然后检查当前上下文是否与第一个相同匹配,忽略重复。等式检查使用generate-id
函数;每个XML元素都有一个id属性,在运行时显式或隐式生成,唯一标识它。
在我们的例子中,密钥匹配<Property>
个元素并对它们编制索引。因为我们要删除<PropertyList>
内的重复项而不是整个XML中的重复项,所以密钥使用&#34;索引&#34;:父项<PropertyList>
的(生成的)if的串联, <Title>
元素值,|
符号和<Value>
元素值。这就是这一部分的作用:
<xsl:key name="property" match="Property" use="concat(generate-id(parent::*), Title, '|', Value)" />
匹配<PropertyList>
的模板然后以递归方式应用模板,但仅适用于此谓词所在的<Property>
元素:[generate-id(.) = generate-id(key('property', concat(generate-id(parent::*), Title, '|', Value))[1])]
让我们打破这种局面。 generate-id(.)
为当前节点(Property元素)生成一个id。然后检查该id是否与为此生成的id相同:key('property', concat(generate-id(parent::*), Title, '|', Value))[1]
对于父级(我们的PropertyList),Title,|
和Value&#34的生成id的串联的匹配,它说&#34;密钥命名属性;然后只获取匹配节点集的第一个元素。
请注意,你这样说:
如您所见,此示例TXT和PDF中有不同的节点。在这个节点内有节点和子节点。
我假设每种类型(TXT,PDF,...)在给定的<DatasetList>
中只出现一次,并且您想删除PropertyList
本地的重复项。如果类型可以重复并且您想要删除整个类型的重复项,则必须将Muenchian分组转到另一个级别(包括类型)。但我认为上述解决方案正是您的目标。
此外,如果Title和Value元素可能包含|
个符号,则可能会失败。在这种情况下,您可以选择不同的分隔符。
如果你可以使用XSLT 2,这会变得更加简单,因为它内置了分组。在这种情况下,请在你的问题中指定,我可以做出新的答案。