65.9K
CodeProject 正在变化。 阅读更多。
Home

在 PHP 中处理 XML

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (15投票s)

2013年4月24日

CPOL

3分钟阅读

viewsIcon

74964

downloadIcon

2099

在 PHP 中使用 XML。

引言

由于速度和大量连接问题(我知道 MySQL 无法处理),我不得不在一个正在进行的项目中使用 XML 存储一些数据,而不是使用 MySQL。我能想到的唯一方法是使用共享内存和 XML。

我以前从未在 PHP 上使用过 XML,所以我的第一反应是从 PHP 手册中获取一些信息,但内容非常稀少。谷歌也没有提供太多帮助。

几个小时后(已经感觉想用头撞墙了),我终于让它们都正常工作了。为了拯救像我一样遇到困难的人,我决定分享我的一点经验。本文将帮助你:

  1. 从头开始编写 XML
  2. 从 XML 读取数据
  3. 向现有 XML 添加节点
  4. 修改现有 XML 中的节点
  5. 从现有 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 个产品节点 Wink )。SimpleXMLElement 可用于向现有 XML 添加额外的节点。要添加价格为 3.00 美元、折扣为 0.3% 且 pid 为 328 的橙子,请使用以下代码:
<?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”。

© . All rights reserved.