首页 文章

如何使用Linq(C#)解析SVG样式属性

提问于
浏览
2

我想和Linq一起访问SVG styling properties . 对于像椭圆这样的SVG元素,我可以简单地检查它们的属性并获得相应的值 . 假设我的svg文件包含这个椭圆:

<ellipse
     style="fill:#ff0000;fill-rule:evenodd;stroke:#ff60ff;stroke-width:0.47105053px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
     id="path3338"
     cx="457.0145"
     cy="261.14557"
     rx="102.28526"
     ry="126.51072"
     transform="matrix(0.79195929,0.6105739,-0.6105739,0.79195929,0,0)" />

我使用此代码来获取信息:

XDocument xml = XDocument.Load(PathToSvgFile);
IEnumerable<XElement> xmlEllipses = xml.Descendants("{http://www.w3.org/2000/svg}ellipse");
SvgEllipse[] ellipses = (
                from data in xmlEllipses
                select new SvgEllipse
                {
                    Cx = data.Attribute("cx") != null 
                         ? (double)data.Attribute("cx") 
                         : 0,
                    Cy = data.Attribute("cy") != null 
                         ? (double)data.Attribute("cy") 
                         : 0,
                    Rx = data.Attribute("rx") != null
                         ? (double)data.Attribute("rx") 
                         : 0,
                    Ry = data.Attribute("ry") != null
                         ? (double)data.Attribute("ry") 
                         : 0
                }
                ).ToArray();

这段代码从给定的svg文件中选择所有椭圆元素,并将其属性保存在我的椭圆类中 .

我想为每个元素的style属性做同样的事情 . 问题是, style 属性的 value 是整个样式字符串:

fill:#ff0000; fill-rule:evenodd; stroke:#ff60ff; stroke-width:0.47105053px; stroke-linecap:butt; stroke-linejoin:miter; stroke-opacity:1

目前我正在处理该字符串,使用 string.Split()string.StartsWith() 函数来查找正确的属性及其值 . 它有效,但我认为它不安全且难以阅读 . 与此主题类似(Parse style attribute collection using linq) .

是否有可能以简单的方式处理样式属性,如上所示?

我希望我的问题有点清楚 . 提前致谢!

A.初学者

1 回答

  • 0

    你可以使用Split,Select,Tuple和一点反射的组合来做到这一点 .

    所以,让我们首先在List of Tuple中转换样式字符串

    using System.Threading;
    
    var styleValue = "fill:#ff0000;fill-rule:evenodd;stroke:#ff60ff;stroke-width:0.47105053px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1";
    
    Func<string, string> toTitleCase = s => Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(s).Replace("-","");
    
    var styleValues = styleValue.Replace(" ", "")
                                .Split(new []{ ';' }, StringSplitOptions.RemoveEmptyEntries)
                                .Select(s => s.Split(':'))
                                .Select(s => Tuple.Create(toTitleCase(s[0]), s[1]))
                                .ToList();
    

    styleValues 的值为:

    List<Tuple<string, string>>(7) 
    { 
        [(Fill, #ff0000)], 
        [(FillRule, evenodd)], 
        [(Stroke, #ff60ff)], 
        [(StrokeWidth, 0.47105053px)], 
        [(StrokeLinecap, butt)], 
        [(StrokeLinejoin, miter)], 
        [(StrokeOpacity, 1)] 
    }
    

    假设您有一个代表该样式的类具有以下属性:

    public class SvgStyle
    {
        public string Fill { get; set; }
        public string FillRule { get; set; }
        public string Stroke { get; set; }
        public string StrokeWidth { get; set; }
        public string StrokeLinecap { get; set; }
        public string StrokeLinejoin { get; set; }
        public string StrokeOpacity { get; set; }
    }
    

    我们现在可以使用反射来填充SvgStyle类中的值

    var svgStyle = new SvgStyle();
    
    var svgStyleType = typeof(SvgStyle);
    
    svgStyleType.GetProperties()
                .Join(styleValues, p => p.Name, sv => sv.Item1, (p,sv) => new { p, sv })
                .ToList()
                .ForEach(t => t.p.SetValue(svgStyle, t.sv.Item2));
    

    现在你的SvgStyle类将拥有所有值

    SvgStyle 
    {
        Fill="#ff0000", 
        FillRule="evenodd", 
        Stroke="#ff60ff", 
        StrokeLinecap="butt", 
        StrokeLinejoin="miter", 
        StrokeOpacity="1", 
        StrokeWidth="0.47105053px" 
    }
    

相关问题