Régler la différence avec XPath 1.0 - comment puis-je obtenir .//table sans .//table//table?
-
20-09-2019 - |
Question
Je suis en train de trouver toutes les tables ci-dessous mon noeud courant sans inclure aussi les tables imbriquées. Autrement dit, si j'ai, je veux trouver « oui » et non « non »:
<table> <!-- outer table - no -->
<tr><td>
<div> <!-- *** context node *** -->
<table> <!-- yes -->
<tr><td>
<table> ... </table> <!-- no -->
</td></tr>
</table>
<table> <!-- yes -->
<tr><td>
<table> ... </table> <!-- no -->
</td></tr>
</table>
</div>
</td></tr>
</table>
Yat-il un moyen facile de le faire dans XPath 1.0? (En 2.0, il serait .//table except .//table//table
, mais je ne pas de 2.0 en option.)
EDIT: s'il vous plaît, les réponses à ce jour ne respectent pas l'idée du noeud contexte actuel. Je ne sais pas jusqu'à quel point sur la première couche de table peut être (et il peut être différent), et je aussi ne sais pas si je pourrais être dans une autre table (ou deux ou trois).
Littéralement, je veux ce .//table except .//table//table
dans XPath 2.0 serait, mais je ne XPath 1.
La solution 5
Après avoir étudié ici et ailleurs, la réponse semble être « vous ne pouvez pas, et c'est la raison pour laquelle nous avons XPath 2.0 ». Eh bien.
Autres conseils
Je pense que vous voulez enfant :: table de ping-alias
#!/usr/bin/perl --
use strict;
use warnings;
use HTML::TreeBuilder;
{
my $tree = HTML::TreeBuilder->new();
$tree->parse(<<'__HTML__');
<table> <!-- outer table - no -->
<tr><td>
<div> <!-- *** context node *** -->
<table> <!-- yes -->
<tr><td>
<table> ... </table> <!-- no -->
</td></tr>
</table>
<table> <!-- yes -->
<tr><td>
<table> ... </table> <!-- no -->
</td></tr>
</table>
</div>
</td></tr>
</table>
__HTML__
sub HTML::Element::addressx {
return join(
'/',
'/', # // ROOT
reverse( # so it starts at the top
map {
my $n = $_->pindex() || '0';
my $t = $_->tag;
$t . '['. $n .']'
} # so that root's undef -> '0'
$_[0], # self and...
$_[0]->lineage
)
);
} ## end sub HTML::Element::addressx
for my $td ( $tree->look_down( _tag => qr/div|table/i ) ) {
print $td->addressx, "\n";
}
$tree->delete;
undef $tree;
}
__END__
//html[0]/body[1]/table[0]
//html[0]/body[1]/table[0]/tr[0]/td[0]/div[0]
//html[0]/body[1]/table[0]/tr[0]/td[0]/div[0]/table[0]
//html[0]/body[1]/table[0]/tr[0]/td[0]/div[0]/table[0]/tr[0]/td[0]/table[0]
//html[0]/body[1]/table[0]/tr[0]/td[0]/div[0]/table[1]
//html[0]/body[1]/table[0]/tr[0]/td[0]/div[0]/table[1]/tr[0]/td[0]/table[0]
et la seconde partie
#!/usr/bin/perl --
use strict;
use warnings;
use HTML::TreeBuilder::XPath;
my $tree = HTML::TreeBuilder::XPath->new;
$tree->parse_content(<<'__HTML__');
<table> <!-- outer table - no -->
<tr><td>
<div> <!-- *** context node *** -->
<table> <!-- yes -->
<tr><td>
<table> ... </table> <!-- no -->
</td></tr>
</table>
<table> <!-- yes -->
<tr><td>
<table> ... </table> <!-- no -->
</td></tr>
</table>
</div>
</td></tr>
</table>
__HTML__
#~ for my $result ($tree->findnodes(q{//html[0]/body[1]/table[0]/tr[0]/td[0]/div[0]})) {
for my $result ($tree->findnodes(q{/html/body/table/tr/td/div})) {
print $result->as_HTML,"\n\n";
for my $table( $result->findnodes(q{table}) ){ ## child::table
print "$table\n";
print $table->as_HTML,"\n\n\n";
}
}
__END__
<div><table><tr><td><table><tr><td> ... </td></tr></table></td></tr></table><table><tr><td><table><tr><td> ... </td></tr></table></td></tr></table></div>
HTML::Element=HASH(0xc6c964)
<table><tr><td><table><tr><td> ... </td></tr></table></td></tr></table>
HTML::Element=HASH(0xc6cbf4)
<table><tr><td><table><tr><td> ... </td></tr></table></td></tr></table>
Eh bien, si je comprends bien, le content_list peut résoudre:
my $table_one = $tree->findnodes('/html//table')->[1];
for ( $table_one->content_list ) {
last if $_->exists('table');
print $_->as_text;
}
:)
Qu'en est-il .//table[not(.//table)]
? Désolé pour être bref, je suis sur mon téléphone.
Je ne sais pas comment obtenir le nœud de contexte à évaluer dans les prédicats imbriquées, mais ce que vous avez besoin est quelque chose comme ceci:
descendant::table[not(ancestor::table[ancestor::div])]
uniquement avec la possibilité de référencer le nœud de contexte, au lieu de div
EDIT : Si vous définissez une variable pour le noeud contextuel,
<xsl:variable name="contextNode" select="." />
vous pouvez référencer dans le prédicat XPath:
descendant::table[not(ancestor::table[ancestor::*[generate-id(.)=generate-id($contextNode)]])]