Fernando Olvera
Fernando Olvera

Reputation: 99

Add new node to a XML on every item with a variable as attribute using PHP

I have been doing some practice with PHP and I have some questions on how to add new nodes to a XML on every item with a variable as attribute using PHP, I will explain it detailed.

First I load an XML file that structure seems similar to the next one:

<?xml version="1.0" encoding="utf-8"?>
<products>
  <item>
    <reference>00001</reference>
    <other_string>PRODUCT 1</other_string>
    <brand>BRAND 1</brand>
    <promo>YES</promo>
  </item>
  <item>
    <reference>00002</reference>
    <other_string>PRODUCT 2</other_string>
    <brand>BRAND 2</brand>
    <promo>YES</promo>
  </item>
  <item>
    <reference>00003</reference>
    <other_string>PRODUCT 3</other_string>
    <brand>BRAND 3</brand>
    <promo>NO</promo>
  </item>
  <item>
    <reference>00004</reference>
    <other_string>PRODUCT 4</other_string>
    <brand>BRAND 4</brand>
    <promo>NO</promo>
  </item>
  <item>
    <reference>00005</reference>
    <other_string>PRODUCT 5</other_string>
    <brand>BRAND 5</brand>
    <promo>YES</promo>
  </item>
</products>

And as you can see there is a node in the XML called <promo></promo> with 2 possible variables "YES" and "NO" so based on that I need to create a new node containing "1" if "YES" is present or "0" if "NO" to look similar to this:

<?xml version="1.0" encoding="utf-8"?>
<products>
  <item>
    <reference>00001</reference>
    <other_string>PRODUCT 1</other_string>
    <brand>BRAND 1</brand>
    <promo>YES</promo>
    <newnode>1</newnode>
  </item>
  <item>
    <reference>00002</reference>
    <other_string>PRODUCT 2</other_string>
    <brand>BRAND 2</brand>
    <promo>YES</promo>
    <newnode>1</newnode>
  </item>
  <item>
    <reference>00003</reference>
    <other_string>PRODUCT 3</other_string>
    <brand>BRAND 3</brand>
    <promo>NO</promo>
    <newnode>0</newnode>
  </item>
  <item>
    <reference>00004</reference>
    <other_string>PRODUCT 4</other_string>
    <brand>BRAND 4</brand>
    <promo>NO</promo>
    <newnode>0</newnode>
  </item>
  <item>
    <reference>00005</reference>
    <other_string>PRODUCT 5</other_string>
    <brand>BRAND 5</brand>
    <promo>YES</promo>
    <newnode>1</newnode>
  </item>
</products>

I have been playing with this code but it does not work recursively and it seems that do not detect the values using xPath:

<?php
$sXML = simplexml_load_file('file.xml', null, LIBXML_NOBLANKS);
$promoyes = $sXML->xpath("//item[promo='YES']");
foreach ( $promoyes as $value )    {
    $value = $sXML->item->addChild('newnode', '1');
}
unset($value);
$promono = $sXML->xpath("//item[promo='NO']");
foreach ( $promono as $value )    {
    $value = $sXML->item->addChild('newnode', '0');
}
unset($value);

$domDocument = dom_import_simplexml($sXML)->ownerDocument;
$domDocument->formatOutput = true;
echo $domDocument->save('new.xml'); 
?>

Any help will be appreciate.

Upvotes: 0

Views: 44

Answers (2)

Nigel Ren
Nigel Ren

Reputation: 57121

As you can tell, the nodes are all added to the first <item> node - this is down to the lines...

$value = $sXML->item->addChild('newnode', '1');

As you start at the root node and just use ->item-> this will always assume you mean to add the new node to the first <item> element.

You just need to add the node to the $value node instead. I've also simplified it to use 1 loop and it selects any <item> elements with a <promo> element (using //item[promo]). This then adds the new node with a test on the <promo> value...

$sXML = simplexml_load_file('file.xml', null, LIBXML_NOBLANKS);
$promo = $sXML->xpath("//item[promo]");
foreach ( $promo as $value )    {
    $value->newnode = ($value->promo=='YES')? 1:0;
}

$domDocument = dom_import_simplexml($sXML)->ownerDocument;
$domDocument->formatOutput = true;
$domDocument->save('new.xml'); 

Upvotes: 1

Nick
Nick

Reputation: 147166

This is most easily done using DOMDocument on its own. You can use getElementsByTagName to find all the promo elements and then add a newnode element with the value based on the value of the promo element:

$doc = new DOMDocument();
$doc->loadXML($xml);
foreach ($doc->getElementsByTagName('promo') as $ele) {
    $newnode = $doc->createElement('newnode');
    $newnode->nodeValue = $ele->nodeValue == 'YES' ? 1 : 0;
    $ele->parentNode->appendChild($newnode);
}
echo $doc->saveXML();

Demo on 3v4l.org

Upvotes: 1

Related Questions