XML解析器可分爲兩大類:(1).基於事件驅動的XML解析器。(2).基於樹的解析器。
在上一篇文章中,我們淺談了一種典型的基於事件驅動的XML解析器——SAX解析器。今天來看看第二種,基於樹的解析器。
與第一種解析器相比,基於樹的解析器能夠一次性分析整個XML文檔,並且把分析結果保存在一個樹狀結構中,並提供一組API來訪問這個樹狀結構。
典型的基於樹的XML解析器有:DOM解析器、SimpleXML解析器等等。
DOM(document object model)即文檔對象模型.DOM是一組創建和編輯XML文檔的標準編程接口,我們可以通過DOM動態地對XML文檔進行各種處理。除此之外,DOM是一個與平臺無關和組織結構無關的模型,DOM解析器讀取XML文檔,並且將它劃分爲各種對象:元素對象、屬性對象和註釋對象等等。DOM解析器爲XML文檔的每一個元素創建一個樹狀結構,因爲它能夠快速搜索XML文檔的任何元素。
但因DOM需要佔據大量的內存,所以適合處理較小的XML文檔。
DOM提供了各種內置的類,用於在PHP中解析XML文檔。
1.DOMDocument類
DOMDocument類派生於DOMNode基類,以下是用DOMDocument類對XML文檔進行各種操作。
創建文檔對象
例如:
$dom=new DOMDocument('1.0','UTF-8');//創建文檔對象
兩個參數分別表示XML文檔的版本號、文檔的字符編碼。
裝入XML文檔
有兩種方法:
$dom->load('Student.xml',LIBXML_NOBLANKS);//將XML文檔裝入到文檔對象中,並刪除所有的空白符
$xml='<?xml version="1.0" encoding="UTF-8"?><root><child></child></root>';
$dom->loadXML($xml);
前一個方法第一個參數爲XML文檔的文件名或者路徑,第二個方法的參數表示包含XML文檔的字符串。LIBXML_NOBLANKS常量表示刪除對象樹中的所有空白符。
輸出DOMDocument對象內容
也有兩種方法:
$dom->save('demo1.xml');//輸出對象內容,以demol.xml的形式保存
$xmldata='<?xml version="1.0" encoding="UTF-8"?><root><child></child></root>';
$dom->loadXML($xmldata);
print $dom->saveXML();
save()方法將DOM對象樹內容輸出到由參數指定的文件中,返回值是保存到文件的字節數。
saveXML()方法將DOM對象樹內容輸出到一個字符串中,執行成功則返回一個XML字符串,失敗則返回FALSE值。
格式化文檔
$dom->formatOutput=true;//格式化文檔
讀取XML文檔的根元素
$root=$dom->documentElement;//讀取根元素
創建元素節點對象
$root=$dom->createElement('STUDENTDETALL');//創建元素節點對象
$dom->appendChild($root);//將元素節點對象加到文檔對象中去
$child=$dom->createElement('employee');//創建元素節點對象
$root->appendChild($child);//將元素節點對象加到另外一個元素節點對象中,成爲它的子元素
創建屬性節點
$attr1=$dom->createAttribute('ID');//創建屬性節點對象
$attr1->value="S0001";//設置屬性的值
$name->appendChild($attr1);//將屬性節點對象加到元素節點對象中
2.DOMNode類
DOMNode類是DOM API中大多數類的基類,提供了幾個公共函數,不能作爲單獨的類來使用。它提供的方法和屬性可以用於派生於該類的子類。
常見的DOMNode屬性有:nodeType、childNodes、nodeValue、nodeName等等,這裏就不一一舉例說明它們了。
常見的節點類型常量有:XML_ELEMENT_NODE、XML_TEXT_NODE、XML_ATTRIBUTE_NODE等等。可以使用這些常量來判定元素節點的類型。
例如:
foreach($children as $child){//遍歷根節點下的所有子節點的集合,格式:foreach(數組名 as 下標名)
if($child->nodeName=="STUDENTDETALL")
{
foreach($child->childNodes as $student) {//遍歷<STUDENTDETALL>節點下所有子節點的集合
if ($student->nodeName == "STUDENT") {
foreach ($student->childNodes as $name) {//遍歷<STUDENT>節點下所有子節點的集合
if ($name->nodeType == XML_ELEMENT_NODE) { //如果子節點的類型爲元素節點
$ts = $name->getAttribute("ID");//獲取該元素節點屬性名爲ID的屬性值
if ($ts == $id) {//將獲取的屬性值與傳入的參數做比較
/**若相符,則返回至此元素節點所屬的根節點下的子節點(即<STUDENTDETALL>節點)
* 並在此基礎上刪除相應的<STUDENT>節點
*/
$child->removeChild($student);
}
}
}
}
}
}
}
DOMNode類的常用方法有:appendChild()、hasAttributes()、removeChild()等等。這裏也不一一介紹了,在後邊的例子中會具體用到。
3.DOMElement類
DOMElement類派生於DOMNode類,用來定義XML文檔的元素,一個DOMElement對象代表XML文檔的一個元素。
4.DOMText類
文本節點是簡單節點,只包含文本內容,不含有子節點和屬性,利用DOMText類,可以表示XML文檔的字符數據。
除此之外還有·DOMNodeList類、DOMAttr類等等,這裏就不一一講解了。
利用以上類和方法,我們可以對XML文檔進行基本的操作。
例如:
1.輸出XML文檔裏的每條信息
/**
* 該程序以樹狀結構輸出XML文檔中的信息
*/
$xmlfile="newStudent.xml";
$dom=new DOMDocument();
$dom->load($xmlfile,LIBXML_NOBLANKS);//裝入XML文檔
$root=$dom->documentElement;//讀取根元素
$children=$root->childNodes;//獲取當前元素的下一級子節點集(STUDENTDETALL的子節點集)
$count = 1;//記錄元素數量
printTree($children);//調用函數輸出XML文檔信息
echo "XML文檔中的元素個數爲:$count";
function printTree($nodeCollection){
global $count;//設置全局變量,記錄元素的個數
echo "<ul>";
for ($x = 0; $x < ($nodeCollection->length); $x++) {
$count++;
$node = $nodeCollection->item($x);//逐個獲取子節點集的每一個元素
echo "<li>";
switch ($node->nodeType) {
case XML_ELEMENT_NODE://元素節點
print "元素:" . $node->nodeName;
if ($node->nodeName == "NAME") { //若元素名爲NAME則同時輸出它的屬性值
$id = $node->getAttribute("ID");
print ",ID屬性:" . $id . "\n";
}
break;
case XML_ATTRIBUTE_NODE://屬性節點
print "屬性名:" . $node->nodeName;
print "屬性值:" . $node->nodeValue . "\n";
break;
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
print "內容:" . $node->nodeValue . "\n";
break;
default:
print "其他節點名:" . $node->nodeName . "\n";
}
if($node->childNodes!=null) {//判斷當前元素的下一級子節點集是否爲空,不爲空則繼續遞歸
printTree($node->childNodes);
}
}
echo "</ul>";
}
2.往XML文檔裏增加信息
$xmlfile="testStudent.xml";
Addbook($xmlfile,"S0003","徐峯","22","廣州市","數據分析師");
function Addbook($xml,$id,$sname,$sage,$saddress,$sdepartment){
$dom=new DOMDocument();
$dom->formatOutput=true;
$dom->load($xml,LIBXML_NOBLANKS);
$root=$dom->documentElement;
$children=$root->childNodes;
foreach($children as $child){
if($child->nodeType==XML_ELEMENT_NODE)
{
if($child->nodeName=="STUDENTDETALL")
{
$newchild=$dom->createElement("STUDENT");
$name=$dom->createElement("NAME");
$name->setAttribute("ID",$id);
$nametext=$dom->createTextNode($sname);
$name->appendChild($nametext);
$age=$dom->createElement("AGE");
$agetext=$dom->createTextNode($sage);
$age->appendChild($agetext);
$address=$dom->createElement("ADDRESS");
$addresstext=$dom->createTextNode($saddress);
$address->appendChild($addresstext);
$department=$dom->createElement("DEPARTMENT");
$departmenttext=$dom->createTextNode($sdepartment);
$department->appendChild($departmenttext);
$newchild->appendChild($name);
$newchild->appendChild($age);
$newchild->appendChild($address);
$newchild->appendChild($department);
$child->appendChild($newchild);
}
}
}
$dom->formatOutput=true;
$dom->encoding="UTF-8";
$url="newStudent.xml";
$dom->save("newStudent.xml");
return $url;
}
3.利用DOM刪除XML文檔
$xmlfile="newStudent.xml";
print(deleteinfo($xmlfile,"S0003"));
function deleteinfo($xml,$id){
$dom=new DOMDocument();
$dom->load($xml,LIBXML_NOBLANKS);
$root=$dom->documentElement;
$children=$root->childNodes;
foreach($children as $child){//遍歷根節點下的所有子節點的集合,格式:foreach(數組名 as 下標名)
if($child->nodeName=="STUDENTDETALL")
{
foreach($child->childNodes as $student) {//遍歷<STUDENTDETALL>節點下所有子節點的集合
if ($student->nodeName == "STUDENT") {
foreach ($student->childNodes as $name) {//遍歷<STUDENT>節點下所有子節點的集合
if ($name->nodeType == XML_ELEMENT_NODE) { //如果子節點的類型爲元素節點
$ts = $name->getAttribute("ID");//獲取該元素節點屬性名爲ID的屬性值
if ($ts == $id) {//將獲取的屬性值與傳入的參數做比較
/**若相符,則返回至此元素節點所屬的根節點下的子節點(即<STUDENTDETALL>節點)
* 並在此基礎上刪除相應的<STUDENT>節點
*/
$child->removeChild($student);
}
}
}
}
}
}
}
$dom->formatOutput=true;
$xmlnewfile=$dom->saveXML();
$dom->save("afterdelete.xml");
return $xmlnewfile;
}
4.在XML文檔中查詢相應的信息
$xmlfile="newStudent.xml";
selectinfo($xmlfile,"黃浩");
//讀取某節點下所有子文本節點的內容
function get($domnode){
$content='';
foreach($domnode->childNodes as $child){
if($child->nodeType==XML_TEXT_NODE){
$content.=$child->nodeValue;
}
}
return $content;
}
//查詢XML文檔中相應的信息
function selectinfo($xml,$sname)
{
$dom = new DOMDocument();
$dom->load($xml);
$root = $dom->documentElement;
/**
* 對根節點<PERSON>下的子節點進行遍歷
*/
foreach ($root->childNodes as $element) {
if ($element->nodeType == XML_ELEMENT_NODE && $element->nodeName == "STUDENTDETALL") {
/**
* 對<STUDENTDETALL>下的子節點進行遍歷
*/
foreach ($element->childNodes as $student) {
if($student->nodeType==XML_ELEMENT_NODE && $student->nodeName == "STUDENT"){
$cl = false;//將變量初值置爲false,表示未找到信息
/**
* 對<STUDENT>下的子節點進行遍歷,如果根據子節點類型和名稱的不同進行不同的操作
*/
foreach($student->childNodes as $name) {
if ($name->nodeType == XML_ELEMENT_NODE && $name->nodeName == "NAME") {
if ($sname == get($name)) {//調用get()函數讀取某節點下所有子文本節點的內容
$cl = true;//若找到指定信息則將變量的置爲true
}
}
if ($name->nodeType == XML_ELEMENT_NODE && $name->nodeName == "AGE") {
$age = get($name);
}
if ($name->nodeType == XML_ELEMENT_NODE && $name->nodeName == "ADDRESS") {
$address = get($name);
}
if ($name->nodeType == XML_ELEMENT_NODE && $name->nodeName == "DEPARTMENT") {
$department = get($name);
}
}
if($cl){//如果找到信息則執行輸出操作
print ("你查詢的信息如下:<br/>");
print ("姓名:$sname<br/>年齡:$age<br/>地址:$address<br/>職位:$department<br/>");
}
}
}
}
}
}
…等等
對DOM解析器的就先收到這,對於其他的XML解析器將在之後的文章中進行淺談。