这个问题已经被重新表述了。我正在使用CPAN Perl模块WWW::Mechanize浏览网站,HTML::TreeBuilder-XPath捕获内容,xacobeo在HTML/XML上测试我的XPath代码。目标是从基于PHP的网站调用此Perl脚本,并将抓取的内容上传到数据库中。因此,即使内容“丢失”,仍需要对其进行账务处理。
下面是一个经过测试、简化的样例代码,描述了我的挑战。注意:
一个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新手。非常感谢任何最终的贡献。
下面是一个经过测试、简化的样例代码,描述了我的挑战。注意:
- 此页面动态生成,包含不同商店输出的各种
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>
一个XPath语句:
'//table[contains(@id, "ITEMS")]/tr[position() >1]/td/span/text()'
将找到:
We have nuts!
we have veggies!
We have booze!
并且XPath语句为:
'//table[contains(@id, "ITEMS")]/tr[position() >1]/td/table/tr/td/text()'
将会找到:
Almonds
Cashews
Carrots
Celery
这两个XPath语句可以合并:
'//table[contains(@id, "ITEMS")]/tr[position() >1]/td/span/text() | //table[contains(@id, "ITEMS")]/tr[position() >1]/table/tr/td/text()'
找到:
We have nuts!
Almonds
Cashews
We have veggies!
Carrots
Celery
We have booze!
以上数组可以使用正则表达式(在真实代码中)进行解密,以获取其产品到列表的关联。 但是,该数组是否可以使用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()')'
在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
在实际代码中,产品已知,因此可以预先定义
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新手。非常感谢任何最终的贡献。
td[3 and 4 and 6]
不会返回第三、第四和第六个成员。括号中的表达式返回 true,因此所有的td
都会被返回。请使用td[position()=3 or position()=4 or position()=6]
。 - chorobaif
表达式。在XPath 1.0中,没有if
表达式,但在某些情况下,单个XPath表达式可能足以实现条件选择。这就是为什么知道确切情况很重要的原因。 - Dimitre Novatchev