2013-10-24 17 views
4

我正在使用PHP DOM擴展來解析一些XML以便以某種其他形式存儲數據。毫不奇怪,當我解析一個元素時,我經常需要獲得某個名字的所有子元素。有方法DOMElement::getElementsByTagName($name),但它會返回具有該名稱的所有後代,而不僅僅是直接的子代。也有屬性DOMNode::$childNodes但(1)它包含節點列表,而不是元素列表,即使我設法將列表項目變成元素(2)我仍然需要檢查所有的名稱。是否真的沒有優雅的解決方案來獲取某些特定名稱的孩子,或者我在文檔中丟失了什麼?PHP DOM:如何以優雅的方式通過標籤名稱獲取子元素?

一些例證:

<?php 

DOMDocument(); 
$document->loadXML(<<<EndOfXML 
<a> 
    <b>1</b> 
    <b>2</b> 
    <c> 
    <b>3</b> 
    <b>4</b> 
    </c> 
</a> 
EndOfXML 
); 

$bs = $document 
    ->getElementsByTagName('a') 
    ->item(0) 
    ->getElementsByTagName('b'); 

foreach($bs as $b){ 
    echo $b->nodeValue . "\n"; 
} 

// Returns: 
// 1 
// 2 
// 3 
// 4 
// I'd like to obtain only: 
// 1 
// 2 

?> 
+3

OTOH,只需在上下文節點上運行'DOMXPath :: query'即可。 (或添加整個文檔,並查詢'/ a [1]/b') – Wrikken

+1

在現實生活中,我解析了相當大的文件,所以我使用DOMReader和它的方法expand()來解析塊。不幸的是,副作用是我沒有'DOMDocument',只有很多'DOMElement'的實例,我無法爲他們優雅地構造'DOMXPAth' ...爲什麼這些想法很糟糕!我想避免將'DOMElment'再次轉換爲'SimpleXML',但我越來越接近這個決定...... – Kalmar

回答

4

優雅的方式我能想象會使用FilterIterator是適合這份工作。典型的一個是能夠在工作這麼說DOMNodeList和(可選)接受標記名從迭代花園示範DOMElementFilter不進行過濾:

$a = $doc->getElementsByTagName('a')->item(0); 

$bs = new DOMElementFilter($a->childNodes, 'b'); 

foreach($bs as $b){ 
    echo $b->nodeValue . "\n"; 
} 

這會給你正在尋找的結果用於:

1 
2 

您現在可以發現DOMElementFilter in the Development branch。對於任何標記名,允許使用*也是值得的,因爲它也可以使用getElementsByTagName("*")。但這只是一些評論。

海爾是在線工作使用例如:https://eval.in/57170

2

簡單的迭代過程

 $parent = $p->parentNode; 

     foreach ($parent->childNodes as $pp) { 

      if ($pp->nodeName == 'p') { 
       if (strlen($pp->nodeValue)) { 
        echo "{$pp->nodeValue}\n"; 
       } 
      } 

     } 
0

在生產中使用的我的解決辦法:

在乾草堆裏(DOM查找一個針(節點) )

function getAttachableNodeByAttributeName(\DOMElement $parent = null, string $elementTagName = null, string $attributeName = null, string $attributeValue = null) 
{ 
    $returnNode = null; 

    $needleDOMNode = $parent->getElementsByTagName($elementTagName); 

    $length = $needleDOMNode->length; 
    //traverse through each existing given node object 
    for ($i = $length; --$i >= 0;) { 

     $needle = $needleDOMNode->item($i); 

     //only one DOM node and no attributes specified? 
     if (!$attributeName && !$attributeValue && 1 === $length) return $needle; 
     //multiple nodes and attributes are specified 
     elseif ($attributeName && $attributeValue && $needle->getAttribute($attributeName) === $attributeValue) return $needle; 
    } 

    return $returnNode; 
} 

用法:

$countryNode = getAttachableNodeByAttributeName($countriesNode, 'country', 'iso', 'NL'); 

返回從父節點國家DOM元素通過指定的屬性iso使用國家ISO代碼「NL」,基本上像一個真正的搜索會做。通過數組/對象中的名稱查找某個國家/地區。

另一使用例如:

$productNode = getAttachableNodeByAttributeName($products, 'partner-products'); 

返回一個只包含單一(根)節點,不受任何屬性搜索DOM節點元件。 注意:爲此,您必須確保根節點由元素的標記名稱唯一,例如countries->country[ISO] - countries此處的節點是唯一的,並且是所有子節點的父節點。

相關問題