【问题标题】:How to parse SVG styling properties using Linq (C#)如何使用 Linq (C#) 解析 SVG 样式属性
【发布时间】:2016-04-02 03:58:43
【问题描述】:

我想使用 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 属性的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.初学者

【问题讨论】:

  • 你需要一个 CSS 解析器。这是我在搜索这样的东西时发现的第一个。 github.com/Athari/CsCss
  • 你看到我的回答了吗?
  • @Alberto 是的,我看到了您的回答,看起来很有希望!虽然我没有时间测试它。但是,如果它对我有用,我现在会这样做并将其标记为正确答案。 :) 这比我的方法更安全,但仍然有一些字符串拆分。但我想像椭圆示例这样的查询没有办法做到这一点。

标签: c# linq svg


【解决方案1】:

您可以结合使用 Split、Select、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" 
}

【讨论】:

  • 好的,如果我的 'SvgStyle' 类具有我的 'styleValues' 列表中可能出现的所有属性,则此方法有效,否则我会收到错误消息。假设我只想拥有特定的属性,例如“Fill”、“Stroke”和“StrokeWidth”。我如何修改您的代码以检查我的“SvgStyle”类是否已在我的列表中实现了当前属性,如果不只是继续?我认为这应该在反射线中检查,对吗?抱歉,但我以前从未听说过反射概念,所以我不知道如何自己解决。
  • @A.Beginner 我修好了。我正在查看键/值列表并寻找一些属性,现在我将其反转,我得到所有属性,并查看键/值中是否有任何值与属性名称匹配
  • 谢谢!这效果更好,但在某些情况下我仍然会出错。例如,当“styleValue”末尾有意外的空白或终止分号时。我更改了“styleValues”分配以处理这些问题,并在您的帖子中对其进行了编辑。非常感谢您的帮助!新年快乐!
  • @A.Beginner 你也新年快乐!!!我改变了我的答案,与你提出的有点不同,你不必使用 string.IsNullOrEmpty 进行过滤,Split 方法已经可以做到这一点。
  • 还有一个建议。 :) 如果使用StringSplitOptions,则需要将';' 更改为new Char[] {';'}new String[] {";"},对吗?至少我得到一个错误,否则。
猜你喜欢
  • 2014-03-11
  • 2011-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-23
  • 1970-01-01
相关资源
最近更新 更多