2012-06-21 4 views
4

je dois extraire (XSLT, XPath, XQuery ... De préférence XPath) les plus profondément imbriqué élément noeuds avec méthode (DEST id = méthode "Russie" = "supprimer" />) et son ancêtre direct (SOURCE id = "AFRICA" method = "modify">).comment obtenir les nœuds les plus profondément imbriqués en utilisant xpath? (Mise en œuvre avec XMLTWIG)

Je ne veux pas obtenir les nœuds supérieurs avec des méthodes (méthode principale = "modifier"> ou méthode principale = "modifier">).

Les éléments imbriqués les plus profonds avec méthode correspondent à des actions réelles. Les éléments supérieurs avec méthode sont en réalité des actions factices qui ne doivent pas être prises en compte.

Voici mon exemple de fichier XML:

<?xml version="1.0" encoding="UTF-8"?> 
<main method="modify"> 
<MACHINE method="modify"> 
    <SOURCE id="AFRICA" method="modify"> 
    <DEST id="RUSSIA" method="delete"/> 
    <DEST id="USA" method="modify"/> 
    </SOURCE> 

    <SOURCE id="USA" method="modify"> 
    <DEST id="AUSTRALIA" method="modify"/> 
    <DEST id="CANADA" method="create"/> 
    </SOURCE> 
</MACHINE> 
</main> 

C'est sortie Xpath Je me attends:

<SOURCE id="AFRICA" method="modify"><DEST id="RUSSIA" method="delete"/> 

<SOURCE id="AFRICA" method="modify"><DEST id="USA" method="modify"/> 

<SOURCE id="USA" method="modify"><DEST id="AUSTRALIA" method="modify"/> 

<SOURCE id="USA" method="modify"><DEST id="CANADA" method="create"/> 

Ma commande actuelle XPath ne fournit pas le résultat adéquat.

Commande XPath ("// [Méthode @]/ancêtre :: *") qui revient:

<main><MACHINE method="modify">          # NOT WANTED 

<MACHINE method="modify"><SOURCE id="AFRICA" method="modify">   # NOT WANTED 

<MACHINE method="modify"><SOURCE id="USA" method="modify">    # NOT WANTED 

<SOURCE id="AFRICA" method="modify"><DEST id="RUSSIA" method="delete"/> 

<SOURCE id="AFRICA" method="modify"><DEST id="USA" method="modify"/> 

<SOURCE id="USA" method="modify"><DEST id="AUSTRALIA" method="modify"/> 

<SOURCE id="USA" method="modify"><DEST id="CANADA" method="create"/> 

Mon code xmltwig pour plus d'informations (contexte):

#!/usr/bin/perl -w 
use warnings; 
use XML::Twig; 
use XML::XPath; 

@my $t= XML::Twig->new; 
my $v= XML::Twig::Elt->new; 
$t-> parsefile ('input.xml'); 

@abc=$t->get_xpath("\/\/[\@method]\/ancestor\:\:\*") ; 
foreach $v (@abc) # outer 1 
{ 
    foreach $v ($v ->children) # internal 1 
    { 
     $w=$v->parent; 
     print $w->start_tag; 
     print $v->start_tag; 
    } 
    } 
+0

Nous avons besoin XSLT si vous voulez manipuler les nœuds afin XPath seul peut Ne retirez pas les ancêtres que vous ne voulez pas. Considérons ensuite de poster des échantillons bien formés d'entrée et de sortie, donc pour l'échantillon d'entrée manque au moins une étiquette de fermeture et le résultat souhaité n'est pas bien formé, il n'est pas clair si vous voulez que l'élément 'SOURCE' contienne les éléments 'DEST' ou si vous voulez aplatir la hiérarchie existante et afficher tous les éléments au même niveau. –

+0

J'ai corrigé/mis à jour ma question. Le fichier de sortie est le résultat de ma commande xpath '// [@ method]/ancestor :: *'. Faites moi savoir s'il est possible avec xpath de filtrer le noeud le plus éloigné avec la méthode (et d'inclure son ancêtre direct). Sinon possible (nous utilisons XSLT), je modifierai la question en ayant un fichier XML SORTIE – laurentngu

+1

Je pense que trouver les éléments les plus profondément imbriqués n'est pas possible avec XPath parce que XPath ne dispose pas d'une fonction 'actuelle()'. Sinon, la solution serait de sélectionner tous les éléments pour lesquels il n'y a pas d'autres éléments avec un plus grand nombre d'ancêtres. En utilisant XSLT, cela peut être exprimé. –

Répondre

3

Les nœuds avec une profondeur maximale peut être trouvée avec

//*[count(ancestor::*) = max(//*/count(ancestor::*))] 

mais il pourrait effectuer horriblement, selon la façon intelligente votre optimiseur est.

Ayant trouvé ces nœuds, il est bien sûr trivial de trouver leurs ancêtres. Mais vous recherchez une sortie avec plus de structure que XPath seule peut fournir.

0

Le stylesheet

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:output indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="/"> 
    <xsl:apply-templates 
    select="//DEST[@method and not(node())]"/> 
</xsl:template> 

<xsl:template match="@* | node()"> 
    <xsl:copy> 
    <xsl:apply-templates select="@* , node()"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="DEST[@method and not(node())]"> 
    <xsl:apply-templates select=".."> 
    <xsl:with-param name="leaf" select="current()"/> 
    </xsl:apply-templates> 
</xsl:template> 

