代码之家  ›  专栏  ›  技术社区  ›  Hannes

给定xpath,从xpathnodeiterator中删除/移除节点

  •  0
  • Hannes  · 技术社区  · 15 年前

    首先,如果有人对这个问题有不同的,也许更短(或更好)的解决方案,那也很受欢迎。


    我试图“简单地”删除(几乎)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>
    

    …然后是另一个相同的节点(如果忽略meta字段: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 回复  |  直到 15 年前
        1
  •  1
  •   Tomalak    15 年前

    仅在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>
    
        2
  •  1
  •   Ivan Wilson    15 年前

    感谢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();
        }
    
        3
  •  0
  •   Hannes    15 年前

    这个问题可以这样解决(但是,它不能解决我的实际问题…)。

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

    我放弃了在10分钟后粘贴代码…