2010-03-26 4 views
0

Tout d'abord, si quelqu'un a une solution différente, peut-être plus courte (ou meilleure), le problème est également le bienvenu. J'essaie de "simplement" supprimer (presque) les éléments en double dans XSLT. Il y a quelques nœuds (métadonnées) que je ne veux pas inclure lors de la comparaison, et je ne pouvais pas comprendre comment faire cela dans XSLT alors je pensais l'étendre avec une fonction supprimant ces nœuds. Comme si:Supprimer/Supprimer un nœud de XPathNodeIterator, avec un XPath

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

Et l'extension, qui ne fonctionne pas si bien ... (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; 
} 

Mon approche initiale à l'aide 'CurrentSubNode.DeleteSelf();' ne fonctionne pas car il devient confus et perd sa position dans XPathNavigator, provoquant la suppression du premier élément trouvé à l'aide de "removeXPath". Quelque chose comme un DeleteAndMoveNext() serait bien, mais il semble y avoir aucune méthode ...


données Exemple:

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

..et puis un autre nœud identique (si vous ignorez la méta champs, db, id, nom_d).

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

Le résultat devrait être ...

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

Répondre

0

Le problème peut être résolu comme celui-ci (cependant, il ne résout pas mon problème réel ...).

  • Créer une liste de type XPathNavigator qui contiendra les nœuds que vous souhaitez supprimer.
  • Ajoutez les noeuds à cette liste au lieu d'utiliser DeleteSelf().
  • Lorsque vous avez trouvé tous les nœuds que vous souhaitez supprimer, passez en revue votre liste et supprimez les nœuds. Puisque ces nœuds sont des navigateurs, il n'y a aucun problème avec la position perdue.

J'ai renoncé à essayer de coller le code après 10 minutes ...

1

Vous pouvez le faire dans XSLT seul facilement, une fonction d'extension vraiment pas nécessaire. Considérez ceci:

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

Ah, merci! Mes données semblent un peu différentes, ce qui les rend un peu plus compliquées. Les nœuds ressemblent à d/df600/df600/@ i1 etc .. Aussi, je voudrais encore sortir ces nœuds sous la 'vue d'enregistrement normale' dans une 'vue de débogage' en mode débogage, peut-être que je peux utiliser le @ attribut de mode pour cela? – Hannes

+0

@RymdPung: Vous pouvez déclarer un débogage '', ce qui vous permet de modifier le comportement de l'extérieur. Il suffit de laisser tomber un '' le cas échéant. Si vous avez du mal à adapter mon code à vos besoins, montrez votre code XML d'entrée et spécifiez à quoi cela devrait ressembler dans quelles circonstances. – Tomalak

+0

Les données sont dans une version modifiée (ne me demandez pas pourquoi) du format MarcXML (http://www.loc.gov/standards/marcxml/). Je ne peux pas poster de longs messages dans le commentaire, j'ai donc modifié mon message original avec des exemples de données. La sortie des deux vues est très différente, donc je pense que l'utilisation de @mode de XSLT pour diviser les vues est un peu plus propre. – Hannes

1

Merci pour l'indice RymdPung, j'ai pu supprimer des lignes vides dans une section répétitive à l'aide de votre suggestion de liste.

J'ai ajouté une référence à l'espace de noms System.Collections.Generic dans mon code.

Voici la méthode que j'ai créée pour analyser un ensemble de noeuds, identifier ceux que je veux supprimer, puis les supprimer dans une boucle séparée.

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