<xsl:template match="*[DEST[@method and not(node())]]"> 
    <xsl:param name="leaf"/> 
    <xsl:copy> 
    <xsl:copy-of select="@* , $leaf"/> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 

transforme

<?xml version="1.0" encoding="UTF-8"?> 
<main method="modify"> 
<MACHINE method="modify"> 
    <SOURCE id="AFRICA" method="modify"> 
    <DEST id="RUSSIA" method="delete"/> 
    <DEST id="USA" method="modify"/> 
    </SOURCE> 

    <SOURCE id="USA" method="modify"> 
    <DEST id="AUSTRALIA" method="modify"/> 
    <DEST id="CANADA" method="create"/> 
    </SOURCE> 
</MACHINE> 
</main> 

dans

<SOURCE id="AFRICA" method="modify"> 
    <DEST id="RUSSIA" method="delete"/> 
</SOURCE> 
<SOURCE id="AFRICA" method="modify"> 
    <DEST id="USA" method="modify"/> 
</SOURCE> 
<SOURCE id="USA" method="modify"> 
    <DEST id="AUSTRALIA" method="modify"/> 
</SOURCE> 
<SOURCE id="USA" method="modify"> 
    <DEST id="CANADA" method="create"/> 
</SOURCE> 
+0

La question ressemble plus à laurentgnu veut trouver les éléments les plus profondément imbriqués dans un document XML. –

+0

Oui J'ai besoin de Xpath pour montrer les éléments les plus profondément imbriqués et leur ancêtre direct. En tout cas merci @Martin pour cette solution XLST.Mais en fait, j'ai besoin d'utiliser une commande xpath ** si possible **. Voici le code xmltwig que j'utilise: '@ abc = $ t-> get_xpath (" \/\/[\ @ méthode] \/ancêtre \: \: \ * "); foreach mon $ v (@abc) '{# blabla} – laurentngu

+0

Eh bien, vous semblez vouloir réorganiser les nœuds en éliminant les ancêtres et en mappant chaque feuille à son parent, du moins c'est ce que je vois dans votre résultat affiché. Comme XPath ne vous permet pas de manipuler des nœuds mais de sélectionner des nœuds dans un document existant, je pense que vous avez besoin de plus de XPath. L'exemple de votre commentaire suggère que vous voulez utiliser un langage hôte impératif et XPath mais je ne reconnais pas cette langue, donc je ne peux pas vous aider avec ça. Étiquetez votre question avec cette langue (par exemple, Python, PHP), expliquez quelle API XPath vous utilisez, puis les personnes ayant de l'expérience dans ce domaine peuvent vous aider. –

1

Comme je l'ai mentionné dans mon commentaire sur la question, je ne pense pas que ce soit possible avec XPath pur comme XPath n'a rien comme une fonction current() qui permettrait de se référer au contexte en dehors d'une restriction [].

La solution la plus similaire devrait être cette XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ZD="http://xyz.abc"> 
    <xsl:output method="text"/> 

    <xsl:template match="//*"> 
     <xsl:choose> 
      <xsl:when test="not(//*[count(ancestor::node()) > count(current()/ancestor::node())])"><xsl:value-of select="local-name(.)"/><xsl:text> 
</xsl:text></xsl:when> 
      <xsl:otherwise> 
       <xsl:copy> 
        <xsl:apply-templates select="@*|node()"/> 
       </xsl:copy> 
      </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 

    <xsl:template match="text()|@*"/> 
</xsl:stylesheet> 

L'élément <xsl:when> trouve les éléments les plus profondément imbriquées. Par exemple, je produis les noms locaux des éléments trouvés, suivis d'une nouvelle ligne, mais bien sûr, vous pouvez afficher tout ce dont vous avez besoin.

Mise à jour: Notez que ceci est basé sur les connaissances/outils XPath 1.0. Il semble que c'est effectivement possible d'exprimer dans XPath 2.0.

0

Une telle expression de XPath2.0 est:

//*[not(*) 
    and 
    count(ancestor::*) 
    = 
    max(//*[not(*)]/count(ancestor::*)) 
    ] 
    /(self::node|..) 

Pour illustrer cela avec un exemple complet XSLT 2.0:

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 

    <xsl:variable name="vResult" select= 
    "//*[not(*) 
     and 
      count(ancestor::*) 
     = 
     max(//*[not(*)]/count(ancestor::*)) 
     ] 
      /(self::node|..) 
    "/> 

<xsl:template match="/"> 
    <xsl:sequence select="$vResult"/> 
</xsl:template> 
</xsl:stylesheet> 

Lorsque cette transformation est appliquée sur le XML fourni document:

<main method="modify"> 
    <MACHINE method="modify"> 
     <SOURCE id="AFRICA" method="modify"> 
      <DEST id="RUSSIA" method="delete"/> 
      <DEST id="USA" method="modify"/> 
     </SOURCE> 
     <SOURCE id="USA" method="modify"> 
      <DEST id="AUSTRALIA" method="modify"/> 
      <DEST id="CANADA" method="create"/> 
     </SOURCE> 
    </MACHINE> 
</main> 

l'expression XPath est évaluée et les éléments sélectionnés (les éléments en profondeur maximale et leurs parents) sont copiés à la sortie:

<SOURCE id="AFRICA" method="modify"> 
      <DEST id="RUSSIA" method="delete"/> 
      <DEST id="USA" method="modify"/> 
     </SOURCE> 
<SOURCE id="USA" method="modify"> 
      <DEST id="AUSTRALIA" method="modify"/> 
      <DEST id="CANADA" method="create"/> 
     </SOURCE> 
Questions connexes