PHP DOM:如何以优雅的方式通过标签名称获取子元素?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19555054/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHP DOM: How to get child elements by tag name in an elegant manner?
提问by Kalmar
I'm parsing some XML with PHP DOM extension in order to store the data in some other form. Quite unsurprisingly, when I parse an element I pretty often need to obtain all children elements of some name. There is the method DOMElement::getElementsByTagName($name)
, but it returns all descendants with that name, not just immediate children. There is also the property DOMNode::$childNodes
but (1) it contains node list, not element list, and even if I managed to turn the list items into elements (2) I'd still need to check all of them for the name. Is there really no elegant solution to get only the children of some specific name or am I missing something in the documentation?
我正在解析一些带有 PHP DOM 扩展的 XML,以便以其他形式存储数据。毫不奇怪,当我解析一个元素时,我经常需要获取某个名称的所有子元素。有方法DOMElement::getElementsByTagName($name)
,但它返回所有具有该名称的后代,而不仅仅是直接的孩子。还有这个属性,DOMNode::$childNodes
但是 (1) 它包含节点列表,而不是元素列表,即使我设法将列表项转换为元素 (2) 我仍然需要检查所有这些项的名称。真的没有优雅的解决方案来只获取某个特定名称的孩子,还是我在文档中遗漏了什么?
Some illustration:
一些插图:
<?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
?>
回答by M.Z.
simple iteration process
简单的迭代过程
$parent = $p->parentNode;
foreach ( $parent->childNodes as $pp ) {
if ( $pp->nodeName == 'p' ) {
if ( strlen( $pp->nodeValue ) ) {
echo "{$pp->nodeValue}\n";
}
}
}
回答by hakre
An elegant manner I can imagine would be using a FilterIterator
that is suitable for the job. Exemplary one that is able to work on such a said DOMNodeList
and (optionally) accepting a tagname to filter for as an exemplary DOMElementFilter
from the Iterator Gardendoes:
我可以想象的一种优雅方式是使用FilterIterator
适合该工作的方式。能够处理这样的示例DOMNodeList
并且(可选地)接受标记名作为DOMElementFilter
来自Iterator Garden的示例进行过滤的示例 :
$a = $doc->getElementsByTagName('a')->item(0);
$bs = new DOMElementFilter($a->childNodes, 'b');
foreach($bs as $b){
echo $b->nodeValue . "\n";
}
This will give the results you're looking for:
这将给出您正在寻找的结果:
1
2
You can find DOMElementFilter
in the Development branchnow. It's perhaps worth to allow *
for any tagname as it's possible with getElementsByTagName("*")
as well. But that's just some commentary.
您现在可以DOMElementFilter
在 Development 分支中找到。允许*
使用任何标记名可能是值得的,因为它也是可能的getElementsByTagName("*")
。但这只是一些评论。
Hier is a working usage example online: https://eval.in/57170
Hier 是一个在线的工作用法示例:https: //eval.in/57170
回答by stamster
My solution used in a production:
我在生产中使用的解决方案:
Finds a needle (node) in a haystack (DOM)
在大海捞针 (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;
}
Usage:
用法:
$countryNode = getAttachableNodeByAttributeName($countriesNode, 'country', 'iso', 'NL');
Returns DOM element from parent countries node by specified attribute iso
using country ISO code 'NL', basically like a real search would do. Find a certain country by it's name in an array / object.
iso
使用国家/地区 ISO 代码“NL”通过指定属性从父国家/地区节点返回 DOM 元素,基本上就像真正的搜索一样。在数组/对象中按名称查找某个国家/地区。
Another usage example:
另一个使用示例:
$productNode = getAttachableNodeByAttributeName($products, 'partner-products');
Returns DOM node element containing only single (root) node, without searching by any attribute.
Note: for this you must make sure that root nodes are unique by elements' tag name, e.g. countries->country[ISO]
- countries
node here is unique and parent to all child nodes.
返回仅包含单个(根)节点的 DOM 节点元素,不按任何属性进行搜索。注意:为此,您必须确保根节点通过元素的标签名称是唯一的,例如countries->country[ISO]
-countries
此处的节点是唯一的并且是所有子节点的父节点。