2

I have an XML like below

<entries>
  <entry>
    <title lang="en">Sample</title>
    <entrydate>0</entrydate>
    <contents>0</contents>
    <entrynum>0</entrynum>
  </entry>
  <entry>
    <title lang="fr">Sample</title>
    <entrydate>1</entrydate>
    <contents>1</contents>
    <entrynum>1</entrynum>
  </entry>
</entries>

Is there a way in PHP to delete the parent node (entry) based on the title lang attribute? I need to keep only the en ones, so in this case I would need to get the XML without the second entry node.

I tried looking around but couldn't find any solution...

Mohammad
  • 21,175
  • 15
  • 55
  • 84
gege
  • 91
  • 7
  • Have you tried to use [SimpleXML](http://php.net/manual/en/book.simplexml.php)? – Ruslan Osmanov Oct 12 '16 at 15:20
  • Yes is the first thing I tried, I use it to retrieve values. But I can't find any example about parsing using the 'lang' attribute and also my more specific need of deleting the whole parent based on the child language. – gege Oct 12 '16 at 15:34

3 Answers3

1

You need to use DOMDocument class to parse string to XML document. Then use DOMXpath class to find target element in document and use DOMNode::removeChild() to remove selected element from document.

$doc = new DOMDocument(); 
$doc->loadXML($xml);
$xpath = new DOMXpath($doc);
// select target entry tag
$entry = $xpath->query("//entry[title[@lang='fr']]")->item(0);
// remove selected element
$entry->parentNode->removeChild($entry);
$xml = $doc->savexml();

You can check result in demo

Mohammad
  • 21,175
  • 15
  • 55
  • 84
  • Hi yes this works as a starting base, thanks! I'm going to find a way to actually have it going through all the xml because with the item(0) it only removes the first one, while I need to do it for all the entries matching. – gege Oct 12 '16 at 16:01
  • @gege If you have multiple `` in your document, remove `item(0)` and iterate `$entry` using `foreach()` and remove every item in loop. – Mohammad Oct 12 '16 at 16:08
0

You could also read your file and generated new one with your modification

<?php
$entries = array('title' => "What's For Dinner",
'link' => 'http://menu.example.com/',
'description' => 'Choose what to eat tonight.');
print "<entries>\n";
foreach ($entries as $element => $content) {
print " <$element>";
print htmlentities($content);
print "</$element>\n";
}
print "</entries>";
?>
ali
  • 1
0

Use the method described in this answer, i.e.

<?php
$xml = simplexml_load_file('1.xml');

$del_items = [];
foreach ($xml->entry as $e) {
  $attr = $e->title->attributes();
  if ($attr && $attr['lang'] != 'en') {
    $del_items []= $e;
  }
}

foreach ($del_items as $e) {
  $dom = dom_import_simplexml($e);
  $dom->parentNode->removeChild($dom);
}

echo $xml->asXML();

Output

<?xml version="1.0" encoding="UTF-8"?>
<entries>
  <entry>
    <title lang="en">Sample</title>
    <entrydate>0</entrydate>
    <contents>0</contents>
    <entrynum>0</entrynum>
  </entry>

</entries>

The items cannot be removed within the first loop, because otherwise we may break the iteration chain. Instead, we collect the entry objects into $del_items array, then remove them from XML in separate loop.

Community
  • 1
  • 1
Ruslan Osmanov
  • 20,486
  • 7
  • 46
  • 60