Как извлечь один элемент из SVG с его ссылочным элементом?

#svg #svg.js

#svg #svg.js

Вопрос:

вот пример 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>
 

Я хочу извлечь три подэлемента: rect , circle , g , однако, вы знаете, rect ссылается linearGradient и g ссылается symbol , как извлечь один элемент вместе с его ссылочными элементами?

Ответ №1:

На самом деле я когда-то делал реализацию для node.js библиотека. Полный исходный код см. в svg-icon-toolbox. Он не использует svg.js , но cheerio, библиотека, похожая на jQuery, для анализа XML-источников и управления ими.

Принцип, по которому он работает, аналогичен принципу сборщика мусора: все, что не помечено как допустимая ссылка, подметается и удаляется.

Определите элемент, который будет сохранен, с его идентификатором.

 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 amp;amp; !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 amp;amp; $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();