0

I'm trying to swap all attribute id's at once from '$old' > '$new' then save the xml:

$reorder = array( 9=>"8", 8=>"5", 7=>"4", 6=>"3", 5=>"0", 4=>"1", 3=>"9", 2=>"7", 1=>"2", 0=>"6" );

    $objDOM = new SimpleXMLElement(some.xml, null, true);
    foreach ($reorder as $old => $new) {
       $picture = $objDOM->xpath('picture[@id="'.$old.'"]');
       $picture[0]["id"] = $new;
    }
    echo $objDOM->asXML();

The result below (doesn't match Array $reorder)

  • 3 > 9
  • 9 > 6
  • 8 > 8
  • 7 > 2
  • 6 > 3
  • 5 > 5
  • 4 > 4
  • 0 > 0
  • 1 > 1
  • 7 > 2

It seems to be switching the id's in sequence, so id's that have just been switched are then switched again if they come up later in the array.

What I'm doing wrong there? How can I get it to switch ALL the id's in one go?

Thanks... Andy

1
  • Have you omitted anything within the code you pasted? Commented Nov 3, 2010 at 13:16

2 Answers 2

2

The answer are two loops

fist you search the xpath for the old id, store it in an array and then loop again to replace the stored results with the new id

$reorder = array(9 => "8", 8 => "5", 7 => "4", 6 => "3", 5 => "0", 4 => "1", 3 => "9", 2 => "7", 1 => "2", 0 => "6");

$objDOM = new SimpleXMLElement(
      '<pictures>
    <picture id="9">id was 9, should be 8 now</picture>
    <picture id="8">id was 8, should be 5 now</picture>
    <picture id="7">id was 7, should be 4 now</picture>
    <picture id="6">id was 6, should be 3 now</picture>
    <picture id="5">id was 5, should be 0 now</picture>
    <picture id="4">id was 4, should be 1 now</picture>
    <picture id="3">id was 3, should be 9 now</picture>
    <picture id="2">id was 2, should be 7 now</picture>
    <picture id="1">id was 1, should be 2 now</picture>
    <picture id="0">id was 0, should be 6 now</picture>
</pictures>');
$oldPicIds = array();

foreach ($reorder as $old => $new) {
   $oldPicIds[$old] = $objDOM->xpath('picture[@id="' . $old . '"]');
}

foreach ($reorder as $old => $new) {
   $oldPicIds[$old][0]['id'] = $new;
}

echo $objDOM->asXML();

Output:

<?xml version="1.0"?>
<pictures>
    <picture id="8">id was 9, should be 8 now</picture>
    <picture id="5">id was 8, should be 5 now</picture>
    <picture id="4">id was 7, should be 4 now</picture>
    <picture id="3">id was 6, should be 3 now</picture>
    <picture id="0">id was 5, should be 0 now</picture>
    <picture id="1">id was 4, should be 1 now</picture>
    <picture id="9">id was 3, should be 9 now</picture>
    <picture id="7">id was 2, should be 7 now</picture>
    <picture id="2">id was 1, should be 2 now</picture>
    <picture id="6">id was 0, should be 6 now</picture>
</pictures>

to save an array you could use array_pop to get the last occurrence of picture@id=xy. which should be the wanted one (read comments for drawbacks)

$reorder = array(9 => "8", 8 => "5", 7 => "4", 6 => "3", 5 => "0", 4 => "1", 3 => "9", 2 => "7", 1 => "2", 0 => "6");

$objDOM = new SimpleXMLElement(
      '<pictures>...</pictures>');

foreach ($reorder as $old => $new) {
   $picture = $objDOM->xpath('picture[@id="' . $old . '"]');
   $picture = array_pop($picture);
   $picture['id'] = $new;
}

echo $objDOM->asXML();
Sign up to request clarification or add additional context in comments.

2 Comments

brilliant! (I would vote up your answer but I don't have enough points yet) nice simple explanation too, many thanks maggie.
its ok. what i forgot to mention: the array_pop-solution is only something for unique attribute occurrence and of course sorted. if you just swap the original positions of p.e 9 and 8 the array_pop-solution will fail
0

Judging from the example contained in the question, I would simply iterate over all <picture/> elements and change @id accordingly. For instance:

foreach ($objDOM->picture as $picture)
{
    $id = (string) $picture['id'];
    $picture['id'] = $reorder[$id];
}

This assumes that $reorder has an entry for every @id used in the document. Otherwise, you'll need to use isset() to skip nodes that don't need to be changed.

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.