Мне нужно реализовать следующий алгоритм с SimpleXML:
ПРОБЛЕМЫ:
Как загрузить XML с именованными объектами (например,
).
Чтобы перемещаться по XML, чтобы получить только текстовые узлы … С $sx->xpath('//text()');
Я не могу редактировать узлы, как выбрать текстовые узлы для выпуска?
Вы можете переопределить текстовое содержимое узла, возвращаемого запросом SimpleXML XPath, назначив $node[0]
, например
foreach ( $sx->xpath('//text()') as $text_node ) { $text_node[0] = 'Hello'; }
Однако будьте осторожны, что SimpleXML действительно не имеет представления текстового узла как такового, поэтому такой тип цикла будет вести себя странно, если в элементе есть как дочерние элементы, так и текст.
Например, учитывая XML <a><b>foo<c />bar</b><b>baz quux</b></a>
, два текстовых узла, содержащих foo
и bar
, оба будут представлены в SimpleXML посредством первый элемент <b>
, все содержимое которого будет заменено на 'Hello'
, дважды, как показано ниже ( живая демонстрация здесь ). Используя переменную счетчика в замещаемом тексте, мы можем ясно видеть, что происходит – желаемый результат будет <a><b>Hello 1<c />Hello 2</b><b>Hello 3</b></a>
, но фактическим результатом является <a><b>Hello 2</b><b>Hello 3</b></a>
.
$sx = simplexml_load_string('<a><b>foo<c />bar</b><b>baz quux</b></a>'); $counter = 1; foreach ( $sx->xpath('//text()') as $text_node ) { $text_node[0] = 'Hello ' . $counter++; } echo $sx->asXML();
Подобная манипуляция, по крайней мере, по мере того, как вы создавали проблему (поиск текстовых узлов, а не повторение, возможно, рекурсивно, по определенному набору элементов) гораздо более подходит для DOM API, чем для SimpleXML. Имейте в виду, что между ними нет разницы в производительности (они оба являются обертками вокруг одного и того же синтаксического анализатора XML) и что вы можете комбинировать операции с использованием двух API в одном документе с помощью simplexml_import_dom()
и dom_import_simplexml()
, без дополнительные накладные расходы, поскольку документ не нуждается в повторном анализе.
Вот приведенный выше пример, зафиксированный с использованием смеси SimpleXML и DOM ( live demo ). Если бы это был весь код, вы могли просто анализировать DOM напрямую, но это демонстрирует, как легко их смешивать, если у вас уже есть другой код, управляющий этим документом с помощью SimpleXML. Обратите внимание, что в конце мы выводим XML с использованием исходного объекта SimpleXML – нам не нужно запускать simplexml_import_dom($dom)
, потому что оба объекта относятся к одному и тому же анализируемому «документу» в памяти.
$sx = simplexml_load_string('<a><b>foo<c />bar</b><b>baz quux</b></a>'); $dom = dom_import_simplexml($sx); $counter = 1; $xpath = new DOMXpath($dom->ownerDocument); foreach ( $xpath->query('//text()') as $text_node ) { $text_node->nodeValue = 'Hello ' . $counter++; } echo $sx->asXML();