我正在使用PHP DOM扩展解析一些XML,以便以其他形式存储数据。毫不奇怪,当我解析一个元素时,我经常需要获取某些名称的所有子元素。方法DOMElement::getElementsByTagName($name)
,但它返回具有该名称的所有后代,而不仅仅是直接子项。还有属性DOMNode::$childNodes
但是(1)它包含节点列表,而不是元素列表,即使我设法将列表项转换为元素(2)我仍然需要检查它们的所有内容名称。是否真的没有优雅的解决方案只能获得某些特定名称的孩子,或者我在文档中遗漏了什么?
一些例子:
<?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
?>
答案 0 :(得分:4)
我能想象的优雅方式是使用适合工作的FilterIterator
。能够处理这样的所述DOMNodeList
和(可选)接受标记名以作为来自 Iterator Garden 的示例性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("*")
也可以。但那只是一些评论。
Hier是一个在线工作用例:https://eval.in/57170
答案 1 :(得分:3)
简单的迭代过程
$parent = $p->parentNode;
foreach ( $parent->childNodes as $pp ) {
if ( $pp->nodeName == 'p' ) {
if ( strlen( $pp->nodeValue ) ) {
echo "{$pp->nodeValue}\n";
}
}
}
答案 2 :(得分: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');
使用国家ISO代码&#39; NL&#39;按指定属性iso
从父国家/地区节点返回DOM元素,基本上就像真正的搜索一样。在数组/对象中按名称查找某个国家/地区。
另一个用法示例:
$productNode = getAttachableNodeByAttributeName($products, 'partner-products');
返回仅包含单个(根)节点的DOM节点元素,而不搜索任何属性。
注意:为此,您必须确保根节点的根节点是唯一的。标签名称,例如此处countries->country[ISO]
- countries
节点是唯一的,并且是所有子节点的父节点。