Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Для профи > SimpleXML, серриализация


Автор: Sergey89 5.9.2007, 18:47
Код

<?php
$xml_str = <<<XML
<?xml version="1.0"?>
<parent>
    <child1>Hello!</child1>
    <child2></child2>
    <child3 />
</parent>
XML;

$xml = new SimpleXMLElement($xml_str);
$xml = (array)$xml;
unserialize(serialize($xml));

Код

SimpleXMLElement Object
(
    [child1] => Hello!
    [child2] => SimpleXMLElement Object
        (
        )

)

Код

O:16:"SimpleXMLElement":2:{s:6:"child1";s:6:"Hello!";s:6:"child3";O:16:"SimpleXMLElement":0:{}}


Суть проблемы в том, что пустые узлы не рассериализовать. Натыкаемся на предупреждение:
Код

Warning: unserialize() [function.unserialize]: Node no longer exists


Одно решение я нашёл:
Код
<?php
$xml = (array)$xml;

foreach ($xml as &$node) {
   if ($node instanceof SimpleXMLElement) {
      $node = null;
   }
}


Но может есть что-то более изящное?

Автор: WolfON 5.9.2007, 18:58
Нет - изящного выхода отсюда нету.

Может быть имеет смысл пересмотреть структуру xml, может-быть сделать child3 атрибутом, если он имеет какой-то смысл.
А если не имеет, то зачем его хранить? можно добавить когда потребуется.

Автор: Sergey89 5.9.2007, 19:00
WolfON, имеется уже готовый XML файл. Хочется всячески исключить правку самого файла, т.к. он находится в ZIP архиве.

Автор: WolfON 5.9.2007, 19:02
Тогда обойдитесь без сериализации а сохраняйте все в xml.
Что мешает?

Автор: Sergey89 5.9.2007, 19:09
WolfON, этот XML файл разбирается скриптом и результат записывается в массив. Чтобы повторно не разбирать XML, сделано кэширование массива через серриализацию.

Автор: WolfON 5.9.2007, 19:14
ну тогда остается только ваш первый вариант

Автор: Sergey89 5.9.2007, 19:24
Пришла в голову ещё одна идея
Код

<?php
$xml_str = <<<XML
<?xml version="1.0"?>
<parent>
    <child1>Hello!</child1>
    <child2></child2>
    <child3 />
</parent>
XML;

$xml = new SimpleXMLElement($xml_str);
$str = str_replace('O:16:"SimpleXMLElement":0:{}', 's:0:"";', serialize((array)$xml));

print_r(unserialize($str));

Автор: Diesel Draft 6.9.2007, 10:34
Я б написал класс, который создает точно такую структуру, а потом серелезирувал

Автор: Sergey89 6.9.2007, 16:59
Diesel Draft, предлагаешь велосипед изобрести и написать программную реализацию SimpleXML? Хотя можно с наследованием от SimpleXML чё-нить замутить.

Автор: WolfON 6.9.2007, 17:04
Уффф... я вот не понимаю - вам нужно уменьшение нагрузки или что?
Решение с циклом самое быстрое.

Автор: Diesel Draft 6.9.2007, 17:37
Sergey89, Насчет наследования. Я пишу объект который наследует SimpleXML. Но припустим на сервере нет SimpleXML тогда я заменяю класс, не меняя имени на другой. Этот класс умеет все то самое, но реализован на РНР

Автор: Sergey89 6.9.2007, 19:12
Цитата(WolfON @  6.9.2007,  17:04 Найти цитируемый пост)
Уффф... я вот не понимаю - вам нужно уменьшение нагрузки или что?
Решение с циклом самое быстрое. 

Отвлекитесь от кэширования и всего прочего. Я сейчас поставил вопрос конкретно о проблеме серриализации SimpleXML объекта. Но вот решение c str_replace всёравно быстрее.

Цитата(Diesel Draft @  6.9.2007,  17:37 Найти цитируемый пост)
Sergey89, Насчет наследования. Я пишу объект который наследует SimpleXML. Но припустим на сервере нет SimpleXML тогда я заменяю класс, не меняя имени на другой. Этот класс умеет все то самое, но реализован на РНР 

Хостинг без поддержки SimpleXML - недохостинг. PHP 4 сдыхает, а на PHP 5 перешёл любой дорожащий клиентами хостер. Но это так... лирическое отступление.

Автор: WolfON 6.9.2007, 19:42
Цитата

Хостинг без поддержки SimpleXML - недохостинг. PHP 4 сдыхает, а на PHP 5 перешёл любой дорожащий клиентами хостер. Но это так... лирическое отступление.

XML у которого имеют смысл пустые элементы - недоxml smile
ну честно - грамотное использование технологии решит проблему сейчас и не возникнет много проблем в дальнейшем.

