Добрый день хабр!
Довольно часто используя в своих проектах SimpleXml начинаешь задумываться об отсутствии в нем некоторого нужного функционала.
Решил выложить свое расширение, возможно кому-то оно будет полезно.
1) удобное получение значения атрибута и проверка значения атрибута:
Довольно удобно проверять значение конкретного атрибута одной функцией.
При указании имени атрибута первым функция проверяет наличие атрибута с этим именем.
При указании имени и значения функция проверяет существует ли элемент с данным именем и значением.
2) удаление атрибута:
т.к не всегда хак с unset работает — лучше использовать DOM
При указании имени атрибута первым функция удаляет атрибут с этим именем.
При указании имени и значения функция удаляет элемент с данным именем и значением.
3) Для изменения и добавления атрибута
С атрибутами закончено — преходим к элементам:
1) Проверка на наличие потомков
2) Удаление элемента
3) Рекурсивный поиск элементов по имени
array_repack() — преобразует 2 мерный массив в 1-х мерный дополняя его элементами из вложенных массивов
Это нужно для того, чтобы в результате поиска был один одномерный массив со всеми найденными элементами вместо нескольких
вложенных массивов.
4) Рекурсивный поиск элементов по атрибутам
5) Рекурсивное удаление элементов по имени
6) Рекурсивное удаление элементов по имени и значению атрибута
В итоге получается небольшое расширение, немного облегчающее работу с XML
А уже выгрузка XML из файла не проблема
Если есть замечания по статье, коду или найденные баги — отписывайтесь в комментариях или в ЛС
Довольно часто используя в своих проектах SimpleXml начинаешь задумываться об отсутствии в нем некоторого нужного функционала.
Решил выложить свое расширение, возможно кому-то оно будет полезно.
1) удобное получение значения атрибута и проверка значения атрибута:
function get_attr($attr,$value=false){
if($value){
foreach($this->attributes() as $e_attr => $e_value){
if($e_attr==$attr&&$e_value==$value){
return $e_value;
}
}
}else{
foreach($this->attributes() as $e_attr => $e_value){
if($e_attr==$attr){
return $e_value;
}
}
}
return false;
}
Довольно удобно проверять значение конкретного атрибута одной функцией.
$element->get_attr('имя аттрибута',['значение']);
При указании имени атрибута первым функция проверяет наличие атрибута с этим именем.
При указании имени и значения функция проверяет существует ли элемент с данным именем и значением.
2) удаление атрибута:
т.к не всегда хак с unset работает — лучше использовать DOM
function del_attr($attr,$value=false){
$dom = dom_import_simplexml($this);
if($value){
if($this->get_attr($attr,$value)){
$dom->removeAttribute($attr);
}
}else{
if($this->get_attr($attr)){
$dom->removeAttribute($attr);
}
}
}
При указании имени атрибута первым функция удаляет атрибут с этим именем.
При указании имени и значения функция удаляет элемент с данным именем и значением.
3) Для изменения и добавления атрибута
function add_attr($attr,$value=false){
$dom = dom_import_simplexml($this);
if($value){
if($this->get_attr($attr)){
$dom->removeAttribute($attr);
}
$dom->setAttribute($attr,$value);
}else{
if($this->get_attr($attr)){
$dom->removeAttribute($attr);
}
$dom->setAttribute($attr,'');
}
}
С атрибутами закончено — преходим к элементам:
1) Проверка на наличие потомков
function is_leaf(){
return !$this->children()?true:false;
}
2) Удаление элемента
function del_node(){
$dom = dom_import_simplexml($this);
$dom->parentNode->removeChild($dom);
}
3) Рекурсивный поиск элементов по имени
function search_child_by_name($name){
$rez = false;
$ret = false;
if(!$this->is_leaf()){
foreach($this->children() as $key => $child ){
$rez[] = $child->search_child_by_name($name);
}
foreach($rez as $key => $elm){
if(!$elm){unset($rez[$key]);}
}
}
if($this->getName()==$name){
$rez[]=$this;
}
if($rez){
$ret = $this->array_repack($rez);
return $ret;
}
}
array_repack() — преобразует 2 мерный массив в 1-х мерный дополняя его элементами из вложенных массивов
Это нужно для того, чтобы в результате поиска был один одномерный массив со всеми найденными элементами вместо нескольких
вложенных массивов.
private function array_repack($array){
$ret = false;
foreach($array as $elm){
if(is_array($elm)){
foreach($elm as $elm2){
$ret[]=$elm2;
}
}
else{
$ret[]=$elm;
}
}
return $ret;
}
4) Рекурсивный поиск элементов по атрибутам
# Поиск элементов по атрибутам
function search_child_by_attr($attr,$val=false){
$rez = false;
$ret = false;
if(!$this->is_leaf()){
foreach($this->children() as $key => $child ){
$rez[] = $child->search_child_by_attr($attr,$val);
}
foreach($rez as $key => $elm){
if(!$elm){unset($rez[$key]);}
}
}
if($val){
if($this->get_attr($attr,$val)){
$rez[]=$this;
}
}else{
if($this->get_attr($attr)){
$rez[]=$this;
}
}
if($rez){
$ret = $this->array_repack($rez);
return $ret;
}
}
5) Рекурсивное удаление элементов по имени
function del_child_by_name($name){
$childs = $this->search_child_by_name($name);
foreach($childs as $child){
$child->del_node();
}
}
6) Рекурсивное удаление элементов по имени и значению атрибута
function del_child_by_attr($attr,$value=false){
$childs = $this->search_child_by_attr($attr,$value);
foreach($childs as $child){
$child->del_node();
}
}
В итоге получается небольшое расширение, немного облегчающее работу с XML
# Расширение SimpleXML
class SimpleXmlEx extends SimpleXMLElement{
#Получение атрибута
function get_attr($attr,$value=false){
if($value){
foreach($this->attributes() as $e_attr => $e_value){
if($e_attr==$attr&&$e_value==$value){
return $e_value;
}
}
}else{
foreach($this->attributes() as $e_attr => $e_value){
if($e_attr==$attr){
return $e_value;
}
}
}
return false;
}
#Удаление атрибута
function del_attr($attr,$value=false){
$dom = dom_import_simplexml($this);
if($value){
if($this->get_attr($attr,$value)){
$dom->removeAttribute($attr);
}
}else{
if($this->get_attr($attr)){
$dom->removeAttribute($attr);
}
}
}
#Добавление/изменение атрибута
function add_attr($attr,$value=false){
$dom = dom_import_simplexml($this);
if($value){
if($this->get_attr($attr)){
$dom->removeAttribute($attr);
}
$dom->setAttribute($attr,$value);
}else{
if($this->get_attr($attr)){
$dom->removeAttribute($attr);
}
$dom->setAttribute($attr,'');
}
}
#Проверка атрибута на наличие потомков
function is_leaf(){
return !$this->children()?true:false;
}
#Удаление ноды
function del_node(){
$dom = dom_import_simplexml($this);
$dom->parentNode->removeChild($dom);
}
#Приведение 2-х мерного массива к 1 мерному
private function array_repack($array){
$ret = false;
foreach($array as $elm){
if(is_array($elm)){
foreach($elm as $elm2){
$ret[]=$elm2;
}
}
else{
$ret[]=$elm;
}
}
return $ret;
}
#Поиск элементов среди потомков по имени
function search_child_by_name($name){
$rez = false;
$ret = false;
if(!$this->is_leaf()){
foreach($this->children() as $key => $child ){
$rez[] = $child->search_child_by_name($name);
}
foreach($rez as $key => $elm){
if(!$elm){unset($rez[$key]);}
}
}
if($this->getName()==$name){
$rez[]=$this;
}
if($rez){
$ret = $this->array_repack($rez);
return $ret;
}
}
# Поиск элементов по атрибутам
function search_child_by_attr($attr,$val=false){
$rez = false;
$ret = false;
if(!$this->is_leaf()){
foreach($this->children() as $key => $child ){
$rez[] = $child->search_child_by_attr($attr,$val);
}
foreach($rez as $key => $elm){
if(!$elm){unset($rez[$key]);}
}
}
if($val){
if($this->get_attr($attr,$val)){
$rez[]=$this;
}
}else{
if($this->get_attr($attr)){
$rez[]=$this;
}
}
if($rez){
$ret = $this->array_repack($rez);
return $ret;
}
}
#Удаление элементов по имени
function del_child_by_name($name){
$childs = $this->search_child_by_name($name);
foreach($childs as $child){
$child->del_node();
}
}
#Удаление элементов по атрибутам
function del_child_by_attr($attr,$value=false){
$childs = $this->search_child_by_attr($attr,$value);
foreach($childs as $child){
$child->del_node();
}
}
}
А уже выгрузка XML из файла не проблема
$myxml = simplexml_load_file('file.xml','SimpleXmlEx');
Если есть замечания по статье, коду или найденные баги — отписывайтесь в комментариях или в ЛС