outerHTML of an SVG element
Asked Answered
D

5

23

Why can not we get outerHTML of an svg element with element.outerHTML property?

Is this way is the best http://jsfiddle.net/33g8g/ for getting svg source code?

Dunant answered 25/9, 2012 at 23:12 Comment(0)
T
5

It's not accessible via outerHTML because SVG is not HTML -- it's a separate XML specification.

That's why, for example, your svg node in that example has its own namespace defined (xmlns="http://www.w3.org/2000/svg).

Your example may be the most expedient for a one-off query, but it's actually possible to dig in using native attributes. It just takes a bit more work.

Let's use the linked sample node:

 <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
    <text x="0" y="15" fill="black">An SVG element.</text>
</svg> 

If you want to extract the namespace and version, use the attributes property.

var svgElement = $('svg')[0]; // using your example
console.log(svgElement.attributes.xmlns); // outputs "http://www.w3.org/2000/svg"
console.log(svgElement.attributes.version); // outputs "1.1"

If you want to extract the actual contents, iterate over the children. Similar to the above, a non-text node's attributes collection will contain the x/y values (etc).

Without using jQuery, using your example again:

for (var i = 0; i < svgElement.childNodes.length; i++) {
    var child = svgElement.childNodes[i];
    if (child.nodeType == 1) {
        console.log(child.attributes[0].name); // "x"
        console.log(child.attributes[0].value); // "0"
        console.log(child.attributes[1].name); // "y"
        console.log(child.attributes[1].value); // "15"
    }
}

Here's an updated Fiddle, a bit more elegantly demonstrating the possibilities: http://jsfiddle.net/33g8g/8/

Tripper answered 16/9, 2013 at 16:2 Comment(0)
A
23

SVGElements don't have outerHTML property.

You can define like this in pure Javascript

Object.defineProperty(SVGElement.prototype, 'outerHTML', {
    get: function () {
        var $node, $temp;
        $temp = document.createElement('div');
        $node = this.cloneNode(true);
        $temp.appendChild($node);
        return $temp.innerHTML;
    },
    enumerable: false,
    configurable: true
});

Or a one line jQuery solution would be

$('<div>').append($(svgElement).clone()).html();

Reference: https://gist.github.com/jarek-foksa/2648095

Accelerometer answered 13/12, 2013 at 5:39 Comment(2)
Thanks for sharing that – was having a heck of a time getting outerHTML to work in Safari!Heffner
I would add if (!('outerHTML' in SVGElement.prototype)) { /** */ } around the polyfillPalinode
C
9

This is an easier solution and it works great in FF, Chrome, IE. Honor goes to Philipp Wrann.

outerHtml is not working in IE

new XMLSerializer().serializeToString(document.querySelector('#b'))
Chukchi answered 15/7, 2017 at 15:54 Comment(1)
This worked for me. In Angular 2+ I was able to use this on a SVGElement Example: const element: SVGElement = canvas.getPreview(); const svgString: string = w XMLSerializer().serializeToString(element);Instrumentalism
A
7

2013 update: The innerHTML and outerHTML are going to be supported for svg elements too, per the DOM Parsing specification.

A patch for this has been landed in Blink/Chrome and will become available soon, see http://code.google.com/p/chromium/issues/detail?id=311080.

Aston answered 13/12, 2013 at 13:13 Comment(1)
I can confirm this works perfect on the most recent versions of Chrome, Safari and Firefox. Alas, it doesn't work on Internet Explorer 11.Coign
T
5

It's not accessible via outerHTML because SVG is not HTML -- it's a separate XML specification.

That's why, for example, your svg node in that example has its own namespace defined (xmlns="http://www.w3.org/2000/svg).

Your example may be the most expedient for a one-off query, but it's actually possible to dig in using native attributes. It just takes a bit more work.

Let's use the linked sample node:

 <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
    <text x="0" y="15" fill="black">An SVG element.</text>
</svg> 

If you want to extract the namespace and version, use the attributes property.

var svgElement = $('svg')[0]; // using your example
console.log(svgElement.attributes.xmlns); // outputs "http://www.w3.org/2000/svg"
console.log(svgElement.attributes.version); // outputs "1.1"

If you want to extract the actual contents, iterate over the children. Similar to the above, a non-text node's attributes collection will contain the x/y values (etc).

Without using jQuery, using your example again:

for (var i = 0; i < svgElement.childNodes.length; i++) {
    var child = svgElement.childNodes[i];
    if (child.nodeType == 1) {
        console.log(child.attributes[0].name); // "x"
        console.log(child.attributes[0].value); // "0"
        console.log(child.attributes[1].name); // "y"
        console.log(child.attributes[1].value); // "15"
    }
}

Here's an updated Fiddle, a bit more elegantly demonstrating the possibilities: http://jsfiddle.net/33g8g/8/

Tripper answered 16/9, 2013 at 16:2 Comment(0)
Y
1

Using jQuery, you can easily create a temporary HTML wrapper around any element that doesn't support outerHTML :

function wrappedHtml(elt){
    var wrapped = elt.wrap("<wrap></wrap>").parent().html();
    elt.unwrap();
    return wrapped;
}
Yester answered 15/3, 2017 at 12:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.