5

I would like to get SVG tag content with PHP.

test.svg:

<?xml version="1.0" encoding="utf-8"?>
<!-- comment  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 width="202.5px" height="226.084px" viewBox="0 0 202.5 226.084" enable-background="new 0 0 202.5 226.084" xml:space="preserve">
   <g>
        <path d="M0,13.628c47.7940,13.628z"/>
        <polygon points="108.48,207.874 145.506,196.948 145.506,204.536 108.48,214.854  "/>
        <path fill="none" stroke="#000000" d="M114.55,223.959"/>
   </g>
   <g>       
        <path fill="none" stroke="#000000" d="M114.55,223.959"/>
   </g>
   <anythingElse>       
        <path fill="none" stroke="#000000" d="M114.55,223.959"/>
   <anythingElse>       
</svg>

php:

$svg = new SimpleXMLElement( file_get_contents( 'test.svg' )  );

$svg->registerXPathNamespace('svg', 'http://www.w3.org/2000/svg');
$svg->registerXPathNamespace('xlink', 'http://www.w3.org/1999/xlink');

Now, I would like to get the svg tag content as a string.

Desired result (hardcoded example):

$content =  '<g>
    <path d="M0,13.628c47.7940,13.628z"/>
    <polygon points="108.48,207.874 145.506,196.948 145.506,204.536 108.48,214.854  "/>
    <path fill="none" stroke="#000000" d="M114.55,223.959"/>
</g>
   <g>       
        <path fill="none" stroke="#000000" d="M114.55,223.959"/>
   </g>
   <anythingElse>       
        <path fill="none" stroke="#000000" d="M114.55,223.959"/>
   <anythingElse> ';

//EDIT:

I don't want to look for g tag: '/svg:svg/svg:g'. As there is no guarantee that inside the svg there will be a g tag. There could be more then one g tag or some other tags.

I want to get everything between the opening and closing svg tags.

hakre
  • 193,403
  • 52
  • 435
  • 836
user2015338
  • 262
  • 2
  • 4
  • 13
  • 1
    How is this a duplicate? – user2015338 Apr 26 '13 at 12:57
  • Just look for "simplexml get children" and you should find code snippets, tutorials and what not. Next time make your programming problem more clear, you might more have an issue with expressing than with programming. Join over to the PHP chat in case. – hakre Apr 26 '13 at 13:17

2 Answers2

8

You have already seen right (more likely: copy and pasted from an example code that has been given to you in a previous answer w/o understanding it further) that you need to register the XML namespace here for your xpath because there is no prefix for it in the XML:

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 width="202.5px" height="226.084px" viewBox="0 0 202.5 226.084" enable-background="new 0 0 202.5 226.084" xml:space="preserve">

It is just the URI http://www.w3.org/2000/svg, no prefix given. It is the namespace of that <svg> root element.

Therefore you need to register the prefix (the other already prefixed namespace should be already registered automatically):

$svg->registerXPathNamespace('svg', 'http://www.w3.org/2000/svg');

Which is what you do so far.

To now use your registered prefix in the xpath query, prefix the tagname with it:

/svg:svg/svg:g[1]

Should give you the first <g> element in that SVG-Namespace. Let me know if this still needs further explanation / clarification.

See the online demo.

This is also exactly as the reason outline to your previous question:

Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836
  • This is just an example. I don't want to the the g tag. I want to get what is inside the svg tag. I have tried $svgBody = $svg->xpath('//svg:svg'); for example, and still don;t understand why it whoul not work – user2015338 Apr 26 '13 at 12:05
  • and what does `$svgBody->asXML('php://output');` prints you then in plain source? *Edit:* I also added an [online demo](http://eval.in/17651) so you can see how/that the code as outlined works. – hakre Apr 26 '13 at 12:08
  • Fatal error: Call to a member function asXML() on a non-object – user2015338 Apr 26 '13 at 12:12
  • Can not reproduce that, see the linked example. Which libxml and PHP version are you using? – hakre Apr 26 '13 at 12:13
  • Thank you for the example. But you are looking for g tag: '/svg:svg/svg:g' We have no guarantee that inside the svg there will be a g tag. There could be more then one g tag or some other tags I want to get everything between the tags – user2015338 Apr 26 '13 at 12:20
  • @user2015338: And where do you hit the roadblock to modify the xpath expression to achieve that? Are you interested in *all* elements or just SVG elements? – hakre Apr 26 '13 at 13:09
  • I am interested in all svg tag children, give me a second, I will update the question – user2015338 Apr 26 '13 at 13:11
  • think of namespaces: All children, or all children of a specific namespace? – hakre Apr 26 '13 at 13:15
  • All children, not just of a specific namespace. But if you would be so kind to explain both cases I will definitely accept your answer – user2015338 Apr 26 '13 at 13:37
  • 1
    You are asking about the difference of `*` and `svg:*` instead of `svg:g`. Also keep in mind that you get back an array you need to handle for zero up to all elements. Compare as well with http://stackoverflow.com/a/16235134/367456 for the `xpath()` returns an array, always note. – hakre Apr 26 '13 at 13:39
1

I think to get onle the g tag you don;t need namespace you could try this:

$result = $svg->xpath('svg/g');
foreach ($result as $gtag) {
    echo $gtag . "\n";
}

I can't test it though:)

Lukasz 'Severiaan' Grela
  • 6,078
  • 7
  • 43
  • 79