之前在项目中有读取XML的需求,一开始采用的是simplexml将xml文件全部load到内存里,然后一个节点一个节点读的方式,后来随着XML文件的增大,内存被撑爆了。于是赶紧想办法,于是有了流式读取。一开始老大给了我一个封装XMLReader的类,但是我发现这个类不是很符合我的要求,于是又把XMLReader按我的要求重新封装了一遍,在此感谢老大moon。
目前我的类非常简单就提供几个方法,我提供了Demo供大家参考使用。话不多说上代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
<?php /** *
* @author gaoran
* Another new parser for (X|HT)ML(stream version)
* @version 1.0 2014-06-02 18:10:00
* 感谢我的老大moon,之前moon写了一个XMLParser的类,但是我觉得不是我想要的,于是自己重新封装了一遍,自我感觉简单,好用
*/
class New_XMLParser extends
XMLReader{
private
$_tagName ;
/**
* 设置打开xml文件的路径
*/
public
function open( $xml , $encoding =null, $option =null){
parent::open( $xml , $encoding , $option );
}
/**
* 设置要读取数据的节点名称
*/
public
function setTagName( $tagName ){
$this ->_tagName = $tagName ;
}
/**
* 每次读取一个节点数据,以数组格式返回
*/
public
function getData(){
if (! $this ->_tagName){ return
false;}
while ( $this ->read()){
$tagName
= $this ->name;
if ( $this ->nodeType == XMLReader::ELEMENT && $this ->_tagName == $tagName ){
$dom
= new DOMDocument( ‘1.0‘ , ‘utf-8‘ );
$d
= $dom ->importNode( $this ->expand(), true);
//$dom->appendChild($d);
$appinfo
= $this ->domToArray( $d );
return
$appinfo ;
}
}
return
false;
}
/**
*
* @param SimpleXMLElement|DOMDocument|DOMNode $obj SimpleXMLElement, DOMDocument or DOMNode instance
* @return array Array representation of the XML structure.
*/
public
static function domToArray( $obj ) {
if
( $obj instanceof DOMNode) {
$obj
= simplexml_import_dom( $obj );
}
$result
= array ();
$namespaces
= array_merge ( array ( ‘‘
=> ‘‘ ), $obj ->getNamespaces(true));
self::_toArray( $obj , $result , ‘‘ , array_keys ( $namespaces ));
return
$result ;
}
protected
static function _toArray( $xml , & $parentData , $ns , $namespaces ) {
$data
= array ();
foreach
( $namespaces
as $namespace ) {
foreach
( $xml ->attributes( $namespace , true) as
$key => $value ) {
if
(! empty ( $namespace )) {
$key
= $namespace
. ‘:‘ . $key ;
}
$data [ ‘@‘
. $key ] = (string) $value ;
}
foreach
( $xml ->children( $namespace , true) as
$child ) {
self::_toArray( $child , $data , $namespace , $namespaces );
}
}
$asString
= trim((string) $xml );
if
( empty ( $data )) {
$data
= $asString ;
} elseif
(! empty ( $asString )) {
$data [ ‘@‘ ] = $asString ;
}
if
(! empty ( $ns )) {
$ns
.= ‘:‘ ;
}
$name
= $ns . $xml ->getName();
if
(isset( $parentData [ $name ])) {
if
(! is_array ( $parentData [ $name ]) || !isset( $parentData [ $name ][0])) {
$parentData [ $name ] = array ( $parentData [ $name ]);
}
$parentData [ $name ][] = $data ;
} else
{
$parentData [ $name ] = $data ;
}
}
/*
* 关闭XML流
*/
public
function close(){
parent::close();
}
} class
Demo{
public
function run(){
$im
= new New_XMLParser();
$im ->open( ‘yingyonghui‘ );
$im ->setTagName( "webName" );
print_r( $im ->getData());
$im ->setTagName( "webSiteUrl" );
print_r( $im ->getData());
$im ->setTagName( "app" );
print_r( $im ->getData());
//$im->open(‘yingyonghui‘);
$i
= 0;
while ( $i
< 3 && $appinfo
= $im ->getData()){
print_r( $appinfo );
$i
++;
}
$im ->close();
}
} $d = new Demo();
$d ->run();
|
目前够用了,以后继续改进吧,欢迎大家拍砖,一起进步完善。