2010-06-15 18 views
7

Sadece DOMElement :: getElementsByTagName çağrısı ile bulunan acil çocukları almanın bir yolu var mı? Örneğin, bir kategori öğesine sahip bir XML belgesine sahibim. Bir DOMElement üst düzey kategorisini temsil eden varsaPHP DOMElement :: getElementsByTagName - Neredeyse sadece eşleşen çocuklar elde etmek için?

<category> 
    <id>1</id> 
    <name>Top Level Category Name</name> 
    <subCategory> 
     <id>2</id> 
     <name>Sub Category Name</name> 
    </subCategory> 
    ... 
</category> 

,

$topLevelCategoryElement->getElementsByTagName('id'); 

düğümleri için bir liste döndürür: Bu kategori elemanı gibi (aynı yapıya sahip) alt kategori elemanları vardır Tüm 'id' elemanları, en üst seviyeden sadece bir tane istiyorum. Bunu XPath kullanmanın dışında herhangi bir yolu var mı?

cevap

15

Korkarım ki değil. Çocuklarda yinelemeniz veya XPath kullanmanız gerekir. XPath ve XML dosyası ile

for ($n = $parent->firstChild; $n !== null; $n = $n->nextSibling) { 
    if ($n instanceof DOMElement && $n->tagName == "xxx") { 
     //... 
    } 
} 

Örnek:

$xml = ...; 
$d = new DOMDocument(); 
$d->loadXML($xml); 
$cat = $d->getElementsByTagName("subCategory")->item(0); 
$xp = new DOMXpath($d); 
$q = $xp->query("id", $cat); //note the second argument 
echo $q->item(0)->textContent; 

2 verir.

+0

aslında bu, SO-textbox işlevler taslaktan daha iyi. (Instanceof kontrolünü unutmuşum) – Kris

+0

Darn, çözüm için teşekkürler –

+0

Eklenen xpath çözümü için tekrar daha iyiyim. Seçim iyi – Kris

2

PHP kullanmıyorum, ancak PHP aslında DOM API'yi specified the W3C olarak uygularsa, herhangi bir Düğüm nesnesinde childNodes özelliği olması gerekir. Doğrudan tüm çocukların üzerinde yineleyebilmeli ve aradıklarınız olup olmadıklarını görmek için etiket adlarını test etmelisiniz. Ağacınızın neye benzediğine bağlı olarak, bu, tüm öğelerin etiket adına göre alınmasından ve ağaç konumlarının test edilmesinden daha yavaş olabilir veya önemli ölçüde daha hızlı olabilir. Böyle

11

şey

/** 
* Traverse an elements children and collect those nodes that 
* have the tagname specified in $tagName. Non-recursive 
* 
* @param DOMElement $element 
* @param string $tagName 
* @return array 
*/ 
function getImmediateChildrenByTagName(DOMElement $element, $tagName) 
{ 
    $result = array(); 
    foreach($element->childNodes as $child) 
    { 
     if($child instanceof DOMElement && $child->tagName == $tagName) 
     { 
      $result[] = $child; 
     } 
    } 
    return $result; 
} 

düzenlemeyi yapmalıdır: DOMElement instanceof eklendi

+0

Teşekkürler, bu yardımcı oldu. Değiştirmem gereken bir şey, '$ element-> children' - '$ element-> childNodes' idi. Bu cevap gönderildikten sonra muhtemelen bir şey değişti. – dontGoPlastic

-1

kullanarak elemanları karşılaştırabilirsiniz kontrol ===. Bu, bir Xpath nesnesinin başlatılmasını engeller.

$dom = new DOMDocument(); 
$dom->loadXML($xmlString); 

$return   = array(); 

//find your top level element 
$topLevelElement = $dom->getElementsByTagName('category'); 
//find all `id` child elements recursively 
$idElements  = $topLevelElement->getElementsByTagName('id'); 

if ($idElements->length > 0) { 
    foreach ($idElements as $idElement) { 
     if ($idElement->parentNode === $topLevelElement) { 
      $return[] = $idElement; 
     } 
    } 
} 

//$return now holds non nested child elements 

XML belgenizin boyutuna bağlı olarak Xpath'in daha iyi performans gösterdiğini görebilirsiniz. Ancak zarafet açısından bu çözüm daha temizdir.

İlgili konular