给定XPath,从XPathNodeIterator中删除/删除节点

时间:2010-03-26 16:38:20

标签: c# xml xslt

首先,如果有人对问题有不同的,可能更短(或更好)的解决方案,那么也欢迎。


我试图“简单地”删除(几乎)XSLT中的重复元素。有一些(元数据)节点我不想在比较时包含,我无法弄清楚如何在XSLT中做到这一点,所以我想用扩展这些节点的函数扩展它。像这样:

<xsl:for-each select="abx:removeNodes(d/df600|d/df610|d/df611|d/df630|d/df650|d/df651|d/df655, '*[@key=&quot;i1&quot; or @key=&quot;i2&quot; or key=&quot;db&quot;]')">
   <xsl:if test="not(node()=preceding-sibling::*)">
      blah
   </xsl:if>
</xsl:for-each>

扩展,但效果不好......(C#)

public XPathNodeIterator removeNodes(XPathNodeIterator p_NodeIterator, String removeXPath)
{
   Logger Logger = new Logger("xslt");
   Logger.Log("removeNodes(removeXPath={0}):", removeXPath);

   foreach (XPathNavigator CurrentNode in p_NodeIterator)
   {
      Logger.Log("removeNodes(): CurrentNode.OuterXml={0}.", CurrentNode.OuterXml);

      foreach (XPathNavigator CurrentSubNode in CurrentNode.Select(removeXPath))
      {
         Logger.Log("removeNodes(): CurrentSubNode.OuterXml={0}.", CurrentSubNode.OuterXml);
         // How do i delete this node!?
         //CurrentSubNode.DeleteSelf();
      }
   }

   return p_NodeIterator;
}

我使用'CurrentSubNode.DeleteSelf();'的初始方法不起作用,因为它混淆并丢失其在XPathNavigator中的位置,导致它只删除它使用“removeXPath”找到的第一个项目。像DeleteAndMoveNext()这样的东西会很好但似乎没有这样的方法...


示例数据:

<df650>
  <df650 key="i1"> </df650>
  <df650 key="i2">0</df650>
  <df650 key="a">foo</df650>
  <df650 key="x">bar</df650>
  <df650 key="db">someDB</df650>
  <df650 key="id">b2</df650>
  <df650 key="dsname">someDS</df650>
</df650>

..然后是另一个相同的节点(如果忽略元字段; db,id,dsname)。

<df650>
  <df650 key="i1"> </df650>
  <df650 key="i2">0</df650>
  <df650 key="a">foo</df650>
  <df650 key="x">bar</df650>
  <df650 key="db">someOtherDB</df650>
  <df650 key="id">b2</df650>
  <df650 key="dsname">someOtherDS</df650>
</df650>

结果应该是......

<df650>
  <df650 key="i1"> </df650>
  <df650 key="i2">0</df650>
  <df650 key="a">foo</df650>
  <df650 key="x">bar</df650>
</df650>

3 个答案:

答案 0 :(得分:1)

您可以轻松地在XSLT中单独执行此操作,实际上不需要扩展功能。考虑一下:

<!-- make a template that matches all nodes that cold be removed -->
<xsl:template match="d/df600|d/df610|d/df611|d/df630|d/df650|d/df651|d/df655">
  <!-- check the your condition for node removal, whatever it may be -->
  <xsl:if test="not(@key='i1' or @key='i2' or @key='db')">
    <!-- ...if it is *not* met, copy the node -->
    <xsl:copy-of select="." />
  </xsl:if>
  <!-- ...in all other cases, nothing happens, i.e. the node is removed -->
</xsl:template>

答案 1 :(得分:1)

感谢RymdPung的提示,我可以使用您的列表建议删除重复部分中的空白行。

我在代码中添加了对System.Collections.Generic命名空间的引用。

这是我创建的用于扫描一组节点,识别要删除的节点,然后在单独的循环中删除它们的方法。

         private void deleteEmptyRows(string path)
    {
        XPathNodeIterator nodesToCheck = MainDataSource.CreateNavigator().Select(path, NamespaceManager);
        List<XPathNavigator> nodesToDelete = new List<XPathNavigator>();
        foreach (XPathNavigator currentItem in nodesToCheck)
            if (currentItem.Value.Trim().Length == 0)
                nodesToDelete.Add(currentItem);

        foreach(XPathNavigator deleteMe in nodesToDelete)
            deleteMe.DeleteSelf();
    }

答案 2 :(得分:0)

问题可以像这样解决(但是,它并没有解决我的实际问题......)。

  • 创建一个类型为XPathNavigator的列表,其中包含您要删除的节点。
  • 将节点添加到此列表中,而不是使用DeleteSelf()。
  • 完成查找要删除的所有节点后,遍历列表并删除节点。由于这些节点是导航器,因此丢失位置没有问题。

我放弃了尝试在10分钟后粘贴代码......