How to catch an SVG parsing error?

2019-02-26 09:33发布

问题:

I'm trying to write a unit test (using qunit) for my code that generates an SVG path as a string. One of the test should be whether that thing is actually valid SVG at all.

In the Chrome browser console, it's easy to test just by doing this:

$("<svg xmlns=\"http://www.w3.org/2000/svg\"><path d=\"asdsdsadas\" /></svg>")

This will fail with an appropriate error message:

Error: Invalid value for attribute d="asdsdsadas"

However, it also returns the invalid document, same as if it would have been ok.

When I run this code in qunit, the error is printed into the browser console, but the unit test still succeeds, since it's not actually an exception. I also had no success trying to catch it.

I've tried overriding console.error, but apparently this error originates on a deeper level that doesn't care about JavaScript trickery.

Does anybody know how to properly recognize this error?

回答1:

The normal way to catch an svg parsing error from a string is to use a DOMParser() object.

If you do pass an invalid string to the parseFromString() method, then the DOMParser will return an error document.

var invalidMarkup = "<svg xmlns=\"http://www.w3.org/2000/svg\"><path d\"M0,0\" /></svg>";
var oParser = new DOMParser();
var doc = oParser.parseFromString(invalidMarkup, 'image/svg+xml');

var failed = doc.documentElement.nodeName.indexOf('parsererror')>-1;

if(failed){
  snippet.log('failed to load the doc : '+doc.documentElement.nodeName);
  }
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

But the markup you gave in the question is valid svg+xml markup.
Parsers won't complain about it.

var yourMarkup = "<svg xmlns=\"http://www.w3.org/2000/svg\"><path d=\"asdsdsadas\" /></svg>";
var oParser = new DOMParser();
var doc = oParser.parseFromString(yourMarkup, 'image/svg+xml');

var failed = doc.documentElement.nodeName.indexOf('parsererror') > -1;

if (failed) {
  snippet.log('failed to load the doc : ' + doc.documentElement.nodeName);
} else {
  snippet.log('success');
}
<!-- Provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

What Chrome console does tell you is that it couldn't draw the whole segments contained in the d attribute of your <path>.

Per specs,

The general rule for error handling in path data is that the SVG user agent shall render a ‘path’ element up to (but not including) the path command containing the first error in the path data specification.

So in your exact case, nothing will be rendered, but no error will thrown either.

The only way to detect such error programmatically, would be to get your path.pathSegList.length and check that it corresponds to the number of segments you added into this attribute.

But IMO, you should test your values directly while generating it.