淺談PHP處理XML文檔的技術手段(二)——DOM解析器

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解析器將在之後的文章中進行淺談。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章