如果没有匹配项,则返回一个空的 DOMNodeList。使用 length 属性进行检查,例如:
<?php
$nodes=$domDocument->getElementsByTagName('book') ;
if ($nodes->length==0) {
// 没有结果
}
?>
(PHP 5, PHP 7, PHP 8)
DOMDocument::getElementsByTagName — 搜索具有给定本地标签名的所有元素
此函数返回一个新的 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
如果没有匹配项,则返回一个空的 DOMNodeList。使用 length 属性进行检查,例如:
<?php
$nodes=$domDocument->getElementsByTagName('book') ;
if ($nodes->length==0) {
// 没有结果
}
?>
请注意,使用 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) 是下一个“未更改”的标签。
我的第一篇帖子!
这就是我如何通过属性及其值获取元素。
例如,如果我想获取所有具有类名 '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;
}
?>
请改进它,并分享它。
这是一个 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
以下示例展示了多个属性和多个子节点。它被用于制作一个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 " - 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 " - Article Attribute Name : ".$params3->item($j)->getAttribute('name').""; // 获取Arti属性
echo " 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
我需要一个$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)) {
// 当你在这个循环内创建新的节点,作为该节点的子节点或后续兄弟节点时
// 它们会出现在这个循环中
}
}
?>
以下代码从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>';
}
}
?>
这是一种使用 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++;
}
?>
我不知道这是否显而易见,但对我来说不是,所以除了 rellim 点 com 的 gem 的帖子之外
添加
<?php
echo $param -> nodeValue.'<br>';
?>
到循环中将输出
value1
value2
value3
这是一个将 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);
}
?>
我第一次尝试用这个函数得到一个稳定的解决方案,用这个异常失败了
"致命错误:调用未定义的方法 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 版本。
问题
你有一个包含文件名引用的 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 代码可以轻松地转换为一个函数,该函数返回一个图片文件名数组、一个相对于找到的图片数量的整数值等。
希望这有帮助。
回复 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;
}
}
如果你想将所有节点移动到另一个标签,你可以这样做
例如:将 <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');