在 PHP 中处理 XML






4.92/5 (15投票s)
在 PHP 中使用 XML。
引言
由于速度和大量连接问题(我知道 MySQL 无法处理),我不得不在一个正在进行的项目中使用 XML 存储一些数据,而不是使用 MySQL。我能想到的唯一方法是使用共享内存和 XML。
我以前从未在 PHP 上使用过 XML,所以我的第一反应是从 PHP 手册中获取一些信息,但内容非常稀少。谷歌也没有提供太多帮助。
几个小时后(已经感觉想用头撞墙了),我终于让它们都正常工作了。为了拯救像我一样遇到困难的人,我决定分享我的一点经验。本文将帮助你:
- 从头开始编写 XML
- 从 XML 读取数据
- 向现有 XML 添加节点
- 修改现有 XML 中的节点
- 从现有 XML 删除节点
你可以直接获取示例代码,它们都有很好的注释。
从头开始编写 XML (使用 XMLWriter)
XMLWriter 旨在从头开始编写格式良好的 XML。其中一个重要的方法是 startDocument()
,它允许你声明要使用的版本和编码(尽管这些是可选的)。
用法
要编写这种性质的简单 XML:<?xml version="1.0"?>
<Customer>
<id>1</id>
<name>Oluwafemi</name>
<address>Cresent Drive, TX</address>
</Customer>
简单示例
可以使用 XMLWriter 来实现:
<?php
//XMLwriter to write XML from scratch - Simple example
$xml = new XMLWriter(); //create a new xmlwriter object
$xml->openMemory(); //using memory for string output
$xml->startDocument(); //create the document tag, you can specify the version and encoding here
$xml->startElement("Customer"); //Create an element
$xml->writeElement("id", "1");
$xml->writeElement("name", "Oluwafemi"); //Write to the element
$xml->writeElement("address", "Cresent Drive, TX");
$xml->endElement(); //End the element
echo $xml->outputMemory(); //done with writing output the xml
?>
这在下载中被命名为 “Simple - XMLWriter.php”。
一个稍微复杂的例子是编写这个 XML:
<xml version="1.0"?>
<purchase>
<customer>
<id>1</id>
<time>2013-04-19 10:56:03</time>
<total>$350</total>
</customer>
<customer>
<id>2</id>
<time>2013-04-23 13:43:41</time>
<total>$1456</total>
</customer>
</purchase>
稍微复杂的例子
这段代码解决了这个难题:
<?php
//XMLwriter to write XML from scratch - Little complex example
$xml = new XMLWriter();
$xml->openMemory();
$xml->startDocument();
$xml->startElement("purchase");
$xml->startElement("customer"); //Start of customer with id 1
$xml->writeElement("id", 1);
$xml->writeElement("time", "2013-04-19 10:56:03");
$xml->writeElement("total", "$350");
$xml->endElement(); //End of customer with id 1
$xml->startElement("customer"); //Start of customer with id 2
$xml->writeElement("id", 2);
$xml->writeElement("time", "2013-04-23 13:43:41");
$xml->writeElement("total", "$1456");
$xml->endElement(); //End of customer with id 1
$xml->endElement();
echo $xml->outputMemory();
?>
这在下载中被命名为 “Little Complex - XMLWriter.php”。
一个更复杂的例子是给一些节点添加属性,例如,在这个例子中的 <product>
节点:
<?xml version="1.0"?>
<products>
<product pid="314">
<name>Apple</name>
<price>$1.00</price>
<discount>3%</discount>
</product>
<product pid="315">
<name>Mango</name>
<price>$0.90</price>
<discount>3%</discount>
</product>
</products>
更复杂的例子(此 XML 将在后面的各种示例中使用)
这也可以使用 XMLWriter 来实现:
<?php
//XMLwriter to write XML from scratch - Little complex example
$xml = new XMLWriter();
$xml->openMemory();
$xml->startDocument();
$xml->startElement("products");
$xml->startElement("product"); //Start of product with pid 314
$xml->writeAttribute("pid", 314);
$xml->writeElement("name", "Apple");
$xml->writeElement("price", "$1.00");
$xml->writeElement("discount", "3%");
$xml->endElement(); //End of product with pid 314
$xml->startElement("product"); //Start of product with pid 315
$xml->writeAttribute("pid", 315);
$xml->writeElement("name", "Mango");
$xml->writeElement("price", "$0.90");
$xml->writeElement("discount", "3%");
$xml->endElement(); //End of product with pid 315
$xml->endElement();
echo $xml->outputMemory(); //Done with writing, output the xml
?>
这在下载中被命名为 “More Complex - XMLWriter.php”。
读取 / 从 XML 获取数据 (使用 XMLReader 和 SimpleXMLElement)
XMLReader 用于从整个 XML 中获取我所说的“节点 XML”。你可以使用 open()
方法从 URI(文件、URL 等)加载 XML,或者使用 xml() 方法从内存加载。这个例子将始终使用 xml()
方法。open()
方法没什么大不了的,只需提供包含 XML 的 URI,例如,open(“c:/…/this.xml”);
或 open(“http://example.com/this.xml”);
。
SimpleXMLElement 可用于从从 XMLReader
获取的“节点 XML”中提取数据。
要获取在上面的 Little Complex 示例中,id 为 1 的客户的总花费:
<?php
.
.
.
/* XMLReader starts from here for Little Complex Example - XMLReader
To get the total amount spent by custormer with id 1
*/
$rxml = new XMLReader(); //Create new XMLReader Object
$rxml->xml($nXML); //Load in the XML
while($rxml->read() && $rxml->name !== 'customer');
//Move to the first customer child
$amountSpent = 0;
while($rxml->name === 'customer')
{
/* The child xml gotten using the readOuterXML() will look thus
<customer><id>1</id><time>2013-04-19 10:56:03</time><total>$350</total></customer>
*/
//Read the current child xml into a SimpleXMLElement
$node = new SimpleXMLElement($rxml->readOuterXML());
if($node->id == 1)
//Check if the id node as 1 as it value
{
$amountSpent = $node->total;
break;
}
$rxml->next('customer');
//Move to the next customer child
}
echo $amountSpent;
?>
这在下载中被命名为 “Little Complex Example - XMLReader.php”。
并且要从上面的 More Complex 示例中获取 pid=315 的产品的名称、价格和折扣:
/* XMLReader starts from here for More Complex XMLReader
To get the name, price, and discount of the prouct with attribute pid = 315
*/
$rxml = new XMLReader(); //Create new XMLReader Object
$rxml->xml($nXML); //Load in the XML
while($rxml->read() && $rxml->name !== 'product'); //Move to the first product child
$name = "";
$price = "";
$discount = "";
while($rxml->name === 'product')
{ /* The child xml gotten using the readOuterXML() will look thus
<product pid="314"><name>Apple</name><price>$1.00</price><discount>3%</discount></product>
*/
if($rxml->getAttribute("pid") == "315") //Check if the atrribute pid is equals to 315
{
$node = new SimpleXMLElement($rxml->readOuterXML());//Read the current child xml into a SimpleXMLElement
$name = $node->name;
$price = $node->price;
$discount = $node->discount;
break;
}
$rxml->next('product'); //Move to the next product child
}
echo "The product is {$name} and is {$price} with {$discount} as discount";
?>
这在下载中被命名为 “More Complex - XMLReader.php”。
向现有 XML 添加子节点 (使用 SimpleXMLElement)
XMLWriter 旨在从头到尾编写新的 XML。但是,假设要将一个新产品添加到上面的 XML More Complex 示例中,你不想再次重写整个 XML,对吧?(想象一下 XML 现在有多达 350,000 个产品节点
<?php
.
.
.
//Adding node starts from here
$sXML = new SimpleXMLElement($nXML); //Load the entire xml in
$newchild = $sXML->addChild("product");
//Notice am now using the $newchild object not the $sXML object
$newchild->addAttribute("pid", 328);
$newchild->addChild("name", "Orange");
$newchild->addChild("price", "$3.00");
$newchild->addChild("discount", "0.3%");
echo $sXML->asXML();
//Notice am now back to the $sXML object. The asXML() method is used to output the XML
?>
这在下载中被命名为 “Adding Node.php”。
修改现有 XML 中的节点 (使用 DomDocument 和 DOMXPath)
假设 Apple 的价格从 1.00 美元变为 2.00 美元(我多么希望 Apple iPad 也以这个价格出售,或者它们不是都是苹果吗),并且折扣降至 1%。然后,你可以使用 DomDocument
修改 XML,同时使用 DOMXPath
查找要修改的节点。
<?php
.
.
.
//Modifying Node starts from here
// Create a new document fragment to hold the new <product> node
$productId = 314;
$parent = new DomDocument;
$parent_node = $parent->createElement('product');
//Add the pid attribute
//Notice that the createAttribute() method was used on $parent
$attribute = $parent->createAttribute("pid");
//but appended to $parent_node
$attribute->value = $productId;
$parent_node->appendChild($attribute);
// Add the child elements
$parent_node->appendChild($parent->createElement('name', "Apple"));
$parent_node->appendChild($parent->createElement('price', "$2.00"));
$parent_node->appendChild($parent->createElement('discount', "1%"));
//Append the $parent_node into $parent
$parent->appendChild($parent_node);
// Load the original XML to modify into a new DomDocument
$dom = new DomDocument;
$dom->loadXML($nXML);
// Locate the old product node to modify
$xpath = new DOMXpath($dom);
$nodelist = $xpath->query("/products/product[@pid={$productId}]");
$oldnode = $nodelist->item(0);
// Load the $parent document fragment into the $dom
$newnode = $dom->importNode($parent->documentElement, true);
// Replace
$oldnode->parentNode->replaceChild($newnode, $oldnode);
echo $dom->saveXML();
//Done output XML
?>
</product>
这在下载中被命名为 “Modifying Node.php”。
删除现有 XML 中的节点 (使用 DomDocument 和 DOMXPath)
假设我们不再销售芒果,并且必须将其从 XML 中删除。
<?php
.
.
.
//Deleting Node of Mango
//Load the original XML to modify into a new DomDocument
$productId = 315;
$dom = new DomDocument;
$dom->loadXML($nXML);
// Locate the old product node to modify
$xpath = new DOMXpath($dom);
$nodelist = $xpath->query("/products/product[@pid={$productId}]");
$oldnode = $nodelist->item(0);
// Remove
$oldnode->parentNode->removeChild($oldnode);
echo $dom->saveXML();//Done output XML
?>
这在下载中被命名为 “Deleting Node.php”。