Эта тема на forum.dklab.ru


Олег Мурашов: XML/PHP проблемы с класом DOMDocument. Очень нужна помощь!!!
Честно скажу, особо поиском не пользовался, так как случай скорее частный. Ответа в документации не нашел, хотя читал внимательно
Вот что нужно и что есть.
1. Некий скрипт хранит свои настройки (константы) в xml представлении. Настройки могут меняться, поэтому структура xml такова (оставил только 3 строки)


<?xml version="1.0" encoding="windows-1251"?>
<constants>
<const name="REDIRECT_STRATEGY" value="http" default="http" />
<const name="SITE_ROOT_ID" value="1" default="1" />
<const name="CAT_ROOT_ID" value="2" default="2" />
</constants>


Параметр default хранит значение по-умолчанию, а value измененное. Мне нужно параметр value вынести в отдельный файл такойже структуры. Причем только в том случае, если значение задано. То есть, основной файл хранит данные по всем константам, а второй хранит только те константы, значения которых отличны от дефолтных.

Как происходит обработка первого файла. Вот примерный код


$dom = new DOMDocument();
$dom->load('constants.xml');
$root = $dom->documentElement;
$cnodes = $root->childNodes;


Как я понимаю, $cnodes - массив объектов. Во всяком случае по нему можно пройтись через


foreach ($cnodes as $k=>$v) {
$name = $v->getAttribute('name');
$value = $v->getAttribute('value');
}


Как мне видится формирование файла с текущими значениями. Попросту проверяем, совпадает ли дефолтное значение с тем, что нам предлагается. Если да, то удаляем "дитя" из node листа, если нет, то там его оставляем, после чего пишем наш node лист со всем остальным в новый файла (там должны остаться только измененные константы), например так

$dom->save('constants_values.xml');

Теперь суть проблемы. Проблема заключается в именно в удалении child'a. Из мануала я понял только то, что его можно удалить только так


$child = $root = getElementsByTagName('const')->item(0);
$root->removeChild($child);


В этом то и проблема. Если бы к элементу можно было обратиться по параметру name, было бы очень здорово - вытащил, проверил, удалил или оставил. А так, мало того, что получается цикл в цикле, так $child не имеет метода getAttribute
Да и вообще, даже через задницу, но сделать не получилось.

Остается надеяться только на Вашу помощь. Я уже все мозги себе убил. Не получается хоть ты тресни!
Г.О.:

$child = $root = getElementsByTagName('const')->item(0);
$root->removeChild($child);

Простите, что это?
Вы удаляете первый элемент <const> из себя же самого.
Олег Мурашов:
Опечатался. Должно быть constants
Можно ли обратиться к child'у не только по его порядковому имени а как-нибудь еще?
Г.О.:
Можно ли обратиться к child'у не только по его порядковому имени а как-нибудь еще?
По идентификатору. getElemenById(). Только мне кажется, вам этого не надо.
$cnodes = $root->childNodes;
Не childNodes. Туда может набиться всякое барахло, текстовые ноды, например.
$cnodes = $root->getElementsByTagName("const");
Попросту проверяем, совпадает ли дефолтное значение с тем, что нам предлагается. Если да, то удаляем "дитя" из node листа, если нет, то там его оставляем, после чего пишем наш node лист со всем остальным в новый файла (там должны остаться только измененные константы), например так
Непонимаю. Зачем удалять дитя? Зачем что-то куда-то писать.
Как мне кажется, вам нужно:
— Открыть два документа: (1) исходный, (2) новый, куда пишутся измененные значения.
— Пройтись по всем <const>.
— Проверить у каждого, если value != default, в (2) добавить нод <const name="..." value="..." />
— Удалить value у ВСЕХ элементов в (1), оставив только default
— Перезаписать (1), сохранить (2)
Олег Мурашов:
Как мне кажется, вам нужно:
Я примерно о том же и говорю, !только:
1. Второго файла может и вовсе не существовать, допустим если все константы на текущий момент дефолтны.
2. В первом файле останется только параметр default

Как это все должно работать:
1. Данные о значении констант могут изменяться из формы. Имеено после обработки формы и должна происходить проверка равно ли значения default из первого файла значению константы пришедшему из формы:
1. Если не равно, значит нужно поместить во второй файл (оставить в нод-листе)
2. Если равно, значит во второй файл не помещаем (удаляем из нод-листа)
2. Нод лист пишем во второй файл - получаем в нем только измененные значения
Пошел попробуй, если что код выложу
Олег Мурашов:
Сделал! Криво, наверное, но работает - пока это главное :)


<?php

$array['CAT_ROOT_ID'] = 10;
$array['USER_TREE_DEPTH'] = 15;

$constants_file = "constants.xml";
$constants_values = "constants_values.xml";

$dom = new DOMDocument();
$dom->load($constants_file);
$root = $dom->documentElement;
$cnodes = $root->childNodes;

$vdom = new DOMDocument();
$vdom->load($constants_file);
$vroot = $vdom->documentElement;
$vcnodes = $vroot->childNodes;

foreach ($cnodes as $k => $v) {
if ( $v->nodeType == XML_ELEMENT_NODE ) {
$name = $v->getAttribute('name');
$default = $v->getAttribute('default');

$counter = $cnodes->length;
for ( $i = 0; $i <= $counter; $i++ ) {
$child = $vroot->getElementsByTagName('const')->item($i);

if ( is_object($child) && $child->nodeType == XML_ELEMENT_NODE ) {
$child_name = $child->getAttribute('name');

if ( (!isset($array[$name]) || $array[$name] == $default ) && $name == $child_name ) {
$vroot->removeChild($child);
} else {
if ( isset($array[$name]) ) {
$child->setAttribute('value', $array[$name]);
$child->removeAttribute('default');
$child->removeAttribute('comment');
}
}
}
}
}
}

$vdom->save($constants_values);

?>


Массив $array имитирует данные из формы

Эта тема на forum.dklab.ru