2024 年 PHP 大会日本站

DOMNode 类

(PHP 5, PHP 7, PHP 8)

类概要

class DOMNode {
/* 常量 */
public const int DOCUMENT_POSITION_DISCONNECTED = 0x1;
public const int DOCUMENT_POSITION_PRECEDING = 0x2;
public const int DOCUMENT_POSITION_FOLLOWING = 0x4;
public const int DOCUMENT_POSITION_CONTAINS = 0x8;
public const int DOCUMENT_POSITION_CONTAINED_BY = 0x10;
/* 属性 */
public readonly string $nodeName;
public readonly int $nodeType;
public readonly ?DOMNode $parentNode;
public readonly ?DOMElement $parentElement;
public readonly DOMNodeList $childNodes;
public readonly ?DOMNode $firstChild;
public readonly ?DOMNode $lastChild;
public readonly ?DOMNode $previousSibling;
public readonly ?DOMNode $nextSibling;
public readonly ?DOMNamedNodeMap $attributes;
public readonly bool $isConnected;
public readonly ?DOMDocument $ownerDocument;
public readonly ?string $namespaceURI;
public string $prefix;
public readonly ?string $localName;
public readonly ?string $baseURI;
/* 方法 */
public C14N(
    bool $exclusive = false,
    bool $withComments = false,
    ?array $xpath = null,
    ?array $nsPrefixes = null
): string|false
public C14NFile(
    string $uri,
    bool $exclusive = false,
    bool $withComments = false,
    ?array $xpath = null,
    ?array $nsPrefixes = null
): int|false
public cloneNode(bool $deep = false): DOMNode|false
public getLineNo(): int
public getRootNode(?array $options = null): DOMNode
public insertBefore(DOMNode $node, ?DOMNode $child = null): DOMNode|false
public isDefaultNamespace(string $namespace): bool
public isEqualNode(?DOMNode $otherNode): bool
public isSameNode(DOMNode $otherNode): bool
public isSupported(string $feature, string $version): bool
public lookupPrefix(string $namespace): ?string
public normalize(): void
public replaceChild(DOMNode $node, DOMNode $child): DOMNode|false
public __sleep(): array
public __wakeup(): void
}

预定义常量

DOMNode::DOCUMENT_POSITION_DISCONNECTED
当另一个节点和参考节点不在同一树中时设置。
DOMNode::DOCUMENT_POSITION_PRECEDING
当另一个节点在参考节点之前时设置。
DOMNode::DOCUMENT_POSITION_FOLLOWING
当另一个节点在参考节点之后时设置。
DOMNode::DOCUMENT_POSITION_CONTAINS
当另一个节点是参考节点的祖先节点时设置。
DOMNode::DOCUMENT_POSITION_CONTAINED_BY
当另一个节点是参考节点的后代节点时设置。
DOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
当结果取决于特定于实现的行为并且可能不可移植时设置。这可能发生在断开的节点或属性节点上。

属性

nodeName

返回当前节点类型的最准确名称

nodeValue

此节点的值,取决于其类型。与W3C规范相反,DOMElement节点的节点值等于DOMNode::textContent,而不是null

nodeType

获取节点的类型。预定义的XML_*_NODE常量之一

parentNode

此节点的父节点。如果没有这样的节点,则返回null

parentElement

此元素的父元素。如果没有这样的元素,则返回null

childNodes

一个DOMNodeList,包含此节点的所有子节点。如果没有子节点,则为空DOMNodeList

firstChild

此节点的第一个子节点。如果没有这样的节点,则返回null

lastChild

此节点的最后一个子节点。如果没有这样的节点,则返回null

previousSibling

此节点之前的节点。如果没有这样的节点,则返回null

nextSibling

此节点之后的节点。如果没有这样的节点,则返回null

attributes

一个DOMNamedNodeMap,包含此节点的属性(如果它是DOMElement)或null(否则)。

isConnected

节点是否连接到文档

ownerDocument

与该节点关联的DOMDocument对象,或者如果该节点是DOMDocument则为null

namespaceURI

此节点的命名空间URI,如果未指定则为null

prefix

此节点的命名空间前缀。

localName

返回此节点限定名称的局部部分。

baseURI

此节点的绝对基本URI,如果实现无法获取绝对URI,则为null

textContent

此节点及其后代的文本内容。

变更日志

版本 描述
8.4.0 已添加方法DOMNode::compareDocumentPosition()
8.4.0 已添加常量DOMNode::DOCUMENT_POSITION_DISCONNECTEDDOMNode::DOCUMENT_POSITION_PRECEDINGDOMNode::DOCUMENT_POSITION_FOLLOWINGDOMNode::DOCUMENT_POSITION_CONTAINSDOMNode::DOCUMENT_POSITION_CONTAINED_BYDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
8.3.0 已添加方法DOMNode::contains()DOMNode::isEqualNode()
8.3.0 已添加属性DOMNode::$parentElementDOMNode::$isConnected
8.0.0 已删除未实现的方法DOMNode::compareDocumentPosition()DOMNode::isEqualNode()DOMNode::getFeature()DOMNode::setUserData()DOMNode::getUserData()

