2

I have an SVG file created in a program like InkScape. I want to load it in Javascript and put it into a SVG object along with other SVG elements.

I'd like to have a function that I can pass a URL, it will fetch that SVG, then return a "g" object grouping everything in the SVG file I loaded.

SVG.LoadXML = function (url, continuation) {
    var http = new XMLHttpRequest();
    http.open("GET", url, false);
    http.send();
    textBody = http.responseText;

    var g = document.createElementNS(SVG.ns, "g");

    g.innerHTML = textBody;

    return g;
}

The body of the file being loaded looks something like this:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC [...] >
<svg version="1.1" [...] >

<g>
  <defs>
    <path id="SVG1ID_1_" [...]
etc.

So, I think what I want to do is open the file as XML, then skip over the first two nodes, enter the second one, and copy all the nodes inside there into my SVG in the document.

This seems like the sort of thing that should be pretty simple and has been implemented a few different ways by a few thousand people already.

Cœur
  • 37,241
  • 25
  • 195
  • 267
MattD
  • 1,324
  • 4
  • 14
  • 28

2 Answers2

4

When dealing with SVG, don't fall into the trap expecting that this works exactly like HTML. A few things need to be done differently here:

SVG elements aren't HTML and you can't set .innerHTML. Use .appendChild() instead. You can obviously only append a DOM element, not plain text, so use .responseXML instead of .responseText.

For navigating the loaded SVG, picking only certain nodes, use the standard DOM methods like .getElementById(), .getElementsByTagName(), .childNodes, firstChild, .lastChild etc.

To append a node from the retrieved SVG to the main SVG, you have to import it first. See another post that describes this.

Community
  • 1
  • 1
Thomas W
  • 14,757
  • 6
  • 48
  • 67
  • I am having a little trouble still. I used `xmlBody = http.responseXML;` to get the XML. Then I grab the SVG node: `var svg = xmlBody.getElementsByTagName("svg")[0];` And then insert all the children: `var svg = xmlBody.getElementsByTagName("svg")[0]; var gs = svg.childNodes; for (var i = 0; i < gs.length; ++i) { g.appendChild(gs[i]); }`, but I don't see anything in the SVG. However, when I use `gs=xmlBody.getElementsByTagName("g")` and insert all those the same way, it does seem to grab all the "g" elements and insert them successfully. – MattD Mar 29 '13 at 14:34
  • You're indeed right! The reason is obviously that the nodes are still belonging to another document and it's not allowed to add them directly. It's still really strange that this works in one case but not the other! I added some information to my answer. – Thomas W Mar 30 '13 at 20:42
0

I hadn't realized that appendChild will also remove that child from the parent, thus my implementation was only getting about half of the SVG items. Here's the working code:

SVG.LoadXML = function (url) {
    var http = new XMLHttpRequest();
    http.open("GET", url, false);
    http.send();
    xmlBody = http.responseXML;

    var g = document.createElementNS(SVG.ns, "g");
    var svg = xmlBody.getElementsByTagName("svg")[0];
    do {
        var child = svg.firstChild;
        g.appendChild(child);
    } while (svg.firstChild);
    return g;
}
MattD
  • 1,324
  • 4
  • 14
  • 28