[转]php使用DOM处理xml文档
2008-05-31 18:35
851 查看
访问树中节点
树中节点的访问不限制在往下一级,你可以访问当前节点的兄弟节点,父节点,甚至任何一个可能被访问到的节点。访问子节点
子节点是当前节点的直接后代。简而言之,所有直接处于当前节点的下一级别的节点都是当前节点的子节点。例如,一个元素节点可能有包含(并不局限于此)注释节点,文本节点和一些其它的元素节点。属性节点只有一个子节点,这个子节点是一个包含属性节点的值的文本节点。文档节点可以包含注释节点,PIs金额一个单独的元素节点来作为子节点。子节点的类型很多时候是由当前节点决定的。可以使用hasChildNodes()方法来检查一个节点是否包含子节点,这个方法将返回一个布尔值来表明该节点是否有子节点。
可以用childNodes属性返回一个包含所有子节点的DOMNoteList对象。DOMNoteList是一个可以循环的对象。可以使用item属性来取得一个DOMNoteList中的一个特定的节点或者利用PHP中的循环函数来访问。比如
if ($root->hasChildNodes()) {
$children = $root->childNodes;
foreach($children as $node) {
print $node->nodeName."/n";
}
}
这段代码先返回了文档节点$root的子节点,然后利用foreach来遍历DOMNodeList对象。输出结果如下
#text
bookinfo
#text
preface
#text
chapter
#text
book元素包含了三个子原属,而且也包含了一些换行符或制表符之类的空白,这些空白在加载XML的时候没有去掉,因此输出结果中有#text。如何在没有去掉XML空白的情况下在结果中去掉#text呢,nodeType属性派上用场了。例如:
foreach($children as $node) {
if ($node->nodeType != XML_TEXT_NODE) {
print $node->nodeName."/n";
}
}
这样就可以去掉那些文本节点(text node),输出结果也没有#text字符了。
———————————————–
接下来不翻译了,改成笔记,翻译的废话太多了 >. 读者可自己运行代码后思考一下,这样更容易上手 ^^
———————————————–
访问特定节点
如果要访问特点节点可以使用节点的标签名。可使用的方法有getElementsByTagName()和getElementsByTagNameNS(),被访问的节点只能包含在文档节点(document node)和元素节点(element node)中,也就是说,要访问的节点必须是基于DOMDocument或DOMElement类。比如文档节点$dom,可以用getElementsByTagName()方法来取得文档中的所有title节点:
$elements = $dom->getElementsByTagName("title");
$length = $elements->length;
for ($x=0;$x < $length;$x++) {
print "Element Value: ".$elements->item($x)->nodeValue."/n";
}
getElementsByTagName()返回了一个DOMNodeList对象$elements,包含了$dom领域内的所有title元素。length属性返回了DOMNodeList对象中元素的个数。
可以使用通配符*作为参数来取得所有的元素:
$preface = $root->getElementsByTagName("preface");
$elements = $preface->item(0)->getElementsByTagName("*");
$length = $elements->length;
for ($x=0;$x < $length;$x++) {
print "Element Name: ".$elements->item($x)->nodeName."/n";
print "Element Value: ".$elements->item($x)->nodeValue."/n";
}
这段代码通过文档元素$root以一个DOMNodeList对象返回了$root之内的所有preface元素并赋值给$preface。接着,返回取得的DOMNodeList对象中的第一个值,然后直接执行getElementsByTagName(”*”)。所有$preface内的元素都以DOMNodeList对象返回到$elements中。最后利用for循环输出所有的元素名称及元素值。输出结果如下:
Element Name: title
Element Value: The DOM Tree
Element Name: para
Element Value: An example DOM Tree using DocBook.
在处理有命名空间的文档时,可以使用getElementsByTagNameNS()方法来返回指定的命名空间的元素。这个方法有两个参数,第一个是命名空间URI,第二个是元素标签的名称。命名空间URI参数也支持通配符*。可以用通配符来取得任一个命名空间的所有元素:
$result = $dom->getElementsByTagNameNS("*", "*");
这行代码返回了一个DOMNodeList对象$result,返回了文档中有命名空间的所有元素。
访问属性(Accessing Attributes)
跟其它节点类型一样,节点的属性(attribute)继承了DOMNode类中的方法和属性(property),但是不能像其它节点一样访问它。
可以用hasAttributes()方法来检查一个节点是否有属性,用attributes属性(property)来取得节点的所有属性, hasAttributes()和attributes都是在DOMNode类中定义的,因此可以在所有的节点中使用,但是只有在DOMElement对象中是由才会返回有意义的值。
if ($root->hasAttributes()) {
$attributes = $root->attributes;
foreach($attributes as $attr) {
print "Attribute Name: ".$attr->nodeName."/n";
print "Attribute Value: ".$attr->nodeValue."/n";
}
}
在这段代码中,如果$root所指代的节点存在属性的话hasAttributes()返回true,接着利用attributes属性返回一个DOMNamedNodeMap对象给$attributes。DOMNamedNodeMap跟DOMNodeList一样,对是可以循环的。输出结果如下:
Attribute Name: lang
Attribute Value: en
与DOMNodeList不同的是DOMNamedNodeMap可以使用名称来访问,而不只是使用位置。比如:
$attr = $attributes->getNamedItem("lang");
print "Attribute Name: ".$attr->nodeName."/n";
print "Attribute Value: ".$attr->nodeValue."/n";
if ($attributes->length > 0) {
$attr = $attributes->item(0);
print "Attribute Name: ".$attr->nodeName."/n";
print "Attribute Value: ".$attr->nodeValue."/n";
}
这两段代码输出结果是一样的。
访问特定属性
用DOMNameNodeMap对象来访问属性只是访问属性的方法之一。DOMElement类提供了一些用来访问指定属性的方法,getAttribute(), getAttributeNode(), getAttributeNS(), and getAttributeNodeNS()
/* Access lang attribute value directly */
print "Attribute Value: ".$root->getAttribute("lang")."/n";
/* Return the lang attribute node and access the returned attribute node */
$attr = $root->getAttributeNode("lang");
print "Attribute Value: ".$attr->nodeValue."/n";
这两段代码的输出结果是一样的。第一段代码返回了lang属性后直接输出;第二段代码先返回lang属性节点,接着输出节点值。
尽管Listing 6-1 中的文档没有使用命名空间,但是还是可以使用命名空间的方法来访问。
print "Attribute Value: ".$root->getAttributeNS(NULL, "lang")."/n";
$attr = $root->getAttributeNodeNS(NULL, "lang");
print "Attribute Value: ".$attr->nodeValue."/n";
第一个参数是要访问的命名空间URI,因为Listing 6-1没有命名空间,因此指定为NULL。
创建和编辑树
文档节点(Document Nodes)
本章早些时候介绍了几种创建DOMDocument对象的方法。创建的对象包含一个文档类型声明,你可以使用DOMImplementation累来创建一个DOMDocument对象,首先创建一个DOMDocType对象来作为DOMImplementation的参数。 DOMImplementation对象中的方法可以使用静态方式访问。比如:
$doctype = DOMImplementation:: createDocumentType("book",
"-//OASIS//DTD DocBook XML V4.1.2//EN",
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd");
$dom = DOMImplementation:: createDocument(NULL, "book", $doctype);
指定编码
$dom->encoding = "UTF-8";
指定编码只影响输出的文档,不影响创建文档过程中的文档编码。
元素节点
创建元素
有两种方法可以用来创建元素,一是使用DOMDocument对象中createElement()和createElementNS()方法,二是利用DOMElement直接实例化一个DOMElement对象。
创建一个bookinfo元素
$bookinfo = $dom->createElement("bookinfo");
这段代码返回了一个名为”bookinfo”的DOMElement对象类型元素给$bookinfo变量。
也可以创建一个包含内容的元素
$bititle = $dom->createElement("title", "DOM in PHP 5");
虽然已经创建了两个元素,但是它们跟文档没有直接关系,是独立的两个元素。
创建一个带有命名空间的元素
$biauthor = $dom->createElementNS(NULL, "author");
$trash = $dom->createElementNS("http://www.example.com/trash", "tr:trash");
直接实例化DOMElement对象来创建元素
$firstname = new DOMElement("firstname", "Rob");
$surname = new DOMElement("surname", "Richards");
$nsElement = new DOMElement("nse:myelement", NULL, "http://www.example.com/ns");
第三行代码的NULL说明不指定值给所创建的元素。
插入元素节点
插入元素节点的方法是从DOMNode类继承的,它们不仅可以用于元素节点,还可以用于其它类型的节点。
$dom->documentElement->appendChild($bookinfo);
appendChild()方法有一个被用来指定为子节点的对象作参数,并返回所创建的节点。新插入的节点作为当前节点的最后一个子节点插入。
在插入author元素前可以先在author元素中插入firstname和surname节点。当将author节点插入文档树中时,firstname和surname也被插入文档中:
$biauthor->appendChild($surname);
$biauthor->insertBefore($firstname, $surname);
上面的代码也可以这么写
$biauthor->appendChild($firstname);
$biauthor->appendChild($surname);
然后将author插入bookinfo节点:
$bookinfo->appendChild($biauthor);
属性节点
可以使用DOMElement中的方法操作属性节点,使用DOMDocument中的方法来直接实例化一个属性节点或使用DOMElement中的方法来创建,也可以使用DOMNode和DOMElement中的方法来插入和移动属性节点。
使用DOMDocument中的createAttribute方法创建属性节点
/* Equivalent methods for creation of lang attribute */
$lang = $dom->createAttribute("lang");
$lang = $dom->createAttributeNS(NULL, "lang");
使用这种方法创建必须另外再给属性赋值,可以使用DOMElement中的nodeValue属性或DOMAttr中的value属性来指定一个值,如:
/* Equivalent calls to set the value for the lang attribute to "en" */
$lang->nodeValue = "en";
$lang->value = "en";
使用DOMAttr创建一个属性节点对象,并直接赋值:
$lang = new DOMAttr("lang", "en");
创建好的属性节点可以想插入元素节点一样插入到一个节点中,但插入的结果不是插入一个子节点,而是一个属性:
/* Equivalent methods for inserting an attribute */
$bookinfo->appendChild($lang);
$bookinfo->insertBefore($lang, NULL);
也可以使用DOMElement中的setAttributeNode()和setAttributeNodeNS()方法在一个节点中插入一个属性。这两个方法必须有一个DOMAtrr对象类型的属性节点作为参数。
/* Equivalent calls for this document as no namespaces are being used */
$oldlang = $bookinfo->setAttributeNode($lang);
$oldlang = $bookinfo->setAttributeNodeNS($lang);
DOMElement类有两个可以直接给一个节点创建属性的方法,setAttribute()和setAttributeNS()。利用这两个方法可以在不创建DOMAttribute对象的情况下就创建一个属性:
/* Equivalent calls to create the lang attribute with value "en" */
$bookinfo->setAttribute("lang", "en");
$bookinfo->setAttributeNS(NULL, "lang", "en");
文本节点
文本节点非常简单,因为它们没有子节点和属性,也就是说它们只包含文本。
创建和插入文本节点
可以利用DOMDocment对象的createTextNode()方法来创建一个文本节点:
/* Equivalent creation of DOMText objects */
$yeartxt = $dom->createTextNode("2005");
$yeartxt = new DOMText("2005");
可以在一行代码中创建节点并将节点插入元素,最后返回创建的节点:
/* Create and Append a copyright element */
$copyright = $bookinfo->appendChild(new DOMElement("copyright"));
下面的代码实现了跟上一段代码一样的功能:
/* Create year element */
$year = $dom->createElement("year");
/* Append text node to set content */
$year->appendChild($yeartxt);
$copyright->appendChild($year);
另外一种创建文本节点的方法:
/* Append a newly created holder element with content "Rob Richards" */
$copyright->appendChild(new DOMElement("holder", "Rob Richards"));
处理文本
DOMText类是从DOMCharacterData类派生出来的,因此,这两个类中的方法都可以用来处理文本。
/* If content is not whitespace then ... */
if (! $yeartxt->isElementContentWhitespace()) {
/* Print substring at offset 1 and length 2: 00 */
print $yeartxt->substringData(1,2)."/n";
/* Append the string -2006 to the content and print output: 2005-2006 */
$yeartxt->appendData("-2006");
print $yeartxt->nodeValue."/n";
/* Delete content at offset 4 with length of 5 and print output: 2005 */
$yeartxt->deleteData(4,5);
print $yeartxt->nodeValue."/n";
/* Insert string "ABC" at offset 1 and print output: 2ABC005 */
$yeartxt->insertData(1, "ABC");
print $yeartxt->nodeValue."/n";
/* Replace content at ofset 1 with length of 3 with an empty string: 2005 */
$yeartxt->replaceData(1, 3, "");
print $yeartxt->nodeValue."/n";
}
现在,上面所有对节点的操作创建了一个如下所示的XML文档:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
<book>
<bookinfo lang="en">
<title>DOM in PHP 5</title>
<author>
<firstname>Rob</firstname>
<surname>Richards</surname>
</author>
<copyright>
<year>2005</year>
<holder>Rob Richards</holder>
</copyright>
</bookinfo>
</book>
其它类型的节点
/* Create a DOMDocumentFragment */
$frag = $dom->createDocumentFragment();
$frag = new DOMDocumentFragment();
/* Create DOMComment */
$comment = $dom->createComment("this is a comment");
$comment = new DOMComment("this is a comment");
/* Results in <!-- this is a comment --> */
/* Create DOMCDATASection */
$cdata = $dom->createCDATASection("<html></html");
$cdata = new DOMCDATASection("<html></html");
/* Results in <![CDATA[<html></html]]> */
/* Create DOMProcessingInstruction */
$pi = $dom->createProcessingInstruction("php", "echo 'Hello World';");
$pi = new DOMProcessingInstruction("php", "echo 'Hello World';");
/* Results in <?php echo 'Hello World';?> */
/* Create DOMEntityReference */
$entityref = $dom->createEntityReference("lt");
$entityref = new DOMEntityReference("lt");
/* Results in < */
$frag = $dom->createDocumentFragment();
$frag->appendChild(new DOMElement("node1", "node1 value"));
$frag->appendChild(new DOMElement("node2", "node2 value"));
$frag = $dom->createDocumentFragment();
$frag->appendXML("<node1>node1 value</node1><node2>node2 value</node2>");
移除和替代节点
之前已经有一个方法setAttributeNode()可以用来移除和替代节点,如果有一个旧的节点跟新的节点同名的话, setAttributeNode()将移除旧的节点并以新的节点替代它,这只在属性类型的节点上奏效。对于其它节点可以使用replaceChild ()和removeChild()方法来实现。
首先创建一个文档:
$doc = DOMDocument::loadXML('<?xml version="1.0"?>
<root>
<child1>child1 content</child1>
<child2>child2 content</child2>
<child3>child3 content</child3>
</root>');
接着要把child2元素删除,并把child3元素用newchild元素替代。第一步是取得这些元素。
$root = $doc->documentElement;
$child2 = $root->getElementsByTagName("child2")->item(0);
$child3 = $root->getElementsByTagName("child3")->item(0);
接着删除$child2对象:
$root->removeChild($child2);
这时候XML文档将会变成如下的结构:
<?xml version="1.0"?>
<root>
<child1>child1 content</child1>
<child3>child3 content</child3>
</root>
在文档中会留出原来元素所占用的行。接着创建一个newchild元素来替代child3。
$oldchild = $root->replaceChild(new DOMElement("newchild", "new content"), $child3);
这样,XML文档变成如下结构:
<?xml version="1.0"?>
<root>
<child1>child1 content</child1>
<newchild>new content</newchild>
</root>
那一行空白也是一个节点,可以用下面的代码删除:
$children = $root->childNodes;
for ($x=$children->length; $x--; $x>=0) {
$node = $children->item($x);
if ($node->nodeType == XML_TEXT_NODE && $node-> isElementContentWhitespace()) {
$root->removeChild($node);
}
}
使用XPath
从PHP5.0开始,可以使用DOMXPath对象的query()方法返回一个包含节点的DOMNodeList对象。PHP5.1开始提供了一个evaluate()方法,它可以返回更多类型的节点对象。
实例化DOMXPath
使用new关键字创建一个DOMXPath对象,并传入一个DOMDocument对象类型的参数。
$domxpath = new DOMXPath($dom);
使用query()方法
PHP5的所有版本都有query()方法,可以利用这个方法和XPath表达式从树形结构获取一些节点,以DOMNodeList对象的形式返回,如果没有获取到任何一个节点就返回一个空的DOMNodeList。可以将一个XPath表达式作为一个参数传给query()方法,比如:
$list = $domxpath->query("/book/bookinfo/author");
$author = $list->item(0);
$list = $domxpath->query("surname", $author);
$surname = $list->item(0);
如果你试图利用XPath表达式返回一个字符串,你会发现返回的是一个空的DOMNodeList对象:
$list = $domxpath->query("string('/book/bookinfo/author/surname')");
var_dump($list);
print "Number of Nodes Returned: ".$list->length."/n";
length返回0。
使用evaluate()方法
PHP5.1开始增加了evaluate()方法,可以像query()方法一样使用它。
$list = $domxpath->evaluate("string(/book/bookinfo/author/surname)");
var_dump($list);
var_dump()函数输出string(8) “Richards”。说明evaluate()方法实现了query()所不能实现的功能。
evaluate()方法返回值的类型很多,有Boolean,Integer,String,Null和DOMNodeList,返回什么类型的值取决于使用你所使用的XPath表达式,如:
$newyear = $domxpath->evaluate("number(/book/bookinfo/copyright/year) + 1");
var_dump($newyear);
像query()方法一样,evaluate()可以返回一个包含多个节点的DOMNodeList对象,如:
$list = $domxpath->evaluate("/book/bookinfo/author");
$author = $list->item(0);
print $author->nodeName."/n";
来源:http://blog.csdn.net/guoguo1980/archive/2008/05/12/2436299.aspx
相关文章推荐
- php使用DOM处理xml文档
- php使用 DOM 创建xml文档
- 在VC6中使用MSXML 4.0 DOM处理XML文档
- 在VC6中使用MSXML 4.0 DOM处理XML文档
- PHP使用DOM和simplexml读取xml文档的方法示例
- 在VC6中使用MSXML 4.0 DOM处理XML文档
- PHP使用DOM XML操作XML[总结]
- Android -使用DOM(文档对象模型)解析XML文件
- android中使用SAX, DOM, 或者pull 来解析XML文档
- Php Xml解析之DOMDocument使用方法
- 使用JAXB处理XML文档——先睹为快
- 使用PHP DOM-XML创建和解析XML文件
- 使用 SAX 处理 XML 文档
- 处理XML文档的DOM元素属性和方法
- Java中使用DOM方式解析和创建XML文档、及dom4j使用简介
- php中处理xml的文档方法
- 处理及遍历XML文档DOM元素属性及方法整理
- 使用JAXB处理XML文档——先睹为快
- php下使用SimpleXML 处理XML 文件
- 使用 SAX 处理 XML 文档(转载)