如何在PHP中使用XMLReader?
我有以下XML文件,该文件相当大,我无法让simplexml打开并读取该文件,因此我尝试使用XMLReader,但在php中没有成功如何在PHP中使用XMLReader?,php,xml,parsing,simplexml,xmlreader,Php,Xml,Parsing,Simplexml,Xmlreader,我有以下XML文件,该文件相当大,我无法让simplexml打开并读取该文件,因此我尝试使用XMLReader,但在php中没有成功 <?xml version="1.0" encoding="ISO-8859-1"?> <products> <last_updated>2009-11-30 13:52:40</last_updated> <product> <element_1>foo<
<?xml version="1.0" encoding="ISO-8859-1"?>
<products>
<last_updated>2009-11-30 13:52:40</last_updated>
<product>
<element_1>foo</element_1>
<element_2>foo</element_2>
<element_3>foo</element_3>
<element_4>foo</element_4>
</product>
<product>
<element_1>bar</element_1>
<element_2>bar</element_2>
<element_3>bar</element_3>
<element_4>bar</element_4>
</product>
</products>
2009-11-30 13:52:40
福
福
福
福
酒吧
酒吧
酒吧
酒吧
不幸的是,我还没有找到一个关于PHP的好教程,我很想看看如何将每个元素内容存储在数据库中。XMLReader在上有很好的文档记录。这是一个XML拉式解析器,这意味着它用于迭代给定XML文档的节点(或DOM节点)。例如,您可以这样浏览您提供的整个文档:
<?php
$reader = new XMLReader();
if (!$reader->open("data.xml"))
{
die("Failed to open 'data.xml'");
}
while($reader->read())
{
$node = $reader->expand();
// process $node...
}
$reader->close();
?>
open(“data.xml”))
{
die(“未能打开'data.xml'”);
}
而($reader->read())
{
$node=$reader->expand();
//处理$node。。。
}
$reader->close();
?>
然后由您决定如何处理返回的节点。这完全取决于工作单元的大小,但我猜您正在尝试依次处理每个
节点
为此,最简单的方法是使用XMLReader访问每个节点,然后使用SimpleXML访问它们。通过这种方式,您可以保持较低的内存使用率,因为您一次只处理一个节点,并且仍然可以利用SimpleXML的易用性。例如:
$z = new XMLReader;
$z->open('data.xml');
$doc = new DOMDocument;
// move to the first <product /> node
while ($z->read() && $z->name !== 'product');
// now that we're at the right depth, hop to the next <product/> until the end of the tree
while ($z->name === 'product')
{
// either one should work
//$node = new SimpleXMLElement($z->readOuterXML());
$node = simplexml_import_dom($doc->importNode($z->expand(), true));
// now you can use $node without going insane about parsing
var_dump($node->element_1);
// go to next <product />
$z->next('product');
}
$z=新的XMLReader;
$z->open('data.xml');
$doc=新文档;
//移动到第一个节点
而($z->read()&&$z->name!=='product');
//现在我们已经到达了正确的深度,跳到下一个直到树的尽头
而($z->name===‘产品’)
{
//任何一个都应该起作用
//$node=newsimplexmlement($z->readOuterXML());
$node=simplexml\u import\u dom($doc->importNode($z->expand(),true));
//现在,您可以使用$node而不必为解析而发狂
变量转储($node->element\u 1);
//转到下一个
$z->next('product');
}
快速概述不同方法的优缺点:
仅限XMLReader
- 优点:速度快,占用内存少
- 缺点:编写和调试过于困难,需要大量的用户代码才能完成任何有用的工作。Userland代码速度慢,容易出错。另外,它给您留下了更多需要维护的代码行
- 优点:不需要使用太多内存(只需要处理一个节点所需的内存),SimpleXML,顾名思义,非常易于使用
- 缺点:为每个节点创建SimpleXMLElement对象不是很快。你真的必须对它进行基准测试,以了解它是否是你的问题。不过,即使是一台普通的机器,每秒也能处理1000个节点
- 优点:使用的内存大约与SimpleXML一样多,并且比创建新的SimpleXML元素更快。我希望可以使用
,但在这种情况下它似乎不起作用simplexml\u import\u dom()
- 缺点:使用DOM很烦人。它介于XMLReader和SimpleXML之间。不像XMLReader那样复杂和笨拙,但离使用SimpleXML还有几光年
我的建议是:用SimpleXML编写一个原型,看看它是否适合您。如果性能至关重要,请尝试DOM。尽可能远离XMLReader。请记住,编写的代码越多,引入错误或性能下降的可能性就越高。对于使用属性格式化的xml data.xml:
<building_data>
<building address="some address" lat="28.902914" lng="-71.007235" />
<building address="some address" lat="48.892342" lng="-75.0423423" />
<building address="some address" lat="58.929753" lng="-79.1236987" />
</building_data>
简单示例:
公共功能产品交易()
{
$saveFileName='ceneo.xml';
$filename=$this->path.$saveFileName;
如果(文件_存在($filename)){
$reader=newXMLReader();
$reader->open($filename);
$countElements=0;
而($reader->read()){
if($reader->nodeType==XMLReader::ELEMENT){
$nodeName=$reader->name;
}
如果($reader->nodeType==XMLReader::TEXT&&!empty($nodeName)){
交换机($nodeName){
案件编号:
变量转储($reader->value);
打破
}
}
如果($reader->nodeType==XMLReader::END_元素&&$reader->name==offer'){
$countElements++;
}
}
$reader->close();
退出(打印(“”).var_转储($countElements));
}
}
被接受的答案给了我一个良好的开端,但带来了比我想要的更多的类和更多的处理;这就是我的解释:
function parseMyXML ($xml) { //pass in an XML string
$myXML = new XMLReader();
$myXML->xml($xml);
while ($myXML->read()) { //start reading.
if ($myXML->nodeType == XMLReader::ELEMENT) { //only opening tags.
$tag = $myXML->name; //make $tag contain the name of the tag
switch ($tag) {
case 'Tag1': //this tag contains no child elements, only the content we need. And it's unique.
$variable = $myXML->readInnerXML(); //now variable contains the contents of tag1
break;
case 'Tag2': //this tag contains child elements, of which we only want one.
while($myXML->read()) { //so we tell it to keep reading
if ($myXML->nodeType == XMLReader::ELEMENT && $myXML->name === 'Amount') { // and when it finds the amount tag...
$variable2 = $myXML->readInnerXML(); //...put it in $variable2.
break;
}
}
break;
case 'Tag3': //tag3 also has children, which are not unique, but we need two of the children this time.
while($myXML->read()) {
if ($myXML->nodeType == XMLReader::ELEMENT && $myXML->name === 'Amount') {
$variable3 = $myXML->readInnerXML();
break;
} else if ($myXML->nodeType == XMLReader::ELEMENT && $myXML->name === 'Currency') {
$variable4 = $myXML->readInnerXML();
break;
}
}
break;
}
}
}
$myXML->close();
}
我的XML解析生涯的大部分时间都是从一卡车XML(AmazonMWS)中提取有用信息。因此,我的回答假设您只需要特定的信息,并且您知道它的位置 我发现使用XMLReader最简单的方法是知道我想要从哪些标记中获得信息并使用它们。如果您知道XML的结构,并且它有许多独特的标记,我发现使用第一种情况是很容易的。案例2和案例3只是向您展示如何对更复杂的标记执行此操作。这是非常快的,;我有一个关于速度的讨论 在这样做基于标记的解析时,要记住的最重要的一点是使用
if($myXML->nodeType==XMLReader::ELEMENT){…
——它检查以确保我们只处理打开的节点,而不处理空白或关闭的节点或其他什么
<html>
<head>
<script>
function showRSS(str) {
if (str.length==0) {
document.getElementById("rssOutput").innerHTML="";
return;
}
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
} else { // code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function() {
if (this.readyState==4 && this.status==200) {
document.getElementById("rssOutput").innerHTML=this.responseText;
}
}
xmlhttp.open("GET","getrss.php?q="+str,true);
xmlhttp.send();
}
</script>
</head>
<body>
<form>
<select onchange="showRSS(this.value)">
<option value="">Select an RSS-feed:</option>
<option value="Google">Google News</option>
<option value="ZDN">ZDNet News</option>
<option value="job">Job</option>
</select>
</form>
<br>
<div id="rssOutput">RSS-feed will be listed here...</div>
</body>
</html>
这对我来说效果更好更快
<?php
//get the q parameter from URL
$q=$_GET["q"];
//find out which feed was selected
if($q=="Google") {
$xml=("http://news.google.com/news?ned=us&topic=h&output=rss");
} elseif($q=="ZDN") {
$xml=("https://www.zdnet.com/news/rss.xml");
}elseif($q == "job"){
$xml=("https://ngcareers.com/feed");
}
$xmlDoc = new DOMDocument();
$xmlDoc->load($xml);
//get elements from "<channel>"
$channel=$xmlDoc->getElementsByTagName('channel')->item(0);
$channel_title = $channel->getElementsByTagName('title')
->item(0)->childNodes->item(0)->nodeValue;
$channel_link = $channel->getElementsByTagName('link')
->item(0)->childNodes->item(0)->nodeValue;
$channel_desc = $channel->getElementsByTagName('description')
->item(0)->childNodes->item(0)->nodeValue;
//output elements from "<channel>"
echo("<p><a href='" . $channel_link
. "'>" . $channel_title . "</a>");
echo("<br>");
echo($channel_desc . "</p>");
//get and output "<item>" elements
$x=$xmlDoc->getElementsByTagName('item');
$count = $x->length;
// print_r( $x->item(0)->getElementsByTagName('title')->item(0)->nodeValue);
// print_r( $x->item(0)->getElementsByTagName('link')->item(0)->nodeValue);
// print_r( $x->item(0)->getElementsByTagName('description')->item(0)->nodeValue);
// return;
for ($i=0; $i <= $count; $i++) {
//Title
$item_title = $x->item(0)->getElementsByTagName('title')->item(0)->nodeValue;
//Link
$item_link = $x->item(0)->getElementsByTagName('link')->item(0)->nodeValue;
//Description
$item_desc = $x->item(0)->getElementsByTagName('description')->item(0)->nodeValue;
//Category
$item_cat = $x->item(0)->getElementsByTagName('category')->item(0)->nodeValue;
echo ("<p>Title: <a href='" . $item_link
. "'>" . $item_title . "</a>");
echo ("<br>");
echo ("Desc: ".$item_desc);
echo ("<br>");
echo ("Category: ".$item_cat . "</p>");
}
?>
您是否阅读了PHP文档中一些用户提供的示例?可能会有所帮助。在完成一个节点的处理后,您将如何让它移动到下一个节点?另外,关于XMLReader在PHP.net上的良好文档记录,我不同意,这是我见过的文档记录最差的函数之一,我已经使用PHP.net很长时间了,但事实并非如此在这里提问之前,我首先要解决这个问题:)我不确定您是否理解XMLReader::read()从一个节点到另一个节点的方式
function parseMyXML ($xml) { //pass in an XML string
$myXML = new XMLReader();
$myXML->xml($xml);
while ($myXML->read()) { //start reading.
if ($myXML->nodeType == XMLReader::ELEMENT) { //only opening tags.
$tag = $myXML->name; //make $tag contain the name of the tag
switch ($tag) {
case 'Tag1': //this tag contains no child elements, only the content we need. And it's unique.
$variable = $myXML->readInnerXML(); //now variable contains the contents of tag1
break;
case 'Tag2': //this tag contains child elements, of which we only want one.
while($myXML->read()) { //so we tell it to keep reading
if ($myXML->nodeType == XMLReader::ELEMENT && $myXML->name === 'Amount') { // and when it finds the amount tag...
$variable2 = $myXML->readInnerXML(); //...put it in $variable2.
break;
}
}
break;
case 'Tag3': //tag3 also has children, which are not unique, but we need two of the children this time.
while($myXML->read()) {
if ($myXML->nodeType == XMLReader::ELEMENT && $myXML->name === 'Amount') {
$variable3 = $myXML->readInnerXML();
break;
} else if ($myXML->nodeType == XMLReader::ELEMENT && $myXML->name === 'Currency') {
$variable4 = $myXML->readInnerXML();
break;
}
}
break;
}
}
}
$myXML->close();
}
<html>
<head>
<script>
function showRSS(str) {
if (str.length==0) {
document.getElementById("rssOutput").innerHTML="";
return;
}
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
} else { // code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function() {
if (this.readyState==4 && this.status==200) {
document.getElementById("rssOutput").innerHTML=this.responseText;
}
}
xmlhttp.open("GET","getrss.php?q="+str,true);
xmlhttp.send();
}
</script>
</head>
<body>
<form>
<select onchange="showRSS(this.value)">
<option value="">Select an RSS-feed:</option>
<option value="Google">Google News</option>
<option value="ZDN">ZDNet News</option>
<option value="job">Job</option>
</select>
</form>
<br>
<div id="rssOutput">RSS-feed will be listed here...</div>
</body>
</html>
<?php
//get the q parameter from URL
$q=$_GET["q"];
//find out which feed was selected
if($q=="Google") {
$xml=("http://news.google.com/news?ned=us&topic=h&output=rss");
} elseif($q=="ZDN") {
$xml=("https://www.zdnet.com/news/rss.xml");
}elseif($q == "job"){
$xml=("https://ngcareers.com/feed");
}
$xmlDoc = new DOMDocument();
$xmlDoc->load($xml);
//get elements from "<channel>"
$channel=$xmlDoc->getElementsByTagName('channel')->item(0);
$channel_title = $channel->getElementsByTagName('title')
->item(0)->childNodes->item(0)->nodeValue;
$channel_link = $channel->getElementsByTagName('link')
->item(0)->childNodes->item(0)->nodeValue;
$channel_desc = $channel->getElementsByTagName('description')
->item(0)->childNodes->item(0)->nodeValue;
//output elements from "<channel>"
echo("<p><a href='" . $channel_link
. "'>" . $channel_title . "</a>");
echo("<br>");
echo($channel_desc . "</p>");
//get and output "<item>" elements
$x=$xmlDoc->getElementsByTagName('item');
$count = $x->length;
// print_r( $x->item(0)->getElementsByTagName('title')->item(0)->nodeValue);
// print_r( $x->item(0)->getElementsByTagName('link')->item(0)->nodeValue);
// print_r( $x->item(0)->getElementsByTagName('description')->item(0)->nodeValue);
// return;
for ($i=0; $i <= $count; $i++) {
//Title
$item_title = $x->item(0)->getElementsByTagName('title')->item(0)->nodeValue;
//Link
$item_link = $x->item(0)->getElementsByTagName('link')->item(0)->nodeValue;
//Description
$item_desc = $x->item(0)->getElementsByTagName('description')->item(0)->nodeValue;
//Category
$item_cat = $x->item(0)->getElementsByTagName('category')->item(0)->nodeValue;
echo ("<p>Title: <a href='" . $item_link
. "'>" . $item_title . "</a>");
echo ("<br>");
echo ("Desc: ".$item_desc);
echo ("<br>");
echo ("Category: ".$item_cat . "</p>");
}
?>