2010-03-26 103 views
0

首先,如果某人有一個不同的,也許更短(或更好)的問題解決方案,那麼也是受歡迎的。從XPathNodeIterator中刪除/刪除節點(給定XPath)


我想「簡單地」刪除(幾乎)在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> 

回答

0

問題可以像這樣解決(但是,它不能解決我的實際問題...)。

  • 創建一個XPathNavigator類型列表,其中將包含要刪除的節點。
  • 將節點添加到此列表中而不是使用DeleteSelf()。
  • 完成查找所有要刪除的節點後,遍歷列表並刪除節點。由於這些節點是導航器,所以丟失位置沒有問題。

我放棄了試圖將代碼粘貼在10分鐘後...

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

啊,謝謝!我的數據看起來有點不同,這使得它有點棘手。節點看起來像d/df600/df600/@ i1 etc ..此外,我仍然想在調試模式下,在'調試記錄視圖'中的'正常記錄視圖'下輸出這些節點,也許我可以使用@模式屬性呢? – Hannes 2010-03-30 07:58:14

+0

@RymdPung:你可以聲明一個'',這樣你就可以從外部修改行爲。在適當的地方放一個'「。如果您無法根據需要調整我的代碼,請顯示您的輸入XML並指定在什麼情況下它應該看起來像什麼。 – Tomalak 2010-03-30 09:30:27

+0

這些數據是經過修改的(不要問我爲什麼)MarcXML格式版本(http://www.loc.gov/standards/marcxml/)。我無法在評論中發佈長消息,因此我使用數據示例編輯了原始消息。 這兩個視圖的輸出是非常不同的,所以我認爲使用XSLT的@mode來分割視圖有點乾淨。 – Hannes 2010-03-30 11:23:58

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(); 
    }