DOMDocument::getElementsByTagName

(PHP 5, PHP 7, PHP 8)

DOMDocument::getElementsByTagName搜索具有给定本地标签名的所有元素

说明

public DOMDocument::getElementsByTagName(string $qualifiedName): DOMNodeList

此函数返回一个新的 DOMNodeList 类实例,其中包含所有具有给定本地标签名的元素。

参数

qualifiedName

要匹配的标签的本地名称(不带命名空间)。特殊值 * 匹配所有标签。

返回值

一个新的 DOMNodeList 对象,包含所有匹配的元素。

范例

示例 #1 基本用法示例

<?php
$xml
= <<< XML
<?xml version="1.0" encoding="utf-8"?>
<books>
<book>Patterns of Enterprise Application Architecture</book>
<book>Design Patterns: Elements of Reusable Software Design</book>
<book>Clean Code</book>
</books>
XML;

$dom = new DOMDocument;
$dom->loadXML($xml);
$books = $dom->getElementsByTagName('book');
foreach (
$books as $book) {
echo
$book->nodeValue, PHP_EOL;
}
?>

上面的例子将输出

Patterns of Enterprise Application Architecture
Design Patterns: Elements of Reusable Software Design
Clean Code

参见

添加笔记

用户贡献的笔记 14 个笔记

51
James L
15 年前
如果没有匹配项,则返回一个空的 DOMNodeList。使用 length 属性进行检查,例如:

<?php
$nodes
=$domDocument->getElementsByTagName('book') ;
if (
$nodes->length==0) {
// 没有结果
}
?>
11
Philip N
13 年前
请注意,使用 getElementsByTagName 时,它是一个动态列表。因此,如果您有调整 DOM 结构的代码,它将更改 getElementsByTagName 结果列表的结果。

以下代码迭代通过一组完整的結果,并将它们全部更改为新的标签

<?php
$nodes
= $xml->getElementsByTagName ("oldtag");

$nodeListLength = $nodes->length; // 此值也会改变
for ($i = 0; $i < $nodeListLength; $i ++)
{
$node = $nodes->item(0);

// 一些代码用于将标签名称从 "oldtag" 更改为其他名称
// 例如,加密标签元素
}
?>

由于列表是动态更新的,因此 $nodes->item(0) 是下一个“未更改”的标签。
11
calvin at g mail
13 年前
我的第一篇帖子!
这就是我如何通过属性及其值获取元素。
例如,如果我想获取所有具有类名 'className' 的 DIV 标签,那么...

<?php
$some_link
= 'some website';
$tagName = 'div';
$attrName = 'class';
$attrValue = 'className';

$dom = new DOMDocument;
$dom->preserveWhiteSpace = false;
@
$dom->loadHTMLFile($some_link);

$html = getTags( $dom, $tagName, $attrName, $attrValue );
echo
$html;

function
getTags( $dom, $tagName, $attrName, $attrValue ){
$html = '';
$domxpath = new DOMXPath($dom);
$newDom = new DOMDocument;
$newDom->formatOutput = true;

$filtered = $domxpath->query("//$tagName" . '[@' . $attrName . "='$attrValue']");
// $filtered = $domxpath->query('//div[@class="className"]');
// '//' 当你不知道 '绝对' 路径时

// 由于上面的返回值是 DomNodeList 对象
// 我使用以下例程将其转换为字符串(html);从这个网站上某人的帖子中复制的。谢谢。
$i = 0;
while(
$myItem = $filtered->item($i++) ){
$node = $newDom->importNode( $myItem, true ); // 导入节点
$newDom->appendChild($node); // 附加节点
}
$html = $newDom->saveHTML();
return
$html;
}

?>

请改进它,并分享它。
8
gem at rellim dot com
19 年前
这是一个 getElementsByTagName() 的例子

<?php
$xml
=<<<EOT
<?xml version="1.0"?>
<config>
<section id="section1">
<param name="param1">value1</param>
<param name="param2">value2</param>
</section>
<section id="section2">
<param name="param3">value3</param>
</section>
</config>
EOT;

$dom = new DomDocument;
$dom->preserveWhiteSpace = FALSE;
$dom->loadXML($xml);
$params = $dom->getElementsByTagName('param');

foreach (
$params as $param) {
echo
$param -> getAttribute('name').'<br>';
}
?>

预期结果
--------------
参数1
参数2
参数3
10
gurmukh24 at gmail dot com
15 年前
以下示例展示了多个属性和多个子节点。它被用于制作一个Joomla插件,实现文章的批量上传。Gurmukh Singh Bhatti

