Search code examples
phpxmlsimplexml

Cannot add node to xml via php and simplexml


I'm baffled by this and the funny part is I've used this code successfully numerous times...

My aim is to create a new node (newsku) which will combine a string to an existing node from the xml.

Here's the xml:

<products>
    <product>
        <id>3</id>
        <name><![CDATA[ΜΙΚΡΟΦΩΝΟ SAMSON G-TRACK]]></name>
        <manufacturer><![CDATA[SAMSON]]></manufacturer>
        <sku><![CDATA[550.SAM.060]]></sku>
        <description_greek><![CDATA[Samson G-Track - large diaphragm USB studio 
condenser microphone (USB bus-powered), built-in audio interface and mixer, 
allows simultaneous input of vocals and guitar, bass, or keyboard while also 
providing monitoring through an on-board headphone output. Specifications: mic 
and instrument/line gain control with clip LED, stereo input jacks for (3.5mm 
stereo-jack) instrument or line level signal, stereo headphone jack for zero 
latency monitoring with level control, 3-position headphone switch for stereo, 
mono and computer monitoring. USB bus-powered. Includes desktop microphone 
stand, audio I/O cables, USB cables and Cakewalk Sonar LE software. Optional 
shockmount available.
]]></description_greek>
        <short_description_greek><![CDATA[Samson G-Track - large diaphragm USB studio 
condenser microphone (USB bus-powered)]]></short_description_greek>
        <price>155.00</price>
        <msrp>185.00</msrp>
        <instock>no</instock>
        <images total="2">
            <image_1>http://test.com/media/catalog/product/5/5/550.sam.060-mi-
01.jpg</image_1>
            <image_2>http://test.com/media/catalog/product/5/5/550.sam.060-mi-
02.jpg</image_2>
        </images>
    </product>
</products>

And here's my code:

<?php
    header('Content-Type: text/html; charset=UTF-8');
    error_reporting(E_ALL);

    // Import test xml

    $products = simplexml_load_file("http://test.com/xml/customer.xml");

    foreach($products->xpath("product") as $p) {
        $p->addChild("newsku", "NEW" . $p->sku);
    }

    $products->asXML('test.xml');
    echo 'test XML files are updated';
?>

What happens is that I get the original xml without the new node...

Probably I'm doing something really stupid since I've used this without any problem whatsoever in many other xml files...

Any ideas?

Thanks!


Solution

  • Your code will work fine, but it will not update the remote source only your local version test.xml. Which will be overwritten with the same value on each call to the php code.

    So the following code will fetch from your remote source and then add the new element newsku. Then output to the browser.

    $products = simplexml_load_file('http://test.com/xml/customer.xml');
    
    foreach( $products->xpath("*/product") as $p ) {
        $p->addChild("newsku",  "NEW".$p->sku);
    }
    
    header('Content-Type: text/xml; charset=UTF-8');
    // just outputs the xml - does not save
    exit($products->asXML());
    

    If you need to cache the xml, to write many times then save the file first. This will add a new item on each refresh (pretty sure its not what you want).

    // the xml file name
    $xml_file = 'test.xml';
    
    // check if the file exists or download and save it
    if (!file_exists($xml_file)) {
        file_put_contents($xml_file, file_get_contents('http://test.com/xml/customer.xml'));
    }
    
    // load xml file for changes
    $products = simplexml_load_file($xml_file);
    
    foreach( $products->xpath("*/product") as $p ) {
        $p->addChild("newsku",  "NEW".$p->sku);
    }
    
    header('Content-Type: text/xml; charset=UTF-8');
    
    // save the xml to file
    $products->asXML($xml_file);
    
    // read and display the xml file
    readfile($xml_file);
    

    If /xml/customer.xml is actually local on your server, and i'm confused with remote. You can use the above code without the fgc/fpc stuff and do like (again will update on each call to the file).

    // load xml file for changes
    $products = simplexml_load_file('/path/to/xml/customer.xml');
    
    foreach( $products->xpath("*/product") as $p ) {
        $p->addChild("newsku",  "NEW".$p->sku);
    }
    
    header('Content-Type: text/xml; charset=UTF-8');
    
    // save the xml to file 
    $products->asXML($xml_file);
    readfile($xml_file);
    
    // or just outputs the xml - no saving
    // exit($products->asXML());
    

    Hope it helps.

    See it online - https://3v4l.org/U8EbE