本文不涉及XML的知识,请自行学习,本文不涉及XML的高级操作,只是简单的增删改查。
从图中可以看到,DOMNode类是大部分类的父类,下面将会用到的一些成员函数和成员变量很多都是从他继承来的。比较常用的是标绿色的那几个,本文主要涉及到这几个类。
$doc=new DOMDocument("1.0","utf-8"); $doc->formatOutput=true; //Nicely formats output with indentation and extra space echo $doc->saveXML();
我们将得到一个空的XML,只有一个头,没有任何元素:
<?xml version="1.0" encoding="utf-8"?>
注:saveXML()函数返回的是个XML字符串。下边我们边创建边组合,然后用此函数显示。下边的代码不断的追加即可看到整体的效果。
$root = $doc->createElement("breakfast_menu"); $doc->appendChild($root); echo $doc->saveXML();
结果是:
<?xml version="1.0" encoding="utf-8"?> <breakfast_menu/>
$food = $doc->createElement("food"); // 创建一个名为food的空子元素 $root->appendChild($food); echo $doc->saveXML();
结果是:
<?xml version="1.0" encoding="utf-8"?> <breakfast_menu> <food/> </breakfast_menu>
$food->setAttribute("onsale","yes"); // 添加属性方法一 echo $doc->saveXML();
结果:
<?xml version="1.0" encoding="utf-8"?> <breakfast_menu> <food onsale="yes"/> </breakfast_menu>
$food_attr = $doc->createAttribute("fresh");// 添加属性方法二 $food_attr_txt = $doc->createTextNode("no"); $food_attr->appendChild($food_attr_txt); $food->appendChild($food_attr); echo $doc->saveXML();
结果:
<?xml version="1.0" encoding="utf-8"?> <breakfast_menu> <food onsale="yes" fresh="no"/> </breakfast_menu>
$food_name = $doc->createElement("name","Waffles"); // 创建带文本元素,方法一 $food->appendChild($food_name); echo $doc->saveXML();
结果:
<?xml version="1.0" encoding="utf-8"?> <breakfast_menu> <food onsale="yes" fresh="no"> <name>Waffles</name> </food> </breakfast_menu>
$food_price = $doc->createElement("price"); // 创建带文本元素,方法二 $food_price_txt = $doc->createTextNode("$4"); $food_price->appendChild($food_price_txt); $food->appendChild($food_price); echo $doc->saveXML();
结果:
<?xml version="1.0" encoding="utf-8"?> <breakfast_menu> <food onsale="yes" fresh="no"> <name>Waffles</name> <price>$4</price> </food> </breakfast_menu>
$food_comment = $doc->createComment("Hello, I am a comment"); // 创建一条注释 $food->appendChild($food_comment); echo $doc->saveXML();
结果:
<?xml version="1.0" encoding="utf-8"?> <breakfast_menu> <food onsale="yes" fresh="no"> <name>Waffles</name> <price>$4</price> <!--Hello, I am a comment--> </food> </breakfast_menu>
添加文本
$txt = $doc->createTextNode("TXT"); $food->appendChild($txt); echo $doc->saveXML();
结果:
<?xml version="1.0" encoding="utf-8"?> <breakfast_menu> <food onsale="yes" fresh="no"><name>Waffles</name><price>$4</price><!--Hello, I am a comment-->TXT</food> </breakfast_menu>
$doc->save("./create.xml");
当前目录下会生成create.xml文件
上边我们创建了有一个XML,基本的思路是用DOMDocument对象创建一系列要用的组件,然后把它们用appendChild()方法组合起来(也有部分直接设置的方法,比如setAttribute())。还有几个特性在此说明:
1.根元素有且只有一个,但他也是一个普通元素,可以有属性、文本内容、注释、子元素的组件。
2.更复杂的XML也是由一个个的元素和子元素组成。
3.本人发现,一个元素如果有多个子元素,这些子元素之间都是有文本元素的,如果没有文本就是个空的文本元素。
另:有教程说,使用xml属性不方便扩展,建议只使用子元素。经本人研究,发现一个DOMElement对象对属性的操作有很多方法,比操作子对象的多多了。然后经思考,我觉得是不是这样更好:只有一个的信息用属性,同时有多个的用子元素,比如描述一个人,性别、年龄、父亲、母亲这样的用属性,兄弟姐妹、住房、车辆等用子元素。欢迎大家对此进行讨论。
上文的整体代码:
<?php echo "=========创建一个document========\n"; $doc=new DOMDocument("1.0","utf-8"); $doc->formatOutput=true;//Nicely formats output with indentation and extra space echo $doc->saveXML(); echo "=========创建一个'空'根元素========\n"; $root = $doc->createElement("breakfast_menu"); // 创建一个名为breakfast_menu的空根元素 $doc->appendChild($root); echo $doc->saveXML(); echo "=========创建一个'空'子元素========\n"; $food = $doc->createElement("food"); // 创建一个名为food的空子元素 $root->appendChild($food); echo $doc->saveXML(); echo "=========添加属性方法一========\n"; $food->setAttribute("onsale","yes"); // 添加属性方法一 echo $doc->saveXML(); echo "=========添加属性方法二========\n"; $food_attr = $doc->createAttribute("fresh");// 添加属性方法二 $food_attr_txt = $doc->createTextNode("no"); $food_attr->appendChild($food_attr_txt); $food->appendChild($food_attr); echo $doc->saveXML(); echo "=========添加带文本子元素方法一========\n"; $food_name = $doc->createElement("name","Waffles"); // 创建带文本元素,方法一 $food->appendChild($food_name); echo $doc->saveXML(); echo "=========添加带文本子元素方法二========\n"; $food_price = $doc->createElement("price"); // 创建带文本元素,方法二 $food_price_txt = $doc->createTextNode("$4"); $food_price->appendChild($food_price_txt); $food->appendChild($food_price); echo $doc->saveXML(); echo "=========添加注释========\n"; $food_comment = $doc->createComment("Hello, I am a comment"); // 创建一条注释 $food->appendChild($food_comment); echo $doc->saveXML(); echo "=========添加文本(缩进格式被破坏)========\n"; $txt = $doc->createTextNode("TXT"); $food->appendChild($txt); echo $doc->saveXML(); $doc->save("./create.xml"); ?>
$att_txt1 = $doc->createTextNode("111"); // "111" $att_txt2 = $doc->createTextNode("222"); // "222" $att_txt3 = $doc->createTextNode("333"); // "333" $att_txt4 = $doc->createTextNode("444"); // "444" $att = $doc->createAttribute("id"); // id="" $att->appendChild($att_txt1); // id="111" $att->appendChild($att_txt2); // id="111222" $att->replaceChild($att_txt3,$att_txt2); // id="111333" $att->insertBefore($att_txt4,$att_txt3); // id="111444333" $att->removeChild($att_txt4); // id="111333" echo $att->name; // id echo "\n"; echo $att->value; // 111333 echo "\n"; var_dump($att->hasAttributes()); // bool(false) echo "\n"; var_dump($att->hasChildNodes()); // bool(true) 没错,属性是有子node的, // 组合时是可以用多个TextNode拼装的。 $txt_list = $att->childNodes; // 把子node一个个取出来 foreach ($txt_list as $txt) // 还有如下一些成员变量(继承自DOMNode) { // $att->parentNode; print_r($txt); // $att->firstChild; echo $txt->wholeText; // $att->previousSibling; echo "\n"; // 等等 }
$txt = $doc->createTextNode("aab"); // "aab" $txt->appendData("bcc"); // "aabbcc" $txt->deleteData(2,2); // "aacc" $txt->insertData(2,"bb"); // "aabbcc" $txt->replaceData(2,2,"BB"); // "aaBBcc" echo $txt->substringData(1,4); // "aBBc" echo "\n"; echo $txt->length; // 6 echo "\n"; echo $txt->wholeText; // aaBBcc echo "\n"; echo $txt->data; // aaBBcc echo "\n";
$com = $doc->createComment("AAB"); // <!--"AAB"-->
$com->appendData("BCC"); // <!--"AABBCC"--> $com->deleteData(2,2); // <!--"AACC"-->
$com->insertData(2,"BB"); // <!--"AABBCC"-->
$com->replaceData(2,2,"bb"); // <!--"AAbbCC"-->
echo $com->substringData(1,4); // AbbC
echo "\n";
echo $com->data; // AAbbCC
echo "\n";
echo $com->length; // 6
echo "\n";
示例: $xml=<<<LLL <?xml version="1.0" encoding="UTF-8"?> <breakfast_menu id="1"> AAA <food onsale="yes" fresh="yes"> <name>Waffles</name> <price>$7.95</price> <calories>900</calories> </food> BBB <food onsale="yes" fresh="no"> <name>Bread</name> <price>$8.95</price> <calories>900</calories> </food> CCC <drink onsale="no" fresh="yes"> <name>Milk</name> <price>$4.50</price> <calories>600</calories> </drink> DDD <drink onsale="no" fresh="no"> <name>Orange Juice</name> <price>$6.95</price> <calories>950</calories> </drink> EEE <!-- this is comment --> FFF </breakfast_menu> LLL;
$doc=new DOMDocument("1.0","utf-8");
$doc->formatOutput=true; # Nicely formats output with indentation and extra space
$doc->validateOnParse=true;
$doc->loadXML($xml); // 从字符串加载 #$doc->load($xmlfilename); // 从文件中加载
echo $doc->saveXML(); //生成字符串 #echo $doc->save($xmlfilename); // 保存到文件
if ($doc->hasChildNodes()) { #第一种方法 $root = $doc->firstChild;# because it has one and only one root node #第二种方法 $root = $doc->childNodes->item(0);#the same as above #第三种方法(推荐) $root_list = $doc->getElementsByTagName("breakfast_menu");# this xml may have root but not breakfast_menu if ($root_list->length > 0) { $root = $root_list->item(0); } echo 'root name -> '.$root->nodeName; echo "\n"; }
$food_list = $root->getElementsByTagName("food"); if ($food_list->length > 0) # check before use, anything is possible. { foreach ($food_list as $key => $value) { print_list($key, $value); // 自定义函数,见下文 # 获取所有attribute,如果有未知的也可以得到 if ($value->hasAttributes()) { $attribute_list = $value->attributes; foreach ($attribute_list as $value) { echo 'name -> '.$value->name; echo "\n"; echo 'value -> '.$value->value; echo "\n"; } } } }
$drink_list = $root->getElementsByTagName("drink"); if ($drink_list->length > 0) # check before use, anything is possible. { foreach ($food_list as $key => $value) { print_list($key, $value); if ($value->hasAttribute("onsale") { echo "onsale -> ".$value->getAttribute("onsale"); } if ($value->hasAttribute("fresh") { echo "fresh -> ".$value->getAttribute("fresh"); } } }
function print_list(&$key,&$value) { echo 'key -> '.$key."\n"; #echo 'value type ->';print_r($value)."\n"; $name_list = $value->getElementsByTagName('name'); if ($name_list->length > 0) { echo 'name -> '.$name_list->item(0)->nodeValue."\n"; } $price_list = $value->getElementsByTagName('price'); if ($price_list->length > 0) { echo 'price -> '.$price_list->item(0)->nodeValue."\n"; } $calories_list = $value->getElementsByTagName('calories'); if ($calories_list->length > 0) { echo 'calories -> '.$calories_list->item(0)->nodeValue."\n"; } }
如果有更深层次的嵌套,再继续这样做下去就是了。
最后在补充下在不知道有哪些子元素情况下,解析XML的方法
if ( false and $root->hasChildNodes()) { # let us see, what we can get from a element childNodes # it's text comment and subelement, no attribute print_childs($root->childNodes);//见后文 }
function print_childs($nodelist) { echo "=====================\n"; foreach ($nodelist as $key => $value) { echo $key; echo "\n"; print_r($value); if (is_a($value,'DOMText')) { #echo $value->wholeText; #echo '-------------'; echo $value->nodeValue; } if (is_a($value,'DOMElement')) { echo $value->tagName; echo "\n-------------\n"; echo $value->nodeValue; } # this tell us comment can get if (is_a($value,'DOMComment')) { echo $value->nodeValue; } echo "\n"; } echo "=====================\n"; }
原始xml
$xml=<<<LLL <?xml version="1.0" encoding="UTF-8"?> <breakfast_menu id="1"> <food onsale="yes" fresh="yes"> <name>Waffles</name> <price>$7.95</price> <calories>900</calories> </food> <food onsale="yes" fresh="no"> <name>Bread</name> <price>$8.95</price> <calories>900</calories> </food> <!-- this is comment --> </breakfast_menu> LLL;
$doc=new DOMDocument("1.0","utf-8"); # this is root : <?xml version="1.0" encoding="utf-8"\?\> $doc->formatOutput=true; # Nicely formats output with indentation and extra space $doc->validateOnParse=true; $doc->loadXML($xml); #$doc->load($xmlfilename); # print echo $doc->saveXML(); #echo $doc->save($xmlfilename); # get root if ($doc->hasChildNodes()) { $root_list = $doc->getElementsByTagName("breakfast_menu");# this xml may have root but not breakfast_menu if ($root_list->length > 0) { $root = $root_list->item(0); } echo 'root name -> '.$root->nodeName; echo "\n"; } # get value echo " ===== food =====\n"; $food_list = $root->getElementsByTagName("food"); if ($food_list->length > 0) # check before use, anything is possible. { foreach ($food_list as $key => $value) { $name_list = $value->getElementsByTagName('name'); if ($name_list->length > 0) { $name_list->item(0)->nodeValue="rice"; } $price_list = $value->getElementsByTagName('price'); if ($price_list->length > 0) { $value->removeChild($price_list->item(0)); } $calories_list = $value->getElementsByTagName('calories'); if ($calories_list->length > 0) { $calories_list->item(0)->nodeValue = "3999"; } if ($value->hasAttribute("onsale")) { $value->setAttribute("onsale","modify"); } if ($value->hasAttribute("fresh")) { $value->removeAttribute("fresh"); } } } echo $doc->saveXML(); ?>