<?php
$xml
=<<<EOT
<?xml version="1.0"?>
<root>
<section name="Section1">
<category id="Category1" name="google">
<arti name="article1">
<p>any html code here</p>
<b>my name is so so</b>
</arti>
<arti name="article2">value2</arti>
<arti name="article3">value3</arti>
<arti name="article4">value4</arti>
</category>
<category id="Category2" name="yahoo">
<arti name="articleSection2">Test value</arti>
</category>
</section>
<section name="Section2">
<category id="category1_of_section2" name="msn">
<arti name="article2">value1</arti>
<arti name="article3">value2</arti>
</category>
<category id="Category2_of_section2" name="webcare">
<arti name="param3">value4</arti>
</category>
</section>
</root>
EOT;

$dom = new DomDocument;
$dom->preserveWhiteSpace = FALSE;
$dom->loadXML($xml);
$params = $dom->getElementsByTagName('section'); // 查找所有Section节点
$k=0;
foreach (
$params as $param) // 逐一遍历每个Section节点
{
echo
"Section Attribute :-> ".$params->item($k)->getAttribute('name')."<br>"; // 获取Section属性
$params2 = $params->item($k)->getElementsByTagName('category'); // 查找每个Section内部的Category节点
$i=0; // 用于迭代Category节点的计数器
foreach ($params2 as $p) {
echo
"&nbsp;&nbsp;- Category Attribute Name :-> ".$params2->item($i)->getAttribute('name')."<br>"; // 获取Category属性
$params3 = $params2->item($i)->getElementsByTagName('arti'); // 查找每个Category内部的Arti节点
$j=0;// 用于迭代Arti节点的计数器
foreach ($params3 as $p2)
{
echo
"&nbsp;&nbsp;&nbsp;- Article Attribute Name : ".$params3->item($j)->getAttribute('name').""; // 获取Arti属性
echo "&nbsp;&nbsp; Value : ".$params3->item($j)->nodeValue."<br>"; // 获取节点值
$j++;
}
$i++;
}
$k++;

}
?>

输出
Section Attribute :-> Section1
- Category Attribute Name :-> google
- Article Attribute Name : article1 Value : any html code heremy name is so so
- Article Attribute Name : article2 Value : value2
- Article Attribute Name : article3 Value : value3
- Article Attribute Name : article4 Value : value4
- Category Attribute Name :-> yahoo
- Article Attribute Name : articleSection2 Value : Test value
Section Attribute :-> Section2
- Category Attribute Name :-> msn
- Article Attribute Name : article2 Value : value1
- Article Attribute Name : article3 Value : value2
- Category Attribute Name :-> webcare
- Article Attribute Name : param3 Value : value4
3
rsvvuuren at hotmail dot com
10年前
我需要一个$dom->getElementsByTagName方法,可以在contextNode范围内发挥作用。

我需要getElementsByTagName而不是简单地使用xPath->query的原因是,在遍历返回的节点列表时,会创建更多具有相同tagName的节点。

使用getElementsByTagName时,新节点会“添加到”我正在遍历的节点列表中。

使用xpath查询时,你只会遍历原始的节点列表,新创建的元素不会出现在该节点列表中。

我之前已经使用了DOMDocument的扩展类,因此创建一种可以接受contextNode的getElementsByTagName方法非常简单。

<?php
class SmartDocument extends DOMDocument {
private
$localDom;
public
$xpath;
private
$serialize = array('localDom');

private
$elemName;
private
$elemCounter;

/**
* 构造函数
*/
function __construct() {
parent::__construct ( '1.0', 'UTF-8' );
$this->preserveWhiteSpace = false;
$this->recover = TRUE;
$this->xpath = new DOMXpath ( $this );
}

/**
* 在contextNode内获取元素列表
*
* @param string $name
* @param DomNode $contextNode
* @return DOMNode|NULL
*/
public function getElementsByTagNameContext($name, $contextNode) {

if(
$this->elemName!=$name) {
$this->elemCounter = 0;
$this->elemName =$name;
}

$this->elemLength = $this->xpath->evaluate('count(.//*[name()="'.$this->elemName.'"])', $contextNode);
while(
$this->elemCounter < $this->elemLength) {
$this->elemCounter++;
$nl = $this->xpath->query('.//*[name()="'.$this->elemName.'"]['.$this->elemCounter.']', $contextNode);
if(
$nl->length == 1) {
return
$nl->item(0);
}
}

$this->elemLength = null;
$this->elemCounter = null;
$this->elemName = null;
return
null;
}
}

?>

