使用xpath过滤提取的数据

时间:2012-02-11 20:16:42

标签: php parsing dom xpath

我使用以下代码作为dom文档的输入

<li id="SalesRank">
<b>Amazon Best Sellers Rank:</b>
#20,267 Paid in Kindle Store (
<a href="http://www.amazon.com/gp/bestsellers/digital-text/ref=pd_dp_ts_kstore_1/190-9295683-0277616">See Top 100 Paid in Kindle Store</a>
) 
<ul class="zg_hrsr">
<li class="zg_hrsr_item">
<span class="zg_hrsr_rank">#15</span>
<span class="zg_hrsr_ladder">
in 
<a href="http://www.amazon.com/gp/bestsellers/digital-text/ref=pd_zg_hrsr_kstore_1_1">Kindle Store</a>
 > 
<a href="http://rads.stackoverflow.com/amzn/click/154606011">Kindle eBooks</a>
 > 
<a href="http://rads.stackoverflow.com/amzn/click/157325011">Nonfiction</a>
 > 
<a href="http://rads.stackoverflow.com/amzn/click/292975011">Lifestyle & Home</a>
 > 
<a href="http://rads.stackoverflow.com/amzn/click/156699011">Home & Garden</a>
 > 
<a href="http://rads.stackoverflow.com/amzn/click/156828011">Gardening & Horticulture</a>
 > 
<b>
<a href="http://rads.stackoverflow.com/amzn/click/156847011">Greenhouses</a>
</b>
</span>
</li>
<li class="zg_hrsr_item">
<span class="zg_hrsr_rank">#26</span>
<span class="zg_hrsr_ladder">
in 
<a href="http://www.amazon.com/gp/bestsellers/digital-text/ref=pd_zg_hrsr_kstore_2_1">Kindle Store</a>
 > 
<a href="http://rads.stackoverflow.com/amzn/click/154606011">Kindle eBooks</a>
 > 
<a href="http://rads.stackoverflow.com/amzn/click/157325011">Nonfiction</a>
 > 
<a href="http://rads.stackoverflow.com/amzn/click/292975011">Lifestyle & Home</a>
 > 
<a href="http://rads.stackoverflow.com/amzn/click/156699011">Home & Garden</a>
 > 
<a href="http://rads.stackoverflow.com/amzn/click/156828011">Gardening & Horticulture</a>
 > 
<b>
<a href="http://rads.stackoverflow.com/amzn/click/156849011">House Plants</a>
</b>
</span>
</li>
</ul></li>

我正在使用以下xpath查询来使用textContent ..

提取数据
$xpath_cat->query('//li[@id="SalesRank"]');

您可以检查输出,它包含所有li标记中包含id=salrsrank...的数据,而我只想获取#20,267 paid in kindle store..

所以需要的输出是

  

#20,267在Kindle商店支付

如何修改我的xpath以获得所需的输出?

代码更新

我尝试了下面提供的解决方案并使用了xpath

$xpath_cat->query('//li[@id="SalesRank"]/text()');

但是现在,输出是

  

([0] =&gt; [1] =&gt;#20,267在Kindle商店支付([2] =&gt;)

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

//li[@id='SalesRank']/text()是否适合您?

更新1

如果您想要的文字始终位于该位置,那么

substring-before(normalize-space(//li[@id='SalesRank']/text()[2]), ' (')

将返回

#20,267 Paid in Kindle Store

这使用normailize-space去除无关的空白区域,并substring-before在第一次出现之前选择所有文本“(”。

如果您可以在自己的节点中获取目标文本,则会更容易解决此问题,例如:

<b>Amazon Best Sellers Rank:</b>
<span>#20,267 Paid in Kindle Store</span> (
<a href="http://www.amazon.com/gp/bestsellers/digital-text/ref=pd_dp_ts_kstore_1/190-9295683-0277616">See Top 100 Paid in Kindle Store</a>
) 

<span/>对渲染没有影响,并允许您专门选择所需的文字。

如果第二个解决方案在所有情况下都不起作用,并且您现在无法获得目标文本,那么依赖于宿主语言中的某些后期处理( PHP我认为。)

希望这有帮助,

答案 1 :(得分:1)

我们假设$elementDOMElement,其中包含<li id="SalesRank">...

如果您这样做:

foreach( $element->childNodes as $node){
    echo get_class( $node) . "\n";
    // Print content too for debug:
    // echo $node->nodeValue . "\n";
}

你应该得到如下结果:

DOMText // \n
DOMElement // <b>Amazon Best Sellers Rank:</b>
DOMText // #20,267 Paid in Kindle Store (\n
DOMElement // <a ...
...

因此$element->childNodes->item( 2)->nodeValue 应该包含您的字符串(做好您的作业,检查每次迭代,检查每个元素的文档)。

在第一个(之前,你可以直接获取字符串:

$text = $element->childNodes->item( 2)->nodeValue;
$pos = strpos( $text, '(') - 2; // Add handling for no occurance
return substr( $text, 0, $pos);

或者你可以通过所有子节点迭代并动态检查

foreach( $element->childNodes as $node){
    // Example, rather use regexp with preg_match
    if( (get_class( $node) == 'DOMText')
        && (strncmp( $node->nodeValue, "\n#", 2) == 0)){
        // Tadaaa
        break;
    }
}

或者,如果你想要杀死几只小猫的解决方案:

preg_match( '~(#([\d,]+) ([^<>(]+))~', $element->nodeValue, $match);