Автор: Sergey89 6.9.2007, 19:45
WolfON, ну не совсем. Логично, конечно, будет писать <child2 />, но <child2></child2> также имеет право на жизнь.

Автор: Diesel Draft 7.9.2007, 10:13
Sergey89, что тема уже решена?

Автор: Sergey89 7.9.2007, 22:56
Код

<?php
$str = <<<XML
<?xml version="1.0"?>
<root>
    <child1>Hello</child1>
    <child2></child2>
    <child3 />
    <child4>
        <child5></child5>
        <child6>World!</child6>
        <child7><child8 /></child7>
    </child4>
</root>
XML;

function xmlToArray($xml) {
    $xml = (array)$xml;

    foreach ($xml as &$v) {
        if (count($v) && ($v instanceof SimpleXMLElement)) {
            $v = xmlToArray((array)$v);
        } elseif ($v instanceof SimpleXMLElement) {
            $v = null;
        }
    }

    return $xml;
}

$xml = new SimpleXMLElement($str);
print_r(xmlToArray($xml));

С наследованием от SimpleXMLElemtnt ничего не вышло, т.к. конструктор базового класса объявлен как final.

ЗЫ мне кажется, или heredoc ситнаксис действительно не воспринимается как строка? Это я про подсветку кода.

Автор: WolfON 7.9.2007, 23:16
кажется - heredoc это по сути обычный комментарий

Автор: Sergey89 7.9.2007, 23:23
Нет. Это именно один из способов определения строки. http://php.net/heredoc

Автор: WolfON 7.9.2007, 23:41
черт попутал с phpdoc %)

Автор: Endeveit 8.9.2007, 20:38
ПХП не поддерживает десериализацию объектов DOM, SimpleXML и некоторых других (подробнее где-то на bugs.php.net)
В принципе возможно вот такое решение:
Код

<?php
class mySimpleXMLElement implements Serializable
{
    private $obj_instance = null;
    private $xml_instance = '';

    public function __construct($data)
    {
        $this->obj_instance = simplexml_load_string($data);
    }

    public function getInstance()
    {
        return $this->obj_instance;
    }

    public function serialize()
    {
        $this->xml_instance = $this->obj_instance->asXML();
        unset($this->obj_instance);
        return serialize($this->xml_instance);
    }

    public function unserialize($serialized)
    {
        $this->obj_instance = simplexml_load_string(unserialize($serialized));
    }
}

$xml_str = <<<XML
<?xml version="1.0"?>
 <parent>
  <child1>Hello!</child1>
  <child2></child2>
  <child3 />
</parent>
XML;

$xml = new mySimpleXMLElement($xml_str);
$child = $xml->getInstance()->addChild('child4');
$child->addChild('child4_1', 'Whoa!');
$child->addChild('child4_2', 'It works!');

$s_xml = serialize($xml);
var_dump($s_xml);
$o_xml = unserialize($s_xml);
var_dump($o_xml);

Автор: Sergey89 8.9.2007, 21:23
Endeveit, проблема немного в другом. Необходимо привести объект типа SimpleXMLElement к типу array и серриализовать именно массив. За код конечно спасибо, сохраню для себя его.

Автор: Endeveit 8.9.2007, 22:05
Как я уже написал выше, ПХП в любом случае не поддерживает десериализацию объектов DOM, SimpleXML.
P.S. Если честно, не совсем понятна идея с сериализацией именно массива, мое предыдущее решение много лучше и красивее, имхо.

Автор: Endeveit 8.9.2007, 22:30
Но есть еще решение - руками вызывать метод, который будет приводит объект к массиву нужного вида и руками же делать обратное преобразование.
Как-то так, например:
Код

<?php
class mySimpleXMLElement extends SimpleXMLElement
{
    public function toArray()
    {
        $vars = get_object_vars($this);
        foreach ($vars as $k => $v) {
            if (empty($v)) {
                unset($vars[$k]);
            }
        }
        return $vars;
    }
}

function array_to_mySimpleXMLElement($array)
{
    // тут код, который будет создавать новый объект
    // затем проходить по всем элементам массива $array
    // и добавлять их к объекту
}

$xml_str = <<<XML
<?xml version="1.0"?>
 <parent>
  <child1>Hello!</child1>
  <child2></child2>
  <child3 />
</parent>
XML;

$xml = new mySimpleXMLElement($xml_str);

$s_xml = serialize($xml->toArray());
$o_xml = array_to_mySimpleXMLElement(unserialize($s_xml));


Автор: Sergey89 8.9.2007, 22:36
А это тоже самое что я уже написал. Только в виде отдельной функции.

Автор: Endeveit 8.9.2007, 22:44
Ну, тогда только http://forum.vingrad.ru/index.php?showtopic=171212&view=findpost&p=1250299 решение.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)