ضبط الفرق مع XPath 1.0 - كيف يمكنني الحصول على .//table بدون .//table//table؟
-
20-09-2019 - |
سؤال
أحاول العثور على جميع الطاولات أسفل العقدة الحالية الخاصة بي دون تضمين الجداول المتداخلة. بمعنى آخر ، إذا كان لدي هذا ، أريد أن أجد "نعم" وليس "لا":
<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>
هل هناك أي طريقة سهلة للقيام بذلك في XPath 1.0؟ (في 2.0 ، سيكون ذلك .//table except .//table//table
, ، لكن ليس لدي 2.0 كخيار.)
تعديل: من فضلك ، لا تحترم الإجابات حتى الآن فكرة عقدة السياق الحالية. لا أعرف إلى أي مدى قد تكون الطبقة الأولى من الجدول (وقد تختلف) ، وأنا أيضًا لا أعرف ما إذا كنت قد أكون داخل جدول آخر (أو اثنين أو ثلاثة).
حرفيا ، أريد ماذا .//table except .//table//table
في XPath 2.0 سيكون ، ولكن لدي فقط XPath 1.
المحلول 5
بعد التحقيق فيه هنا وأماكن أخرى ، يبدو أن الإجابة هي "لا يمكنك ذلك ، ولهذا السبب لدينا XPath 2.0". اوه حسناً.
نصائح أخرى
أعتقد أنك تريد الطفل :: الجدول الملقب الجدول
#!/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]
والجزء الثاني
#!/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>
حسنًا ، إذا فهمت ذلك ، يمكن لـ Content_List حل:
my $table_one = $tree->findnodes('/html//table')->[1];
for ( $table_one->content_list ) {
last if $_->exists('table');
print $_->as_text;
}
:)
ماذا عن .//table[not(.//table)]
؟ آسف على الإيجاز ، أنا على هاتفي.
لا أعرف كيف أحصل على عقدة السياق لتقييمها في المتنبئين المتداخلين ، ولكن ما تحتاجه هو شيء من هذا القبيل:
descendant::table[not(ancestor::table[ancestor::div])]
فقط مع القدرة على الرجوع إلى عقدة السياق ، بدلاً من div
تعديل: إذا قمت بتعيين متغير لعقدة السياق ،
<xsl:variable name="contextNode" select="." />
ثم يمكنك الرجوع إليه في مسند XPath:
descendant::table[not(ancestor::table[ancestor::*[generate-id(.)=generate-id($contextNode)]])]