用法

<?php

$doc
= new SmartDocument();
$doc->load('book.xml');

$nl = $doc->query('//books');
foreach(
$nl as $node) {
while(
$book = $doc->getElementsByTagNameContext('book', $node)) {
// 当你在这个循环内创建新的节点,作为该节点的子节点或后续兄弟节点时
// 它们会出现在这个循环中
}

}

?>
3
Marco Maranao
14年前
以下代码从XML文件(或RSS feed)中获取新闻列表,将其先分配给一个名称值对数组,然后生成一个HTML列表。

<?php

$xml
=<<<EOT
<?xml version="1.0" encoding="ISO-8859-1"?>
<news>
<item>
<title>News 1</title>
<created>04/2/2010 08:00 EST</created>
<url>http://news.example.com/news.pdf</url>
</item>
<item>
<title>News 2</title>
<created>04/25/2010 08:00 EST</created>
<url>http://news.example.com/news.pdf</url>
</item>
<item>
<title>News 3</title>
<created>04/27/2010 08:00 EST</created>
<url>http://news.example.com/news.pdf</url>
</item>
</news>
EOT;

$doc = new DOMDocument();

if (
$doc->loadXML($xml)) {
$items = $doc->getElementsByTagName('item');
$headlines = array();

foreach(
$items as $item) {
$headline = array();

if(
$item->childNodes->length) {
foreach(
$item->childNodes as $i) {
$headline[$i->nodeName] = $i->nodeValue;
}
}

$headlines[] = $headline;
}

if(!empty(
$headlines)) {
$hc = 0;

echo
'<ul>';

foreach(
$headlines as $headline) {
if(++
$hc <= 3) {
echo
'<li>'
.'<a href="'.$headline['url'].'" target="_blank">'
.'<span>'.date('F j, Y', strtotime($headline['created'])).'</span><br />'
.$headline['title']
.
'</a>'
.'</li>';
}
}

echo
'</ul>';
}
}

?>
5
yaakov dot moddel at gmail dot com
11 年前
这是一种使用 DOMDocument 类遍历 xml 节点和子节点的非常简单的方法

<?php
$xml
='<?xml version="1.0" encoding="utf-8"?>
<root>
<Parent>
<child>child 1</child>
<child>child 2</child>
<child>child 3</child>
<subParent>
<Grandchild>Grandchild 1</Grandchild>
<Grandchild>Grandchild 2</Grandchild>
<Grandchild>Grandchild 3</Grandchild>
</subParent>
</Parent>
<Parent>
<child>child 4</child>
<child>child 5</child>
<child>child 6</child>
<subParent>
<Grandchild>Grandchild 4</Grandchild>
<Grandchild>Grandchild 5</Grandchild>
<Grandchild>Grandchild 6</Grandchild>
</subParent>
</Parent>
</root>'
;
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
$doc->loadXML($xml);
$i=0;
while(
is_object($finance = $doc->getElementsByTagName("Parent")->item($i)))
{
foreach(
$finance->childNodes as $nodename)
{
if(
$nodename->nodeName=='subParent')
{
foreach(
$nodename->childNodes as $subNodes)
{
echo
$subNodes->nodeName." - ".$subNodes->nodeValue."<br>";
}
}
else
{
echo
$nodename->nodeName." - ".$nodename->nodeValue."<br>";
}
}
$i++;
}
?>
1
Finding values of a node
17 年前
我不知道这是否显而易见,但对我来说不是,所以除了 rellim 点 com 的 gem 的帖子之外
添加

<?php
echo $param -> nodeValue.'<br>';
?>

到循环中将输出
value1
value2
value3
1
simon at onepointltd dot com
10年前
这是一个将 HTML 文档中的填充表格转换为数组的函数。

<?php
// 创建一个包含 HTML 页面中所有填充表格的数组
// 返回的数组:tables_to_array[表格编号][行编号][列编号]
function tables_to_array ($url) {
$htmlDocDom = new DOMDocument();

@
$htmlDocDom->loadHTMLFile($url);
$htmlDocDom->preserveWhiteSpace = false;
$tableCounter = 0;
$htmlDocTableArray = array();
$htmlDocTables = $htmlDocDom->getElementsByTagName('table');
foreach (
$htmlDocTables as $htmlDocTable) {
$htmlDocTableArray[$tableCounter] = array();
$htmlDocRows= $htmlDocTable->getElementsByTagName('tr');
$htmlDocRowCount = 0;
$htmlDocTableArray[$tableCounter] = array();
foreach (
$htmlDocRows as $htmlDocRow) {
if (
strlen($htmlDocRow->nodeValue) > 1)
{
$htmlDocColCount = 0;
$htmlDocTableArray[$tableCounter][$htmlDocRowCount] = array();
$htmlDocCols = $htmlDocRow->getElementsByTagName('td');
foreach (
$htmlDocCols as $htmlDocCol) {
$htmlDocTableArray[$tableCounter][$htmlDocRowCount][] = $htmlDocCol->nodeValue;
$htmlDocColCount++;
}
$htmlDocRowCount++;
}
}
if (
$htmlDocRowCount > 1) $tableCounter++;
}
return(
$htmlDocTableArray);
}
?>
-1
metron at underhive-planet dot com
13 年前
我第一次尝试用这个函数得到一个稳定的解决方案,用这个异常失败了

