0

In a nutshell, I'm wondering just how this can be done, since there doesn't (As far as I know) seem to be a way to do this with PHP's SimpleXMLObject setup.

Here's my xml:

<main>
<item><field>1</field></item>
<item><field>2</field></item>
<item><field>2</field></item>
<item><field>4</field></item>
</main>

I'm trying to have it so that only enteries that match the field value of 2 would be returned in a new xml object. The problem is being able to filter out what doesn't match. I've tried using unset, but it only seems to return an object with t and e as enteries. Is there a better solution for what seems to be a simple request?

canadiancreed
  • 1,966
  • 6
  • 41
  • 58
  • See also : http://stackoverflow.com/questions/1153697/php-delete-xml-element – Kethryweryn Sep 12 '13 at 15:44
  • @Kethryweryn not completely. That referred with filtering based upon attribute, as opposed to filtering out entire rows based upon content in string x. At least that's what I got out of it. – canadiancreed Sep 12 '13 at 16:42
  • You're right, read too fast. However, the DOM seems to be a good starting point for your problem ! – Kethryweryn Sep 12 '13 at 16:46
  • @Kethryweryn no worries. I wish the XML feed I dealt with had attributes, would make things so much easier. – canadiancreed Sep 12 '13 at 16:50
  • Edited my answer, seems to work with the example you provided. However, I don't know how it'll go on a more complex XML. You'll probably have to find the right xpath. – Kethryweryn Sep 12 '13 at 16:56
  • 1
    Oops, didn't read carefully - you want to delete *everything except* 2. The change is pretty obvious: [`/main/item[field!=2]`](http://codepad.viper-7.com/r7QTCQ). – IMSoP Sep 12 '13 at 20:11

2 Answers2

1

This seems to do the trick :

$xml = new SimpleXMLElement("<main><item><field>1</field></item><item><field>2</field></item><item><field>2</field></item><item><field>4</field></item></main>");

$xpath = $xml->xpath('/main/item'); // Comment from IMSoP : you could add the test here with /main/item[field!=2] instead of doing it later on.

foreach($xpath as $seg)
{
    if($seg->field != 2)
    {
        $dom=dom_import_simplexml($seg);
        $dom->parentNode->removeChild($dom);
    }
}

echo $xml->asXML();

Outputs :

<main>
    <item>
        <field>2</field>
    </item>
    <item>
        <field>2</field>
    </item>
</main>
Kethryweryn
  • 639
  • 4
  • 11
  • 2
    If you're going to use XPath anyway, you can avoid the `if` statement by building a filter into your XPath expression: `/main/item[field!=2]`. [Rest of comment retracted: the xpath *is* necessary, as you need a simple array of nodes to delete; the iterator used in `foreach ( $xml->item as $seg )` doesn't like having its items removed mid-loop] – IMSoP Sep 12 '13 at 20:15
  • Good point. Adding in the code comments. – Kethryweryn Sep 13 '13 at 08:56
0

If I remember correctly, you can't delete node.

I solved this by rebuilding SimpleXMLElement object without deleted value - operations on array etc.

Try to iterate nodes, check value and when you want keep this object, copy to another SimpleXML object. It's not pretty but It can work.

Other way is use SimpleXML::asXML() to get XML code and modify it with preg_replace, but it's again not pretty... maybe use full XML DOM?

aso
  • 1,331
  • 4
  • 14
  • 29