我想使用XMLReader读取XML文件,但在解析过程中,每个元素都会调用两次END ELEMENT。
<publications>
<article id="Xu86oazdn">
<title>Learning</title>
<authors>
<author>
<firstname>Michel</firstname>
<lastname>Browsky</lastname>
</author>
</authors>
</article>
</publications>
这是解析作者条目的代码段:
<?php
$xml = new XMLReader();
$xml->open("php://stdin");
$author = null;
while($xml->read()) {
switch($xml->nodeType) {
case XMLReader::ELEMENT:
switch($xml->name) {
case 'author':
echo("+" . $xml->name);
break;
}
case XMLReader::END_ELEMENT:
switch($xml->name) {
case 'author':
echo("-" . $xml->name);
break;
}
}
}
?>
但奇怪的是,每个</author>
都会调用两次END_ELEMENT,如回显消息所示:
+author
-author
-author
如果我通过调用$xml->readOuterXML()
替换回显消息,则第一个END_ELEMENT如下:
<author>
<firstname>Michel</firstname>
<lastname>Browsky</lastname>
</author>
第二个是以下内容:
<author/>
我的代码出了什么问题?我是否以错误的方式使用END_ELEMENT?检测结束元素的正确方法是什么?
答案 0 :(得分:8)
在break
上的第一个switch
条件结束后添加nodeType
语句:
<?php
$xml = new XMLReader();
$xml->open("php://stdin");
while($xml->read()) {
switch($xml->nodeType) {
case XMLReader::ELEMENT:
switch($xml->name) {
case 'author':
echo("+" . $xml->name);
break;
}
// THIS LINE IS MISSING
break;
case XMLReader::END_ELEMENT:
switch($xml->name) {
case 'author':
echo("-" . $xml->name);
break;
}
}
}
?>
在阅读break
之后添加另一个END_ELEMENT
,如果只是为了对称。
case XMLReader::END_ELEMENT:
switch($xml->name) {
case 'author':
echo("-" . $xml->name);
break;
}
}
break;
由于编码风格,问题出现了。简化代码。例如:
$xml = new XMLReader();
$xml->open("php://stdin");
while($xml->read()) {
switch($xml->nodeType) {
case XMLReader::ELEMENT: {
startElement( $xml->name );
break;
}
case XMLReader::END_ELEMENT: {
endElement( $xml->name );
break;
}
}
}
您可以进一步简化。 PHP有一个XML编组软件包,但您也可以将代码抽象为类。然后,这些类的实例将能够从XML文件中读取(或写入)自身。例如:
$xml = new XMLReader();
$xml->open("php://stdin");
while($xml->read()) {
if( $xml->name == 'author' ) {
$author = new Author();
$author->marshall( $xml );
}
}
这将对象存储的细节与对象本身相关联。每次更改Author
对象时,您都知道必须更改它自动编组的方式。您可以使用适当的设计模式,XML模式等进一步抽象和扩展这些概念。
因此,您的最终代码可能类似于:
$xml = new XMLReader();
$xml->open( "php://stdin" );
$publications = new Publications();
$publications->marshall( $xml );
Publications
对象负责读取XML文档,并在出现关联的XML标记时实例化相应的类:
while($xml->read()) {
$article = new Article();
$article->marshall( $xml );
add( $article );
}
使用PHP编组框架来节省时间和精力。考虑XML_Serializer: