带有条件的Perl XPath语句 - 可能吗?

Ric*_*sin 4 perl xpath

这个问题已被重新定义.我正在使用CPAN Perl模块WWW :: Mechanize来浏览网站,使用HTML :: TreeBuilder-XPath来捕获内容,使用xacobeo来测试HTML/XML上的XPath代码.目标是从基于PHP的网站调用此Perl脚本,并将已删除的内容上载到数据库中.因此,如果内容"缺失",仍然需要考虑.

下面是一个经过测试的简化示例代码,描述了我的挑战.注意:

  1. 该页面是动态填充的,包含ITEMS不同商店的各种输出; Products*每个商店都有不同数量的商品.这些产品清单可能有也可能没有下面的逐项表.
  2. 捕获的数据必须在数组中,并且必须维护任何逐项列表(如果存在)与产品列表的关联.

下面,示例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 @veggiesREFmy @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这样的新人,比如我自己.任何最后的贡献将不胜感激.

ike*_*ami 5

如果我猜,你的问题是:"如何从提供的输入中获得以下内容?"

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.

  1. TABLE元素不能直接放在TR元素内.TD元素缺失了.
  2. TR元素不能为空.它必须至少有一个TH或TD元素.