2015-09-26 2 views
4

У меня есть XML:Удаление узлов в XML с помощью XPath и PHP

<root> 
    <level name="main"> 
     <level name="sub_1"> 
     <content id="abc123" /> 
     </level> 
    </level> 
</root> 

Я хотел бы найти узел с id, который abc123 и удалить <content> и его родителей <level>

So конечным результатом будет:

<root> 
    <level name="main"> 
    </level> 
</root> 

Я пробовал это на PHP без результата, что я делаю неправильно?

$doc = new DOMDocument; 
$doc->loadxml($xml_from_file); 
$xpath = new DOMXPath($doc); 
$node_list = $xpath->query("content[@id='abc123']/parent::*"); 
$node = $node_list->item(0); 
$doc->removeChild($node); 
+0

'DOMDocument :: loadXML' принимает XML. Используйте 'DOMDocument :: load' для имени файла. – PHPglue

+0

Спасибо. Я фактически загружаю его из строки в 'loadXML' –

ответ

2

Вот два вопроса источника.

Выражение соответствует только дочерним узлам. Вам нужно запустить его с // для соответствия любому узлу: //content[@id='abc123']/parent::*.

Найденный узел не является дочерним элементом документа, поэтому его необходимо удалить из собственного родителя: $node->parentNode->removeChild($node);.

Предлагаю использовать foreach, чтобы избежать проблем, если узел не существует.

$document = new DOMDocument; 
$document->loadxml($xmlString); 
$xpath = new DOMXPath($document); 

foreach ($xpath->evaluate("//content[@id='abc123']/parent::*") as $node) { 
    $node->parentNode->removeChild($node); 
} 

echo $document->saveXml(); 
+0

Работает отлично! Большое большое спасибо. –

-2

Это своего рода хак, но я получил его для работы с вашим примером. Одна проблема, вероятно, связана с вашим запросом xpath - обратите внимание на // в начале.

$xml_string = '<root> 
    <level name="main"> 
     <level name="sub_1"> 
      <content id="abc123" /> 
     </level> 
    </level> 
</root>'; 

// using SimpleXMLElement instead of DOMDocument 
$xml = new SimpleXMLElement($xml_string); 

// standardize the string version of the xml so str_replace works 
$xml_string = $xml->asXML(); 

// search for the target; note the // at the beginning of the query 
$target = $xml->xpath("//content[@id='abc123']/parent::*"); 

// use simple string replacement to remove the node 
echo str_replace($target[0]->asXML(), '', $xml_string); 

Не очень элегантный, но, похоже, он позаботился о вашей проблеме.

+1

Когда вы работаете с XML, как правило, это плохая идея, чтобы попытаться манипулировать им со строковыми функциями, поскольку структура сложна и тонкая (подумайте об объектах, разделах cdata, комментариях, dtd). Почти всегда лучше использовать XML-классы, такие как доступные для DOM, XPath, XQuery или XSLT. – Abel

2
<?php 

$xml_from_file = '<root> 
    <level name="main"> 
     <level name="sub_1"> 
     <content id="abc123" /> 
     </level> 
    </level> 
</root>'; 

$doc = new DOMDocument; 
$doc->loadxml($xml_from_file); 
$xpath_selector = new DOMXPath($doc); 
//Here you forget at the begin the // 
$node_list = $xpath_selector->query("//content[@id='abc123']/parent::*"); 
//here you get the reference to the parent of content 
$node = $node_list->item(0); 
//but for remove the child you need to go to the parent node 
$node->parentNode->removeChild($node); 
echo $doc->saveXML(); 

?> 

Выход:

<root> 
    <level name="main"> 
    </level> 
</root> 
Смежные вопросы