如何解决如何使用Linq访问后代?
我有一个.svg文件,如下所示:
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="topLevelGroup">
<rect
style="fill:#ff00ff;fill-opacity:1.0;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rectPurple"
width="60.0"
height="30.0"
x="60.0"
y="90.0" />
<rect
style="fill:#ffffff;fill-opacity:1.0;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rectWhite"
width="90.0"
height="30.0"
x="30.0"
y="130.0" />
因此,“ g”是一个组,并且有多个组,而不仅仅是一个,它们每个都有一个唯一的id属性(这里是topLevelGroup)。我的任务是编写一个获取组ID作为参数并返回该组中矩形颜色的方法。由于某种原因,我无法收集这些颜色。这是我尝试过的:
private IEnumerable<XElement> Groups => root.Descendants(ns + "g");
internal IEnumerable<string> GetColorsOfRectsInGroup(string id)
{
IEnumerable<XElement> spec_groups = Groups.Where(g => g.Attribute("id").Value.Contains(id))
.Select(g => g);
IEnumerable<string> colors = from r in spec_groups.Descendants("rect")
select r.GetFillColor();
return colors;
}
因此,基本上,我首先尝试收集与参数id匹配的所有组,然后获取后代“ rect”对象及其颜色。我没有收到任何错误消息,它只是没有通过测试。这也是检查此内容的测试方法:
public void GetColorsOfRectsInGroup()
{
var colors = s1.GetColorsOfRectsInGroup("group1");
Assert.True(UnorderedCompareSequences<string>(new string[] { "#ff0000","#ffff00" },colors));
colors = s2.GetColorsOfRectsInGroup("group2");
Assert.True(UnorderedCompareSequences<string>(new string[] { "#00ff00","#0000ff" },colors));
}
我今天才开始与Linq合作,我一直在浏览网站,但我不知道。我在做什么错了?
解决方法
您应该在separation of concerns上进行更多工作。这对您来说很困难的原因是,您试图用一个大语句来做所有事情。
我的建议是将您的任务分解为较小的任务。这不仅使您的任务更易于理解和进行单元测试/调试,而且还具有更大的增强功能:可以更轻松地重用您的代码来解决类似的问题,也可以更轻松地调整代码以进行细微更改。 / p>
在这种情况下,您应该将问题分为两个子问题:
- 将SVG文件读入
Groups
序列中,每个序列的零个或多个Rectangles
。 - 给出一个
Group
的ID,给我一个和唯一具有此ID的组中的矩形的颜色。
将其拆分为这些子问题的优点是,对于需要解释SVG文件的其他问题,您可以重用第一种方法,例如:“给我所有组ID”或给我总表面积组中所有矩形的数量。
如果您的输入内容不在SVG文件中,例如在“带有矩形的组的列表”中或数据库中,则第二个过程可以重复使用。
最后,很容易看出您可以对它们进行单独的单元测试,这使得对边缘条件进行单元测试更加容易。
返回您的问题
要读取SVG文件,您需要一个类“具有零个或多个矩形的组”:
class Rect
{
public string Id {get; set;}
public double Width {get; set;}
public double Height {get; set;}
Color GetFillColor();
... // etc
}
class Group
{
public string Id {get; set;}
...
// each group has zero or more Rects:
public virtual ICollection<Rect> Rects {get; set;}
}
我选择使用ICollection而不是列表的原因是因为恕我直言,我认为Rect[4]
没有定义的含义。 Rect["rectWhite"]
可以,但这超出了您的问题范围。
另一个原因:这种布局看起来很像数据库的输出,就像您从实体框架中得到的一样。如果您以后决定从数据库表中获取组,则不必更改此界面。
因此,您需要一个过程来将SVG文件读入Groups
序列中。我对SVG文件不是很熟悉,您可能比我更了解如何使用它们。考虑为此使用NUGET包。因此,我将专注于获取组的颜色。
string groupId = ...
IEnumerable<Group> groups = ... // fetch the groups from the source,in your case a SVG file
var result = groups.Where(group => group.Id == groupId)
// from the remaining groups,get the FillColors of the Rectangles:
.SelectMany(group => group.Rects,// parameter resultSelector:
// from every group / rectangle combination,make one new object
// containing the FillColor of the rectangle (so we don't use the group anymore)
(group,rectangle) => rectangle.GetFillColor())
// you might have duplicate colors; If you don't want them,use:
Distinct();
,
尝试以下操作:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement root = doc.Root;
XNamespace ns = root.GetDefaultNamespace();
string id = "rectPurple";
List<XElement> Groups = root.Descendants(ns + "g").ToList();
List<XElement> spec_groups = Groups.Where(x => x.Elements(ns + "rect").Any(y => (string)y.Attribute("id") == id)).ToList();
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。