"致命错误:调用未定义的方法 DOMNodeList::getElementsByTagName()"
这是 xml 代码段
<?xml version="1.0" encoding="UTF-8"?>
<root>
<component>
<properties>
....<任何元素>
</properties>
</component>
</root>

所以沿着元素爬行的 php 代码是
<?php

$src
= new DOMDocument('1.0', 'utf-8');
$src->formatOutput = true;
$src->preserveWhiteSpace = false;

// 加载外部文件
$src->load('../xml/Item_component.xml');

// 检查第一个索引分支节点的子节点:<component>
// 首先获取根元素后的元素:<component>

// 第一层级
$component = $src->getElementsByTagName('component')->item(0);

// 第二层级,获取 component 后的下一个元素,这里失败了!
$properties = $component->getElementsByTagName('properties')->item(0);
...
?>

我发现,在 Apache2 上使用不同的 libxml2 版本会导致不同的结果。这段代码在 libxml2 版本 2.6.23 和 PHP 版本 5.2.6 上会失败。
--
-> 在 libxml2 版本 2.6.32 和 PHP 版本 5.2.6-3ubuntu4.6 上正常工作。
-> 最后,它在 libxml2 2.7.7 和 PHP >= 5.3 上也正常工作。

所以,如果你像我一样厌倦了搜索 DOM 解决方案,请确保你的 web 环境在 Apache2 服务器上安装了正确的 libxml2/PHP 版本。
-1
james
14年前
问题
你有一个包含文件名引用的 XML 文档,例如,图片文件。每个文件名引用由 <file>filename.ext</file> 标签定义。你希望执行额外的验证,例如,在通过 XSD 验证 XML 文档后。额外的验证可以是任何你选择的内容,在这个例子中,将 PHP 代码转换为函数是理想的。然后,该函数将确定图片是否存在并返回一个整数值或布尔值。

<?xml version="1.0"?>
<root>
<box>
<file>example.png</file>
</box>
<content>
<item>
<image><file>example2.png</file></image>
<caption>The above image is an example</caption>
</item>
</content>
</root>

解决方案
<?php

$dom
= new DomDocument();
$dom->prevservWhiteSpace = false;

if (!@
$dom->load("example.xml")) {
echo
"example.xml doesn't exist!\n";
return;
}

$imageList = $dom->getElementsByTagName('file');
$imageCnt = $imageList->length;

for (
$idx = 0; $idx < $imageCnt; $idx++) {
print
$imageList->item($idx)->nodeValue . "\n";
}

?>

上面的 PHP 代码可以轻松地转换为一个函数,该函数返回一个图片文件名数组、一个相对于找到的图片数量的整数值等。

希望这有帮助。
-2
jason at shaped dot ca
16 年前
回复 tildy at pr dot hu

我更喜欢的方式是(例如,从 ISO 3166 XML 文件中收集国家数据)

$countries = new DOMDocument();
$countries->load("./lib/iso_3166.xml");

$countriesList = $countries->getElementsByTagName("ISO_3166-1_Entry");

foreach($countriesList as $country) {
$values = $country->getElementsByTagName("*");
foreach($values as $node) {
echo $node->nodeName."=".$node->nodeValue;
}
}
-3
Mateusz K
4 年前
如果你想将所有节点移动到另一个标签,你可以这样做
例如:将 <div> 和其节点替换为 <p> 和相同的节点。

function replaceDomElementTag(DOMDocument $dom, DOMElement $node, string $tagName)
{
$newElement = $dom->createElement($tagName);
while ($node->childNodes->length)
$newElement->appendChild($node->childNodes[0]);

$node->parentNode->replaceChild($newElement, $node);
}

$dom = new DOMDocument();
replaceDomElementTag($dom, $divElementToReplace, 'p');
To Top