如何从SVG中提取一个元素及其引用元素



这里有一个SVG示例:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="78" y1="269.543" x2="237" y2="269.543">......</linearGradient>
<symbol  id="test" viewBox="-16.126 -14.41 32.251 28.819">...</symbol>
<rect x="78" y="203.043" style="fill:url(#SVGID_1_);" width="159" height="133"/>
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
<g>
<use xlink:href="#test" width="32.251" height="28.819" x="-16.126" y="-14.41" transform="matrix(1 0 0 -1 402.9284 846.39)" style="overflow:visible;"></use>
</g>
</svg>

我想提取三个子元素:rectcircleg,但是,你知道,rectlinearGradientgsymbol,如何提取一个元素及其引用元素?

实际上我曾经为node.js库做过一个实现。有关完整的源代码,请参阅svg图标工具箱。它不使用svg.js,而是使用cheerio,一个类似jQuery的库来解析和操作XML源。

它的工作原理类似于垃圾收集器:所有未标记为有效引用的内容都会被清除。

识别要保留的元素及其id。

var cheerio = require('cheerio');
// elements always removed
const remove = [
'animate',
'animateColor',
'animateMotion',
'animateTransform',
'cursor',
'script',
'set'
].join(',');
// elements always preserved
const preserve = [
'color-profile',
'font'
].join(',');
// elements whose links are ignored
const ignore = [
'a',
'altGlyph'
].join(',');
// removes everything not needed for a single icon export
function reduceTo ($copy, id) {
var reflist = new Set();
//mark elements for preservation
function mark (ref) {
var $target = $copy.find(ref);
//avoid doubles
if (!$target.parents(preserve).length && !reflist.has(ref)) {
reflist.add(ref);
//mark for preservation
$target.prop('refby', id);
//mark as having preserved children
$target.parentsUntil('svg').prop('passedby', id);
}
//find links
$target.find('*').addBack() // descendents and self
.add($target.parents()) // parents
.not([remove, ignore, preserve].join(','))
.each((i, el) => {
var $elem = $(el);
//unpack links and recurse
var link = $elem.attr('xlink:href');
if(link) {
mark(link);
}
funcProps.forEach((prop) => {
var value = $elem.css(prop) || $elem.attr(prop);
link = funcRegex.exec(value);
if (link) {
mark(link[1]);
}
});
});
}
//remove elements not needed
function sweep ($inspect) {
//filter out elements generally preserved
$inspect.children().not(preserve).each((i, el) => {
var $child = $(el);
//elements with children to be preserved: recurse
if ($child.prop('passedby') === id && $child.prop('refby') !== id) {
sweep($child);
//elements without mark: remove
} else if ($child.is(remove) || $child.prop('refby') !== id) {
$child.remove();
}
});
}
mark('#' + id);
sweep($copy);
return $copy;
}
var $ = cheerio.load(svgString, { xmlMode: true });
var reduced = reduceTo ($, id);
var serialized = $.xml();

最新更新