备注

注意:

DOM 扩展使用 UTF-8 编码。使用 mb_convert_encoding()UConverter::transcode()iconv() 处理其他编码。

目录

添加备注

用户贡献的备注 13 条备注

marc at ermshaus dot org
15 年前
我花了很长时间才找到 XML_*_NODE 常量的映射。所以我想,把它贴在这里会很方便。

1 XML_ELEMENT_NODE
2 XML_ATTRIBUTE_NODE
3 XML_TEXT_NODE
4 XML_CDATA_SECTION_NODE
5 XML_ENTITY_REFERENCE_NODE
6 XML_ENTITY_NODE
7 XML_PROCESSING_INSTRUCTION_NODE
8 XML_COMMENT_NODE
9 XML_DOCUMENT_NODE
10 XML_DOCUMENT_TYPE_NODE
11 XML_DOCUMENT_FRAGMENT_NODE
12 XML_NOTATION_NODE
David Rekowski
14 年前
您不能简单地覆盖 `$textContent` 来替换 DOMNode 的文本内容,正如缺少的只读标志所示。相反,您必须执行以下操作:

<?php

$node
->removeChild($node->firstChild);
$node->appendChild(new DOMText('new text content'));

?>

此示例显示了会发生什么情况:

<?php

$doc
= DOMDocument::loadXML('<node>old content</node>');
$node = $doc->getElementsByTagName('node')->item(0);
echo
"Content 1: ".$node->textContent."\n";

$node->textContent = 'new content';
echo
"Content 2: ".$node->textContent."\n";

$newText = new DOMText('new content');

$node->appendChild($newText);
echo
"Content 3: ".$node->textContent."\n";

$node->removeChild($node->firstChild);
$node->appendChild($newText);
echo
"Content 4: ".$node->textContent."\n";

?>

输出结果为:

Content 1: old content // 初始内容
Content 2: old content // 尝试覆盖写入 `$node->textContent`
Content 3: old contentnew content // 只需追加新的文本节点
Content 4: new content // 在追加新的文本节点之前移除第一个子节点

如果您想要 CDATA 节点,请使用以下代码:

<?php
$doc
= DOMDocument::loadXML('<node>old content</node>');
$node = $doc->getElementsByTagName('node')->item(0);
$node->removeChild($node->firstChild);
$newText = $doc->createCDATASection('new cdata content');
$node->appendChild($newText);
echo
"Content withCDATA: ".$doc->saveXML($node)."\n";
?>
R. Studer
14 年前
澄清说明
前面发帖者“发现”的,并且似乎没有记录的这个类 (DOMNode) 上的方法(`getElementsByTagName` 和 `getAttribute`)实际上是 `DOMElement` 类的成员方法,`DOMElement` 类继承自 `DOMNode`。

参见:https://php.net/manual/en/class.domelement.php
Steve K
15 年前
这个类显然还有一个 `getElementsByTagName` 方法。

我通过使用 `is_a()` 函数对 `DOMNodeList->item()` 的输出进行各种测试来确认这一点。
brian wildwoodassociates.info
15 年前
这个类有一个 `getAttribute` 方法。

假设一个 DOMNode 对象 `$ref` 包含从 DOMNode 列表中提取的锚点。然后

`$url = $ref->getAttribute('href');`

将分离与锚点的 href 部分关联的 url。
alastair dot dallas at gmail dot com
13 年前
围绕混合内容的问题让我做了一些实验才记住,所以我想添加这个备注来节省其他人的时间。

当您的标记类似于:<div><p>First text.</p><ul><li><p>First bullet</p></li></ul></div> 时,您将获得非常规则的 XML_ELEMENT_NODE。<div> 具有子节点 <p> 和 <ul>,并且两个 <p> 的 `nodeValue` 都产生您期望的文本。

但是,当您的标记更像 <p>This is <b>bold</b> and this is <i>italic</i>.</p> 时,您会意识到 XML_ELEMENT_NODE 的 `nodeValue` 并不可靠。在这种情况下,您需要查看 <p> 的子节点。对于此示例,<p> 具有子节点:#text,<b>,#text,<i>,#text。

在此示例中,<b> 和 <i> 的 `nodeValue` 与它们的 #text 子节点相同。但是您可能有这样的标记:<p>This <b>is bold and <i>bold italic</i></b>, you see?</p>。在这种情况下,您需要查看 <b> 的子节点,它将是 #text,<i>,因为 <b> 的 `nodeValue` 不够。

