这个问题已被重新定义.我正在使用CPAN Perl模块WWW :: Mechanize来浏览网站,使用HTML :: TreeBuilder-XPath来捕获内容,使用xacobeo来测试HTML/XML上的XPath代码.目标是从基于PHP的网站调用此Perl脚本,并将已删除的内容上载到数据库中.因此,如果内容"缺失",仍然需要考虑.
下面是一个经过测试的简化示例代码,描述了我的挑战.注意:
ITEMS不同商店的各种输出; Products*每个商店都有不同数量的商品.这些产品清单可能有也可能没有下面的逐项表.下面,示例xml每个商店更改(如上所述),但为了简洁起见,我只显示一个"类型"的输出.我意识到所有数据都可以捕获到一个数组中,然后使用正则表达式来解密内容,以便将其上传到数据库中.我正在寻求更好的XPath知识,以帮助简化此(和未来)解决方案.
<!DOCTYPE XHTML>
<table id="8jd9c_ITEMS">
<tr><th style="color:red">The Products we have in stock!</th></tr>
<tr><td><span id="Product_NUTS">We have nuts!</span></td></tr>
<tr><td>
<!--Table may or may not exist -->
<table>
<tr><td style="color:blue;text-indent:10px">Almonds</td></tr>
<tr><td style="color:blue;text-indent:10px">Cashews</td></tr>
<tr></tr>
</table>
</td></tr>
<tr><td><span id="Product_VEGGIES">We have veggies!</span></td></tr>
<tr><td>
<!--Table may or may not exist -->
<table>
<tr><td style="color:blue;text-indent:10px">Carrots</td></tr>
<tr><td style="color:blue;text-indent:10px">Celery</td></tr>
<tr></tr>
</table>
</td></tr>
<tr><td><span id="Product_ALCOHOL">We have booze!</span></td></tr>
<!--In this case, the table does not exist -->
</table>
Run Code Online (Sandbox Code Playgroud)
XPath语句:
'//table[contains(@id, "ITEMS")]/tr[position() >1]/td/span/text()'
Run Code Online (Sandbox Code Playgroud)
会发现:
We have nuts!
we have veggies!
We have booze!
Run Code Online (Sandbox Code Playgroud)
和XPath声明:
'//table[contains(@id, "ITEMS")]/tr[position() >1]/td/table/tr/td/text()'
Run Code Online (Sandbox Code Playgroud)
会发现:
Almonds
Cashews
Carrots
Celery
Run Code Online (Sandbox Code Playgroud)
可以组合两个XPath语句:
'//table[contains(@id, "ITEMS")]/tr[position() >1]/td/span/text() | //table[contains(@id, "ITEMS")]/tr[position() >1]/table/tr/td/text()'
Run Code Online (Sandbox Code Playgroud)
找到:
We have nuts!
Almonds
Cashews
We have veggies!
Carrots
Celery
We have booze!
Run Code Online (Sandbox Code Playgroud)
同样,上面的数组可以使用正则表达式对其产品到列表关联进行解密(在实际代码中). 但是,可以使用XPath以保持该关联的方式构建阵列吗?
例如(伪说话,这不起作用):
'//table[contains(@id, "ITEMS")]/tr[position()>1]/td/span/text() |
if exists('//table[contains(@id, "ITEMS")]/tr[position() >1]/table))
then ("NoTable") else ("TableRef") |
Save this result into @TableRef ('//table[contains(@id, "ITEMS")]/tr[position() >1]/table/tr/td/text()')'
Run Code Online (Sandbox Code Playgroud)
在Perl中构建多维数组(在传统意义上)是不可能的,请参阅perldoc perlref 但是希望类似于上面的解决方案可以创建类似于:
@ITEMS[0] => We have nuts!
@ITEMS[1] => nutsREF <-- say, the last word of the span value + REF
@ITEMS[2] => We have veggies!
@ITEMS[3] => veggiesREF <-- say, the last word of the span value + REF
@ITEMS[4] => We have booze!
@ITEMS[5] => NoTable <-- value accounts for the missing info
@nutsREF[0] => Almonds
@nutsREF[1] => Cashews
@veggiesREF[0] => Carrots
@veggiesREF[1] => Celery
Run Code Online (Sandbox Code Playgroud)
在实际代码的产品是已知的,所以my @veggiesREF并my @nutsREF可以在XPath输出的预期来限定.
我意识到XPath if/else/then功能是在XPath 2.0版本中.我在ubuntu系统上并在本地工作,但我仍然不清楚我的apache2服务器是使用它还是1.0版本.我该如何检查?
最后,如果您可以展示如何从PHP表单提交调用Perl脚本以及如何将Perl数组传递回调用PHP函数,那么这将获得赏金.:)
谢谢!
最终编辑:
紧接在这篇文章下面的评论是针对一个过于模糊的初始帖子.随后的重新发布(和赏金)由ikegami以非常有创意的方式回应解决了伪问题,但在我的实际应用程序中难以掌握和重用 - 这需要在各种html页面上进行多次使用.在关于我们对话框中的第18条评论中,我终于发现了他的意思和使用($ cat) - 他使用的未记录的Perl语法.对于新读者来说,理解该语法可以理解(并重新格式化)他对问题的智能解决方案.他的帖子肯定符合OP中寻求的基本要求,但不使用HTML :: TreeBuilder :: XPath来实现.
jpalecek使用HTML :: TreeBuilder :: XPath,但不会将捕获的数据放入数组中以传递回PHP函数并上传到数据库中.
我从两个响应者那里学到了东西,希望这篇文章可以帮助像Perl这样的新人,比如我自己.任何最后的贡献将不胜感激.
如果我猜,你的问题是:"如何从提供的输入中获得以下内容?"
my $categorized_items = {
'We have nuts!' => [ 'Almonds', 'Cashwes' ],
'We have veggies!' => [ 'Carrots', 'Celery' ],
'We have booze!' => [ ],
};
Run Code Online (Sandbox Code Playgroud)
如果是这样,我就是这样做的:
use Data::Dumper qw( Dumper );
use XML::LibXML qw( );
my $root = XML::LibXML->load_xml(IO=>\*DATA)->documentElement;
my %cat_items;
for my $cat_tr ($root->findnodes('//table[contains(@id, "ITEMS")]/tr[td/span]')) {
my ($cat) = map $_->textContent(),
$cat_tr->findnodes('td/span');
my @items = map $_->textContent(),
$cat_tr->findnodes('following-sibling::tr[position()=1]/td/table/tr/td');
$cat_items{$cat} = \@items;
}
print(Dumper(\%cat_items));
__DATA__
...xml...
Run Code Online (Sandbox Code Playgroud)
PS - 你有什么不是有效的HTML.