Bu nasıl XPath sorgusu (PHP) daha esnek olabilir?

2 Cevap php

PHP'nin SimpleXML kullanarak bir XHTML belgesi ayrıştırma. Belirli bir değer içeren bir düğüm için belgede ul yıllardan bir dizi sorgulamak gerekiyor, ardından kod açıklamaya yardımcı olacaktır ... bu düğümün ebeveynin doğrudan önceki eş bulmak!

Aşağıdaki kukla XHTML Verilen:

<html>
<head></head>
<body>
...

<ul class="attr-list"> 
    <li>Active Life (active)</li> 
    <ul> 
        <li>Amateur Sports Teams (amateursportsteams)</li> 
        <li>Amusement Parks (amusementparks)</li> 
        <li>Fitness & Instruction (fitness)</li> 
        <ul> 
            <li>Dance Studios (dancestudio)</li> 
            <li>Gyms (gyms)</li> 
            <li>Martial Arts (martialarts)</li> 
            <li>Pilates (pilates)</li> 
            <li>Swimming Lessons/Schools (swimminglessons)</li>  
        </ul> 
        <li>Go Karts (gokarts)</li> 
        <li>Mini Golf (mini_golf)</li> 
        <li>Parks (parks)</li> 
        <ul> 
            <li>Dog Parks (dog_parks)</li> 
            <li>Skate Parks (skate_parks)</li> 
        </ul> 
        <li>Playgrounds (playgrounds)</li> 
        <li>Rafting/Kayaking (rafting)</li> 
        <li>Tennis (tennis)</li> 
        <li>Zoos (zoos)</li> 
    </ul> 
    <li>Arts & Entertainment (arts)</li> 
    <ul> 
        <li>Arcades (arcades)</li> 
        <li>Art Galleries (galleries)</li> 
        <li>Wineries (wineries)</li> 
    </ul> 
    <li>Automotive (auto)</li> 
    <ul> 
        <li>Auto Detailing (auto_detailing)</li> 
        <li>Auto Glass Services (autoglass)</li> 
        <li>Auto Parts & Supplies (autopartssupplies)</li> 
    </ul>
    <li>Nightlife (nightlife)</li>
    <ul>
        <li>Bars (bars)</li>
        <ul>
            <li>Dive Bars (divebars)</li>
        </ul>
    </ul>
</ul>

...
</body>
</html>

Ben bir çocuk eleman için ul.attr-listesini sorgulamak gerekiyor, ve "kök" kategorisini keşfetmek. Ben farklı şekillendirilecek XHTML değiştiremezsiniz.

Ben bir kategori olarak "galerileri" var ise, bunu "sanat", "root" kategorisinde olduğunu bilmek gerekir. Ben "dog_parks" varsa ya da, ben bu "aktif" kategorisinde olduğunu bilmek gerekir. Aşağıdaki kod ama sadece max iki iç içe düzeyleri olduğu varsayımı ile, işi alır:

function get_root_category($shortCategoryName){

    $url = "http://www.yelp.com/developers/documentation/category_list";
    $result = file_get_contents($url);

    $dom = new domDocument();
    @$dom->loadHTML($result);
    $dom->preserveWhiteSpace = false;

    $sxml = simplexml_import_dom($dom);

    $lvl1 = $sxml->xpath("//li[contains(., '".$shortCategoryName."')]/parent::ul/preceding-sibling::li");
    $lvl2 = $sxml->xpath("//li[contains(., '".$shortCategoryName."')]/parent::ul/preceding-sibling::li/parent::ul/preceding-sibling::li");

    if($lvl2){
        return array_pop($lvl2);
    } else {
        return array_pop($lvl1);
    }
}

Orada tek bir sorgu yapılması gerekiyor ki, bu XPath yazmak için daha iyi bir yolu olmalı, ve birden, iç içe düzeyleri nispeten kurşun geçirmez olduğunu.

EDIT :: Bu HTML geçerli olmadığını işaret olanlar için teşekkür ederiz. Ancak, sayfanın yapısı ayarlanır, ve bunu düzenleyemezsiniz; Ben sadece bir kaynak olarak kullanmak, ve ne ile nedeniyle yapmak zorunda olabilir.

2 Cevap

I need to query a series of ul's in the document for a node containing a specific value, then find that node's parent's direct previous sibling...

Yani (burada $v aradığınız değer) olacaktır:

$p = "/html/body//ul[li[contains(text(), '$v')]]/preceding-sibling::li[1]";
  • Bu XPath ifadesini kıracak beri $v, tek tırnak içermediğini kontrol emin olun.
  • When you want to look for whole words only, use:
    [contains(concat(' ', text(), ' '), concat(' ', '$v', ' '))].
  • When you want to look case-insentitively, use (I abbreviated the full alphabet with ):
    [contains(translate(text(), 'ABC…XYZ', 'abc…xyz'), '{strtolower($v)}')].
  • Yüklemler iç içe olduğunu unutmayın.
  • Kullanımı text() sadece doğrudan alt metin düğümleri dikkate alınır sağlar unutmayın. Eğer . yerine, bütün "alt ağacı" kullandığınızda <li> dizeye dönüştürülür ve size gerçekten istediğiniz daha fazla sonuç alabilirsiniz.
  • Note that I restricted the // operator (a shortcut for the descendant axis) to a certain part of the tree - if you can restrict it further, by all means do so.
    Letting your XPath start with // makes it much slower than it needs to be since all nodes of the entire document are checked, even those that can not under any circumstances produce a match.
  • Diğerleri zaten belirtildiği gibi, HTML geçersiz.

Nasıl hakkında:

/html/body/ul/ul[count(descendant::li[contains(.,'dog_parks')]) > 0]/preceding-sibling::li

Bu iç içe listeleri ile çalışması gerekir. Her zaman üst en kategorisini alır.

Arada: Ben bu geçerli gibi ul 'ın yuvalama sanmıyorum.