Удалить определенную строку очень просто:
<?php
$xml = '<x>
<y>some text</y>
<y>[ID] hello</y>
<y>world [/ID]</y>
<y>some text</y>
<y>some text</y>
</x>';
$d = new DOMDocument();
$d->loadXML($xml);
$x = new DOMXPath($d);
foreach($x->query('//text()[(contains(.,\'[ID]\') or contains(.,\'[/ID]\'))]') as $elm){
$elm->nodeValue = preg_replace('/\[\/?ID\]/','',$elm->nodeValue);
}
var_dump($d->saveXML());
?>
При удалении текстовых узлов в определенном теге можно изменить эти preg_replace на эти 2:
$elm->nodeValue = preg_replace('/\[ID\].*$/','',$elm->nodeValue);
$elm->nodeValue = preg_replace('/^.*\[/ID\]/','',$elm->nodeValue);
В результате для вашегопример:
<x>
<y>some text</y>
<y></y>
<y></y>
<y>some text</y>
<y>some text</y>
</x>
Однако удаление тегов между ними без повреждения правильно сформированного XML довольно сложно.Прежде чем углубляться в множество действий DOM, как бы вы хотели обработать:
An [/ ID] выше в дереве DOM:
<foo>[ID] foo
<bar> lorem [/ID] ipsum </bar>
</foo>
An [/ ID] ниже в DOM-дереве
<foo> foo
<bar> lorem [ID] ipsum </bar>
[/ID]
</foo>
И открывать / закрывать охватывающие братья и сестры, как в вашем примере:
<foo> foo
<bar> lorem [ID] ipsum </bar>
<bar> lorem [/ID] ipsum </bar>
</foo>
И настоящий нарушитель порядкавопрос: возможно ли вложение, правильное ли это вложение и что оно должно делать?
<foo> foo
<bar> lo [ID] rem [ID] ipsum </bar>
<bar> lorem [/ID] ipsum </bar>
[/ID]
</foo>
Без дальнейшего знания того, как следует обрабатывать эти случаи, реального ответа нет.
Правка, более подробная информация была предоставлена, фактическое, отказоустойчивое решение (т. Е. Анализ XML, не использовать регулярные выражения) кажется довольно длинным, но будет работать в 99,99% случаев (личные опечатки и мозговые ошибки, конечно, исключаются:)):
<?php
$xml = '<x>
<y>some text</y>
<y>
<a> something </a>
well [ID] hello
<a> and then some</a>
</y>
<y>some text</y>
<x>
world
<a> also </a>
foobar [/ID] something
<a> these nodes </a>
</x>
<y>some text</y>
<y>some text</y>
</x>';
echo $xml;
$d = new DOMDocument();
$d->loadXML($xml);
$x = new DOMXPath($d);
foreach($x->query('//text()[contains(.,\'[ID]\')]') as $elm){
//if this node also contains [/ID], replace and be done:
if(($startpos = strpos($elm->nodeValue,'[ID]'))!==false && $endpos = strpos($elm->nodeValue,'[/ID]',$startpos)){
$elm->replaceData($startpos, $endpos-$startpos + 5,'');
var_dump($d->saveXML($elm));
continue;
}
//delete all siblings of this textnode not being text and having [/ID]
while($elm->nextSibling){
if(!($elm->nextSibling instanceof DOMTEXT) || ($pos =strpos($elm->nodeValue,'[/ID]'))===false){
$elm->parentNode->removeChild($elm->nextSibling);
} else {
//id found in same element, replace and go to next [ID]
$elm->parentNode->appendChild(new DOMTExt(substr($elm->nextSibling->nodeValue,$pos+5)));
$elm->parentNode->removeChild($elm->nextSibling);
continue 2;
}
}
//siblings of textnode deleted, string truncated to before [ID], now let's delete intermediate nodes
while($sibling = $elm->parentNode->nextSibling){ // in case of example: other <y> elements:
//loop though childnodes and search a textnode with [/ID]
while($child = $sibling->firstChild){
//delete if not a textnode
if(!($child instanceof DOMText)){
$sibling->removeChild($child);
continue;
}
//we have text, check for [/ID]
if(($pos = strpos($child->nodeValue,'[/ID]'))!==false){
//add remaining text in textnode:
$elm->appendData(substr($child->nodeValue,$pos+5));
//remove current textnode with match:
$sibling->removeChild($child);
//sanity check: [ID] was in <y>, is [/ID]?
if($sibling->tagName!= $elm->parentNode->tagname){
trigger_error('[/ID] found in other tag then [/ID]: '.$sibling->tagName.'<>'.$elm->parentNode->tagName, E_USER_NOTICE);
}
//add remaining childs of sibling to parent of [ID]:
while($sibling->firstChild){
$elm->parentNode->appendChild($sibling->firstChild);
}
//delete the sibling that was found to hold [/ID]
$sibling->parentNode->removeChild($sibling);
//done: end both whiles
break 2;
}
//textnode, but no [/ID], so remove:
$sibling->removeChild($child);
}
//no child, no text, so no [/ID], remove:
$elm->parentNode->parentNode->removeChild($sibling);
}
}
var_dump($d->saveXML());
?>