2

I'm provided a XML file with this structure:

<items>
  <item>
    <images>
      <image>A</image>
      <image>B</image>
      <image>C</image>
    </images>
    .
    .
    .
  </item>
</items>

However the import function of my Shop requires the following format:

<items>
  <item>
    <images>
      <image>A</image>
      <image1>B</image>
      <image2>C</image>
    </images>
    .
    .
    .
  </item>
</items>

At first I was thinking I would do this simply in Java since it would be pretty easy to read line by line and restructure the document but I would love to have it so I can just visit a url and this is done for me.

Here is the approach I took:

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


// Loop over items in original xml
for($i = 0; $i < count($xml->item); $i++)
{
    $images;
    if( ($c = count($xml->item[$i]->images->image)) > 1)
    {
        $images = $xml->item[$i]->images;

        // Remove entry
        unset($xml->item[$i]->images);

        $xml->item[$i]->addChild('images');

        for($y = 0; $y < count($images->image); $y++)
        {
            if($y == 0)
            {
                $xx = $xml->item[$i]->images->addChild('image', $images->image[$y]);

            }else {
                $xml->item[$i]->images->addChild('image' . $y, $images->image[$y]);
            }
        }

        var_dump($images);
    }
}

$xml->asXML('POTO.xml');

The dilemma I have tho is that none of the childs get added to images. I have been told I need to restructure the whole document but this is kind of silly if I var_dump just after removing the images node the node and it's children are all removed however when I go to add images node back to item node it and var_dump the node it shows the node was added to item node as a child however when I try to add image to images nothing gets added.

Do I really need to restructure the whole document because it seems simpler to do it in Java then. Or did I miss something.

3
  • 2
    2 cents: Look into PHP:XSL. Commented Feb 12, 2014 at 23:07
  • What is the value of count($xml->item) and count($images->image)? Are your loop bodies executed? Commented Feb 12, 2014 at 23:09
  • @GeorgeCummins The count syntax looked funny to me, too, but seems to be valid. Looks like PHP 5.3 brought support for a SimpleXMLElement::count() object method, but using the basic count() was actually standard before that. Who knew? Ref: us3.php.net/manual/en/simplexmlelement.count.php Commented Feb 13, 2014 at 0:13

1 Answer 1

1

Okay, I think the key problem here is that assigning the images to $images doesn't work like you'd expect. While such an assignment of a primitive makes a copy, assigning an object makes a reference to the same object (similar to a pointer you've worked with lower level languages). They do this because an object can be larger than a primitive, and unnecessary duplication of that is just wasteful.

However, in this case, the result is that when you unset the images from the main SimpleXML object, you're also destroying the instance in $images. Fortunately, there is a solution. You can clone the object, rather than assigning it. See http://www.php.net/manual/en/language.oop5.cloning.php

I modified your sample code here and it seems to work: http://3v4l.org/ZmRZV

Edit: cleaned up my code a little and included it:

<?php
//$xml = simplexml_load_file('data.xml');
$xml = simplexml_load_string('<items>
  <item>
    <images>
      <image>A</image>
      <image>B</image>
      <image>C</image>
    </images>
  </item>
</items>');

// Loop over items in original xml
foreach ($xml->item as $item) {
    if (count($item->images->image) > 1) {
        // Clone entry
        $images = clone $item->images;

        // Remove entry and replace with empty
        unset($item->images);
        $item->addChild('images');

        for ($i = 0; $i < count($images->image); $i++) {
            $num = ($i > 0) ? $i : '';
            $item->images->addChild('image'.$num, $images->image[$i]);
        }
    }
}

//$xml->asXML('POTO.xml');
echo $xml->asXML();

Looks like this doesn't work prior to version 5.2.1 (http://3v4l.org/m0VoD), but that's going back pretty far, really. Rasmus doesn't want anyone running less than 5.4 (http://www.youtube.com/watch?v=anr7DQnMMs0&t=10m27s), and I'm inclined to agree.

For the record, this behavior, of copying only the reference is not a quirk of PHP. It's a common practice. Further reading: http://en.wikipedia.org/wiki/Cloning_(programming)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.