【问题标题】:XSL: Remove Parent node with duplicate childrenXSL:删除具有重复子节点的父节点
【发布时间】:2017-05-16 07:18:37
【问题描述】:

我有一个关于根据子节点删除父节点的问题。

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 中有不同的 &lt;Type&gt; 节点。 在这个节点中有节点&lt;Property&gt; 和子节点&lt;Title&gt;&lt;Value&gt;

对于每个&lt;Type&gt; 中的每个重复条目,我想删除整个&lt;Property&gt; 节点及其子节点&lt;Title&gt;&lt;Value&gt;

想要的输出应该是这样的:

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

我已经搜索了论坛,但找不到合适的解决方案。提前感谢您的帮助!

【问题讨论】:

  • 请选择 XSLT 1.0 或 XSLT 2.0 - 不能同时选择。要删除重复项,请搜索 grouping - 这可能是这里最常被问到的 XSLT 问题。

标签: xml xslt xslt-1.0 xslt-2.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>

它使用一种称为“Muenchian 分组”的技术,该技术使用key 函数在 XMl 上查找特定条件的匹配项,然后检查当前上下文是否与第一个匹配项相同,以忽略重复项。相等检查使用generate-id 函数;每个 XML 元素都有一个在运行时显式或隐式生成的 id 属性,用于唯一标识它。

在我们的例子中,键匹配&lt;Property&gt; 元素并为它们建立索引。因为我们要删除 &lt;PropertyList&gt; 中的重复项,而不是整个 XML,所以键使用“索引”:父 &lt;PropertyList&gt; 的(生成的)if、&lt;Title&gt; 元素值、@ 的串联987654328@ 符号和&lt;Value&gt; 元素值。这就是这部分的作用:

<xsl:key name="property" match="Property" use="concat(generate-id(parent::*), Title, '|', Value)" />

匹配&lt;PropertyList&gt;的模板然后递归应用模板,但仅适用于该谓词所在的&lt;Property&gt;元素:[generate-id(.) = generate-id(key('property', concat(generate-id(parent::*), Title, '|', Value))[1])]

让我们分解一下。 generate-id(.) 为当前节点(属性元素)生成一个 id。然后它会检查该 id 是否与为此生成的相同:key('property', concat(generate-id(parent::*), Title, '|', Value))[1]

这表示“键名为属性,用于匹配父级(我们的 PropertyList)生成的 id、标题、| 和值的串联”,然后仅采用匹配节点集的第一个元素。

请注意,您是这样说的:

如您所见,此示例 TXT 和 PDF 中有不同的节点。在此节点内有节点和子节点以及 .

我假设每种类型(TXT、PDF、...)在给定的 &lt;DatasetList&gt; 中只出现一次,并且您希望删除 PropertyList 的本地重复项。如果类型可以重复,并且您想在整个类型中删除重复项,则必须将 Muenchian 分组提升到另一个级别(包括类型)。但我认为上述解决方案是您的目标。

此外,如果 Title 和 Value 元素可能包含 | 符号,这可能会失败。在这种情况下,您可以选择不同的分隔符。

如果您可以使用 XSLT 2,这将变得更加简单,因为它内置了分组功能。在这种情况下,请在您的问题中指定,我可以提出新的答案。

【讨论】:

  • 非常感谢您的解释!我尝试了您的方法,到目前为止它仍然有效,只是它删除了标签&lt;PropertyList&gt;&lt;PropertyList/&gt;。如何将这些元素保留在文件中?编辑:刚刚添加了标签!谢谢!
  • @M4rk0444 哎呀,你是对的。该模板与 PropertyList 匹配,但随后直接处理 Property 元素而不复制当前节点。我现在将编辑 XSLT 来解决这个问题。
  • 谢谢!这对我帮助很大!
猜你喜欢
  • 2013-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-03
  • 2021-06-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多