JonBlog
Thoughts on website ideas, PHP and other tech topics, plus going car-free
Resetting namespaced attributes using SimpleXML
Categories: PHP, XML

I am currently working on a PHP class to manipulate SVG documents, using PHP’s SimpleXML to handle the XML structure. I found myself needing to reset the namespaced attribute “xlink:href” in the following XML block:

<image
  y="35.811729"
  x="35.60614"
  id="image2886"
  height="581.58026"
  width="670.37695"
  xlink:href="file:///home/jon/Documents/LeafletGen/test.png"
/>

Finding the necessary info proved somewhat difficult, so I’m recording it here for posterity. Firstly, note that obtaining namespaced attributes via attributes() cannot be done via the default namespace:

$xml = '<image
  y="35.811729"
  x="35.60614"
  id="image2886"
  height="581.58026"
  width="670.37695"
  xlink:href="file:///home/jon/Documents/LeafletGen/test.png"
/>';
$xmlDoc = new SimpleXMLElement($xml);
$attribs = $xmlDoc->attributes();
$attribsNamespace = $xmlDoc->attributes('http://www.w3.org/1999/xlink');

print_r($attribs);
print_r($attribsNamespace);

This code returns the following results:

SimpleXMLElement Object
(
  [@attributes] => Array
    (
      [y] => 35.811729
      [x] => 35.60614
      [id] => image2886
      [height] => 581.58026
      [width] => 670.37695
    )
)

SimpleXMLElement Object
(
  [@attributes] => Array
    (
      [href] => file:///home/jon/Documents/LeafletGen/test.png
    )
)

That illustrates that namespaced items are treated separately. OK, so let’s try setting and unsetting ordinary elements:

// $xml as previously
$xmlDoc = new SimpleXMLElement($xml);
unset($xmlDoc['x']);
$xmlDoc['y'] = "1234";

echo $xmlDoc->asXML();

This returns the result as expected – the “x” attribute is removed and the “y” attribute is reset:

<image
  y="1234"
  id="image2886"
  height="581.58026"
  width="670.37695"
  xlink:href="file:///home/jon/Documents/LeafletGen/test.png"
/>

However, this is not possible with attributes that have a namespace. If we add in an attribute using the array syntax, it replicates the existing attribute:

// $xml as previously
$xmlDoc = new SimpleXMLElement($xml);
$xmlDoc['xlink:href'] = "file:///home/jon/Documents/LeafletGen/new-image.png";

echo $xmlDoc->asXML();

Result:

<image
  y="35.811729"
  x="35.60614"
  id="image2886"
  height="581.58026"
  width="670.37695"
  xlink:href="file:///home/jon/Documents/LeafletGen/test.png"
  xlink:href="file:///home/jon/Documents/LeafletGen/new-image.png"
/>

Clearly, this is not what we want. Furthermore, unsetting using the array syntax doesn’t work either. The solution is to unset the attribute inside a SimpleXMLElement, then set it, either using the array syntax as before, or using the addAttribute method:

// $xml as previously
$xmlDoc = new SimpleXMLElement($xml);
$attribs = $xmlDoc->attributes(
  $ns = 'http://www.w3.org/1999/xlink'
);
$newVal = 'file:///home/jon/Documents/LeafletGen/new-image.png';

unset($attribs->href);
$xmlDoc->addAttribute(
  'xlink:href',
  $newVal,
  $ns
);

// This seems to work too, but the attribute is probably
// not 'understood' by SimpleXML
//$xmlDoc['xlink:href'] = $newVal;

echo $xmlDoc->asXML();

And voila:

<image
  y="35.811729"
  x="35.60614"
  id="image2886"
  height="581.58026"
  width="670.37695"
  xlink:href="file:///home/jon/Documents/LeafletGen/new-image.png"
/>
Tags:

Leave a Reply