php解析xml,并将xml转换为层级数组
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php解析xml,并将xml转换为层级数组相关的知识,希望对你有一定的参考价值。
1)xml_parser_create([ string $encoding ] ):建立一个新的xml解析器并返回可被其他xml函数使用的资源句柄,
参数$encoding:
php4,中用来只指定要被解析的xml输入的字符编码方式;
php5,自动侦测输入xml的编码,encoding仅用来指定解析后输出数据的编码
默认:输入编码=输出编码
php5.0.2+默认编码utf-8;之前版本,ISO-8859-1
2)bool xml_parser_set_option(resource $parser,int $option,mixed $value):为指定的的xml解析进行选项设置
parser:指向要设置选项信息的xml解析器指针
option:要设置选项的名称
value:要设置选项的值
设置成功返回true,失败返回false
选项 数据类型 描述
XML_OPTION_CASE_FOLDING int 控制在该xml解析器中大小写是否有效。默认有效,0原样输出,1转换为大写,只控制输出样式
XML_OPTION_SKIP_TAGSTART int 指明在一个标记名前应略过几个字符
XML_OPTION_SKIP_WHITE int 是否略过由空白字符组成的值
XML_OPTION_TARGET_ENCODING string
3)int xml_parse_into_struct(resource $parser,string $data,array &$values [,array &$index]):将xml
文件解析到两个对应的数组中,index参数含有指向values数组中对应值的指针,该函数返回的是一级数组,不想dom树那样有层级关系
失败返回0,成功返回1
4)eg:
源文件:
<?xml version="1.0" encoding="utf-8"?>
<newdata>
<version a="xxx">aaaa</version>
<sample><![CDATA[0]]></sample>
<all><![CDATA[https]]></all>
</newdata>
value结果:
Array
(
[0] => Array
(
//标签名
[tag] => newdata
//节点状态,open:含有子标签,起始标签;close:open的闭合部分;complete:无子标签
[type] => open
//层级
[level] => 1
)
[1] => Array
(
[tag] => version
[type] => complete
[level] => 2
//节点属性数组
[attributes] => Array
(
[a] => xxx
)
//节点值
[value] => aaaa
)
[2] => Array
(
[tag] => sample
[type] => complete
[level] => 2
[value] => 0
)
[3] => Array
(
[tag] => all
[type] => complete
[level] => 2
[value] => https
)
[4] => Array
(
[tag] => newdata
[type] => close
[level] => 1
)
)
索引结果:
Array
(
//节点名称
[newdata] => Array
(
[0] => 0//节点起始索引
[1] => 4//节点结束索引
)
[version] => Array
(
[0] => 1
)
[sample] => Array
(
[0] => 2
)
[all] => Array
(
[0] => 3
)
)
5)将xml转换为array的函数:
/**
* 将xml字符串转换为数组
* @param string $contents
* @param string $encoding
* @param int $get_attrbutes
* @param string $priority
* @param array
*/
public static function xml2Array($contents = NULL, $encoding = ‘UTF-8‘, $get_attributes = 1, $priority = ‘tag‘) {
if(!$contents) {
return array();
}
if(!function_exists(‘xml_parser_create‘)) {
return array();
}
//xml解析器
$parser = xml_parser_create(‘‘);
xml_parser_set_option($parser,XML_OPTION_TARGET_ENCODING,$encoding);
//将标签原样输出,不转换成大写
xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,0);
//是否忽略空白字符
xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE,1);
//$xml_values,$index引用类型,将文本解析到指定的数组变量中
xml_parse_into_struct($parser, trim($contents), $xml_values/*,$index*/);
//释放解析器
xml_parser_free($parser);
if(!$xml_values)
return array();
$xml_array = array();
$parents = array();
$opened_tags = array();
$arr = array();
//当前操作结构的指针
$current = & $xml_array;
//同级结构下重复标签的计数
$repeated_tag_index = array();
foreach ($xml_values as $data) {
//删除属性和值,确保每次用到的是新的
unset($attributes, $value);
//将标签结构数组,释放到当前的变量域中
extract($data);
//存当前标签的结果
$result = array();
//存属性
$attributes_data = array();
//标签有value
if(isset($value)) {
if($priority == ‘tag‘){
$result = trim($value);
}else{
$result[‘value‘] = trim($value);
}
}
//标签有属性,且不忽略
if($get_attributes && isset($attributes)) {
foreach ($attributes as $attr => $val) {
if ($priority == ‘tag‘){//放入单独记录属性的数组中
$attributes_data[$attr] = $val;
}else{//统一放入$result中
$result[‘attr‘][$attr] = $val;
}
}
}
//处理节点关系
if ($type == "open") {//有子节点标签
$parent[$level - 1] = & $current; //$parent[$level - 1],指向复合标签的起始处
if (!is_array($current) || (!in_array($tag, array_keys($current)))) {//xml复合标签的第一个
$current[$tag] = $result;//属性独立
/*处理结果
[tag] => Array
(
[value] => aaaa,
[attr] => Array
(
[a] => xxx
)
)
*/
if ($attributes_data){
$current[$tag . ‘_attr‘] = $attributes_data;
/*处理结果
[tag] => xxxx,
[tag_attr] => Array
(
[a] => xxx
)
*/
}
$repeated_tag_index[$tag . ‘_‘ . $level] = 1;//记录同级中该标签重复的个数
//指针重新指向符合标签的子标签
$current = & $current[$tag];
}else {
if (isset($current[$tag][0])) {//第3+个同级复合标签
$current[$tag][$repeated_tag_index[$tag . ‘_‘ . $level]] = $result;
$repeated_tag_index[$tag . ‘_‘ . $level] ++;
} else {//第2个同级复合标签
//在关联数组外包一层索引数组
$current[$tag] = array(
$current[$tag],
$result
);
$repeated_tag_index[$tag . ‘_‘ . $level] = 2;
//此处只记录第一个重复标签的属性,可能有bug,需注意!
//要想区别各子标签的属性,需要将$priority设成非‘tag‘
if (isset($current[$tag . ‘_attr‘])) {
$current[$tag][‘0_attr‘] = $current[$tag . ‘_attr‘];
unset($current[$tag . ‘_attr‘]);
}
}
//记录最后一个重复子标签的索引
$last_item_index = $repeated_tag_index[$tag . ‘_‘ . $level] - 1;
//指针指向下一个子标签
$current = & $current[$tag][$last_item_index];
}
} elseif ($type == "complete") {
//第一个complete类型的标签
if (!isset($current[$tag])) {
$current[$tag] = $result;
$repeated_tag_index[$tag . ‘_‘ . $level] = 1;
if ($priority == ‘tag‘ && $attributes_data)
$current[$tag . ‘_attr‘] = $attributes_data;
}
else {
//第3+个同级子标签
//此处只有$current[$tag][0],不行,因为可能索引到字符串的第一个字符
if(isset($current[$tag][0]) && !is_array($current[$tag])){
print_r($current);exit();
}
if(isset($current[$tag][0]) && is_array($current[$tag])) {
$current[$tag][$repeated_tag_index[$tag . ‘_‘ . $level]] = $result;
//子标签的属性不忽略
if ($get_attributes && $priority == ‘tag‘ && $attributes_data) {
$current[$tag][$repeated_tag_index[$tag . ‘_‘ . $level] . ‘_attr‘] = $attributes_data;
}
$repeated_tag_index[$tag . ‘_‘ . $level] ++;
}else{//第2个同级子标签
$current[$tag] = array(
$current[$tag],
$result
);
$repeated_tag_index[$tag . ‘_‘ . $level] = 1;
if ($priority == ‘tag‘ && $get_attributes) {
if (isset($current[$tag . ‘_attr‘])) {
$current[$tag][‘0_attr‘] = $current[$tag . ‘_attr‘];
unset($current[$tag . ‘_attr‘]);
}
if ($attributes_data) {
$current[$tag][$repeated_tag_index[$tag . ‘_‘ . $level] . ‘_attr‘] = $attributes_data;
}
}
$repeated_tag_index[$tag . ‘_‘ . $level] ++;
}
}
}elseif($type == ‘close‘){
//闭合标签和起始标签level相同,因此进入complete类型的子标签后,可以通过父节点的close标签,可以指回到父节点
$current = & $parent[$level - 1];
}
}
return $xml_array;
}
本文出自 “虎哥的博客” 博客,请务必保留此出处http://7613577.blog.51cto.com/7603577/1743533
以上是关于php解析xml,并将xml转换为层级数组的主要内容,如果未能解决你的问题,请参考以下文章
Python面试必考重点之数据存储第二关——XML文档和字典的互转