XML_TEXT_NODE 没有子节点,并且始终命名为“#text”。根据空格的处理方式,您的树可能在 <body> 及其他地方具有作为 <body> 子节点的“空” #text 节点。

属性是节点,但我忘记了它们不在 `childNodes` 表示的树中。使用 `childNodes` 遍历完整树将不会访问任何属性节点。
imranomar at gmail dot com
13 年前
刚刚发现 `node->nodeValue` 会去除所有标签。
metanull
10 年前
另一个将 DOMNode 转换为 php 数组的函数。
此页面上的其他函数生成的数组过于“复杂”;此函数应使数组尽可能整洁。
注意:调用 `DOMDocument::load`、`loadXML` 或 `loadHTML` 时,请确保设置 `LIBXML_NOBLANKS`。
参见:http://be2.php.net/manual/en/libxml.constants.php
参见:http://be2.php.net/manual/en/domdocument.loadxml.php

<?php
/**
* 将 DOMNode 对象转换为数组表示形式
* 注意:将 XML 加载到 DOMDocument 时,请务必使用 LIBXML_NOBLANKS 标记
* @param DOMDocument $dom
* @param DOMNode $node
* @return array
*/
function nodeToArray( $dom, $node) {
if(!
is_a( $dom, 'DOMDocument' ) || !is_a( $node, 'DOMNode' )) {
return
false;
}
$array = false;
if( empty(
trim( $node->localName ))) {// 丢弃空节点
return false;
}
if(
XML_TEXT_NODE == $node->nodeType ) {
return
$node->nodeValue;
}
foreach (
$node->attributes as $attr) {
$array['@'.$attr->localName] = $attr->nodeValue;
}
foreach (
$node->childNodes as $childNode) {
if (
1 == $childNode->childNodes->length && XML_TEXT_NODE == $childNode->firstChild->nodeType ) {
$array[$childNode->localName] = $childNode->nodeValue;
} else {
if(
false !== ($a = self::nodeToArray( $dom, $childNode))) {
$array[$childNode->localName] = $a;
}
}
}
return
$array;
}
?>
[email protected]
10 年前
回复: [email protected] 关于 “#text” 节点。
当结束标签和下一个起始标签之间存在空格或换行符时,会出现 “#text” 节点。

例如 “<data><age>10</age>[空格]<other>20</other>[空格]</data>”

“data” 的 childNodes 有 4 个子节点
- age = 10
- #text = 空格
- other = 20
- #text = 空格
[email protected]
15 年前
显然还有一个 setAttribute 方法

$node->setAttribute( 'attrName' , 'value' );
[email protected]
11 年前
这是一个可以将 DomNode 截断到指定文本字符数的小函数。我用它为我的博客文章生成 HTML 摘要。

<?php

function makehtmlexcerpt(DomNode $html, $excerptlength)
{
$remove = 0;
$htmllength = strlen(html_entity_decode($html->textContent, ENT_QUOTES, 'UTF-8'));
$truncate = $htmllength - $excerptlength;
if(
$htmllength > $excerptlength)
{
if(
$html->hasChildNodes())
{
$children = $html->childNodes;
for(
$counter = 0; $counter < $children->length; $counter ++)
{
$child = $children->item($children->length - ($counter + 1));
$childlength = strlen(html_entity_decode($child->textContent, ENT_QUOTES, 'UTF-8'));
if(
$childlength <= $truncate)
{
$remove ++;
$truncate = $truncate - $childlength;
}
else
{
$child = makehtmlexcerpt($child, $childlength - $truncate);
break;
}
}
if(
$remove != 0)
{
for(
$counter = 0; $counter < $remove; $counter ++)
{
$html->removeChild($html->lastChild);
}
}
}
else
{
if(
$html->nodeName == '#text')
{
$html->nodeValue = substr(html_entity_decode($html->nodeValue, ENT_QUOTES, 'UTF-8'), 0, $htmllength - $truncate);
}
}
}
return
$html;
}

?>
匿名用户
6 年前
如果具体属性的文档中提到了某些属性的只读状态,将非常有帮助。
"
ownerDocument

与该节点关联的 DOMDocument 对象。

"
[email protected]
8 年前
一个可以设置内部 HTML 而不出现编码错误的函数。$html 可以是损坏的内容,例如 “<a ID=id20>ssss”
function setInnerHTML($node, $html) {
removeChildren($node);
if (empty($html)) {
return;
}

$doc = $node->ownerDocument;
$htmlclip = new DOMDocument();
$htmlclip->loadHTML('<meta http-equiv="Content-Type" content="text/html;charset=utf-8"><div>' . $html . '</div>');
$clipNode = $doc->importNode($htmlclip->documentElement->lastChild->firstChild, true);
while ($item = $clipNode->firstChild) {
$node->appendChild($item);
}
}
To Top