DOM树定义了文档的逻辑结构,以及控制你访问和操作这些文档的方法。使用DOM,开发人员可以创建XML或HTML文档,操作它们的结果,增加、修改和删除文档 元素及内容。可以从任何编程语言访问DOM,本文使用PHP 5 DOM扩展,它是PHP核心的一部分,因此除了PHP外,不需要安装其它软件。
DOM树节点遵循XML命名规范,如:
1、Document节点 -- 表示DOMDocument接口
2、Element节点 -- 表示DOMElement接口
3、Attribute节点 -- 表示DOMAttr接口
4、Comment节点 -- 表示DOMComment接口
5、Text节点 -- 表示DOMText接口
提取元素
这一小节介绍如何从DOM树中提取元素和值,本文使用Book.xml作为例子进行说明,其内容如清单1所示。
清单1 Book.xml<?xmlversion ="1.0"encoding="UTF-8"standalone="yes"?>
XML Processing I
John Smith Jr.
HisOwnTM
111-222-333-4441
What is XML about ?XML (Extensible Markup Language) is a ...
SAXSAX is a simple API for ...
StAXMuch powerful and flexible, StAX, is very...
DOMDOM concept
Starting to use DOM...
First DOM application...Here it is your first DOM application...
The end...
第一个示例应用程序使用Book.xml文档,提取出关联的树,然后使用DOMElement接口的getElementsByTagName方法显示第一个子节点实例:
DOMNodeList DOMElement::getElementsByTagName(string $name):这个方法返回所有$name参数指定的标签名的子元素。下面的例子查找根节点 ,然后查找它的子节点 ,和 元素,选择每个子节点的第一个,最后打印这些节点的值:<?php
// 创建一个文档实例
$doc=newDOMDocument();
//载入Book.xml文件
$doc->load( 'Book.xml' );
//使用book标签名搜索所有元素
$books= $doc->getElementsByTagName( "book" );
//使用author标签名搜索所有元素
$authors= $doc->getElementsByTagName( "author" );
//返回第一个标签名为author的元素
$author= $authors->item(0)->nodeValue;
//以publisher标签名搜索所有元素
$publishers= $doc->getElementsByTagName( "publisher" );
//返回第一个找到的标签名为publisher的元素
$publisher= $publishers->item(0)->nodeValue;
//搜索标签名为name的所有元素
$titles= $doc->getElementsByTagName( "name" );
//返回标签名为name的第一个找到的元素
$title= $titles->item(0)->nodeValue;
//打印找到的值
echo "$title - $author - $publisher \n";
?>
最后一行是打印第一个标题,第一个作者,第一个出版商,使用连字符分隔,输出:
XML Processing I - John Smith Jr. - HisOwnTM
递归浏览DOM树
因为XML文档结构中一个标签可以包括另一个标签(分支树),剩下就是叶子节点,因此你可以浏览完整的树或从任何节点开始递归浏览子树 。下面的例子是从任何开始节点($node)浏览下面的XML子树,并列出节点的名字和值。functiongetNodesInfo($node)
{
if($node->hasChildNodes())
{
$subNodes=$node->childNodes;
foreach($subNodesas$subNode)
{
if(($subNode->nodeType != 3) ||
(($subNode->nodeType == 3) &&
(strlen(trim($subNode->wholeText))>=1)))
{
echo"Node name: ".$subNode->nodeName."\n";
echo"Node value: ".$subNode->nodeValue."\n";
}
getNodesInfo($subNode);
}
}
}
上面的例子使用下面的条件去除了所有空文本节点,让输出看起来更干净:if (($subNode->nodeType != 3) ||
(($subNode->nodeType== 3) &&
(strlen(trim($subNode->wholeText))>=1)))
前面的代码检查节点是否被处理,同样,你可以设置预定义的preserveWhiteSpace属性,它移除冗余的空白,默认值是TRUE。
为了测试这个功能,下面这个例子传递Book.xml文档的根节点给递归函数getNodesInfo,然后打印出整个DOM树的标签和值:<?php
//创建一个文档实例
$doc=newDOMDocument();
//载入Book.xml文件
$doc->load( 'Book.xml' );
//设置对象树根
$root= $dom->firstChild;
// 递归函数列出子树的所有节点
function getNodesInfo($node)
{
if ($node->hasChildNodes())
{
$subNodes= $node->childNodes;
foreach ($subNodes as $subNode)
{
if (($subNode->nodeType != 3) ||
(($subNode->nodeType== 3)
&&(strlen(trim($subNode->wholeText))>=1)))
{
echo "Node name: ".$subNode->nodeName."\n";
echo "Node value: ".$subNode->nodeValue."\n";
}
getNodesInfo($subNode);
}
}
}
//调用getNodesInfo函数
getNodesInfo($root);
?>
图1显示了输出的小部分内容
图- 1文档内容:这个图显示了通过getNodesInfo递归函数运行Book.xml的部分输出内容
增加新节点
DOMNode接口包括多个创建新节点和在DOM树中插入节点的方法,如果要创建一个新节点,可以使用createElement或createTextNode方法,然后 ,为了增加一个新节点到DOM树上,可以调用appendChild或insertBefore方法,appendChild方法增加一个新的子节点到特定节点的子节点列表的后面,而 insertBefore方法是在特定节点的前面插入一个节点。
下面是这些方法的原型:
1、DOMElement createElement(string $name [, string $value ]) :这个方法创建了一个DOMElement类的实例,$name参数表示新元素的标签名,$value参数 表示元素的值,你也可以稍后使用DOMElement->nodeValue属性其值。
2、DOMText createTextNode(string $content):这个方法创建了一个DOMText类的实例,$content参数表示新的文本节点的文本内容。
3、DOMNode DOMNode::appendChild(DOMNode $newnode):这个函数扩展了现有子节点末尾$newnode参数,或创建一个新的包括指定节点的子节点列表。
4、DOMNode DOMNode::insertBefore(DOMNode $newnode [,DOMNode $refnode]):这个方法在$refnode节点前插入$newnode参数,如果$refnode节点丢失,新的 节点就添加到节点的子节点列表前。
下面的例子创建了一个节点,并将其追加到节点的末尾://创建一个新元素
$newElement= $dom->createElement('bibliography','Martin Didier, Professional XML');
//使用appendChild函数将其追加到根节点
//调用appendChild函数
appendNewChild($root,$newElement);
//这个函数追加了一个新的子节点
function appendNewChild($currentNode, $node)
{
$currentNode->appendChild($node);
}
如果你通过getNodeInfo()函数运行得出结果,你将会看到如图2所示的输出。
图- 2 追加的节点:这个图显示了新加的节点和它的内容
下面的例子是在节点增加一个子节点://创建一个新的元素
$newElement= $dom->createElement('foreword',
'What I love about this book is that it '.
'grew out of just such a process, '.
'and shows it on every page.');
//设置引用节点
$allContents= $dom->getElementsByTagName('publisher');
$contents= $allContents->item(0);
//调用insertNewChild函数
insertNewChild($contents,$newElement);
//这个函数插入一个新的子节点作为 $currentNode的第一个子节点
function insertNewChild($currentNode, $node)
{
$currentNode->insertBefore(
$node, $currentNode->firstChild);
}
通过getNodesInfo运行修改后的文档,显示新的节点,如图3所示。
图- 3 插入节点:这张图片显示了在节点前插入了子节点
节点克隆
克隆一个节点意味着创建一个和当前节点一模一样的节点,克隆节点时使用cloneNode方法。
DOMNode DOMNode::cloneNode([ bool $deep]):创建当前的克隆,$deep参数指定是否要拷贝当前节点的子节点,其默认值是false。下面的示例代码显示克隆 元素,并作为源元素的子节点,图4显示了输出内容://设置引用节点
$author= $root->getElementsByTagName('author')->item(0);
//调用cloningNode函数
cloningNode($author);
//这个函数克隆$currentNode
function cloningNode($currentNode)
{
$clonenode= $currentNode ->cloneNode(true);
$newnode= $currentNode->appendChild($clonenode);
}
图- 4 克隆节点:克隆子节点并将其放在源节点下,源节点的文本值变成两份了,因为检索节点的文本值时也检索了其子节点的 值
移除子节点
使用removeChild方法从DOM树中移除子节点。
DOMNode DOMNode::removeChild(DOMNode $oldnode):这个函数移除一个子节点,$oldnode参数指出要移除的子节点。下面的示例代码从Book.xml文档中移除子 节点,从图5中显示的输出内容可以看到bibliography节点消失了。
图- 5 移除节点:移除最后一个子节点后,重新列出了节点的名称值,显示节点确实被移除了
替换节点
为了用一个新节点替换已有的节点,使用replaceChild方法。
DOMNode DOMNode::replaceChild(DOMNode $newnode, DOMNode $oldnode):这个函数使用$newnode子节点替换$oldnode节点。
例如,假设你想用新的code子节点替换ISBN子节点://获取ISBN节点
$element= $dom->getElementsByTagName('ISBN')->item(0);
//创建新的元素
$code= $dom->createElement('code', '909090');
//调用replacingNode函数
replacingNode($code,$element);
//这个函数使用$node替换$currentNode
function replacingNode($currentNode, $node)
{
$node->parentNode->replaceChild($currentNode, $node);
}
图6中显示的输出内容表明节点被替换了
图- 6 替换节点:这里显示的是用新的节点替换节点后的文档内容
导入节点
使用importNode方法从另一个树拷贝一个节点到当前的树。
DOMNode DOMDocument::importNode(DOMNode $importedNode [,bool $deep]):这个方法从另一个XML文档导入一个节点,然后插入当前文档的DOM树中, $importedNode参数指出了要导入的节点,导入的节点表示原始节点的一份拷贝,因此导入操作不会修改外部树,$deep参数控制是否导入被导入节点的深度,值为 TRUE时,导入完整的节点子树,为FALSE时,只导入节点本身。
下面的示例从Book_continue.xml文件导入节点到Book.xml,下面是Book_continue.xml文档的内容:<?xmlversion ="1.0"encoding="UTF-8"standalone="yes"?>
XPathXPath is language for...
This chaper is a bonus to...
]]>
cap_II="click_here_for_chapter_II"
cap_III="click_here_for_chapter_III"
cap_IV="click_here_for_chapter_IV"
cap_V="click_here_for_chapter_V"/>
下面是导入节点的代码:
$olddoc=newDOMDocument;
$olddoc->load("Book_continue.xml");
//我想导入到一个新文档的节点
$node= $olddoc->getElementsByTagName("continue")->item(0);
$newnewdoc= new DOMDocument;
$newdoc->formatOutput=true;
$newdoc->load("Book.xml");
//导入节点及其所有子节点到文档
$node= $newdoc->importNode($node, true);
//然后追加到根节点
$newdoc->documentElement->appendChild($node);
echo "\nThe 'new document' after copying the nodes into it:\n";
$root= $newdoc->firstChild;
function getNodesInfo($node)
{
if ($node->hasChildNodes())
{
$subNodes= $node->childNodes;
foreach ($subNodes as $subNode)
{
if (($subNode->nodeType != 3) ||
(($subNode->nodeType==3) &&
(strlen(trim($subNode->wholeText))>=1)))
{
echo "Node name: ".$subNode->nodeName."\n";
echo "Node value: ".$subNode->nodeValue."\n";
}
getNodesInfo($subNode);
}
}
}
getNodesInfo($root);
?>
图7显示前面代码的输出
图- 7 导入节点:这里显示了从Book_continue.xml导入节点并追加到Book.xml后的样子
检查节点的等同性
检查两个节点是否相同使用isSameNode方法。
bool DOMNode::isSameNode(DOMNode $node):当节点是相等的时候,这个函数返回一个布尔值TRUE,否则返回FALSE,$node参数表示你要和当前节点进行比较 的节点。
注意比较不是基于节点的内容进行的://检查两个节点是否相同
$author1= $root->getElementsByTagName('autor')->item(0);
$author2= $root->getElementsByTagName('autor')->item(1);
//调用verifyNodes函数
verifyNodes($author1,$author2);
function verifyNodes($currentNode, $node)
{
if (($currentNode->isSameNode($node))==true)
{
echo "These two nodes are the same";
}
}
创建新的树
PHP 5 DOM扩展可以让你从零开始构建DOM树,下面的示例创建了一个全新的XML文档,使用了两个新函数创建注释和CDATA节点。
1、DOMComment DOMDocument::createComment(string $data):创建一个新的注释节点,$data参数表示节点的内容。
2、DOMCDATASection DOMDocument::createCDATASection(string $data):创建一个新的CDATA节点,$data参数表示节点的内容。<?php
//创建一个文档实例
$document=newDOMDocument();
//使用缩进格式化输出
$document->formatOutput=true;
//创建一个注释
$comment= $document->createComment('Beautiful flowers!!!');
$document->appendChild( $comment );
//创建根元素
$root= $document->createElement( 'flowers' );
$document->appendChild( $root );
//创建子节点
$tulips= $document->createElement( 'tulips' );
//创建元素的第一个子节点,并设置其属性
$bulbs_1= $document->createElement( 'bulbs' );
$bulbs_1->setAttribute('price','� 7.65');
$bulbs_1->appendChild($document->createTextNode( 'Parrot'));
$tulips->appendChild( $bulbs_1 );
//创建元素的第二个子节点,并设置其属性
$bulbs_2= $document->createElement( 'bulbs' );
$bulbs_2->setAttribute('color','magenta');
$bulbs_2->appendChild($document->createTextNode( 'Lily flowering' ));
$tulips->appendChild( $bulbs_2 );
//追加节点到根节点后
$root->appendChild( $tulips );
//创建CDATA小节
$cdata= $document->createCDATASection(
'Sword Lily'.
'Starface');
$document->appendChild( $cdata );
//保存对象树到Flowers.xml
echo $document->saveXML();
$document->save('Flowers.xml');
?>
新的Flower.xml文档内容如下:
Parrot
Lily flowering
[
Sword Lily
Starface
]]>
清单2中的代码创建了一个对象树,并将其保存为Flowers.xml。
清单2 创建一个新的DOM树
本文简单介绍了PHP 5 DOM扩展,并介绍如何使用它操作XML(或HTML)文档,以及如何从零创建一个DOM树。
【编辑推荐】
点赞 0