问题描述
我有这个"booms"的 XML 字符串:
<booms> <boom> <name>John</name> <address>New York City</address> </boom> <boom> <name>Daniel</name> <address>Los Angeles</address> </boom> <boom> <name>Joe</name> <address>Chicago</address> </boom> </booms>
我也有这个 LINQ C# 代码
//string xmlString = ...; XDocument document = XDocument.Load(new StringReader(xmlString)); var booms = from boomElement in document.Descendants("boom") let boolChildren = (from boomElementChild in boomElement.Elements() select String.Format("{0}: {1}", boomElementChild.Name.LocalName, boomElementChild.Value)) select String.Join(Environment.NewLine, boolChildren); var result = String.Join(Environment.NewLine + Environment.NewLine, booms);
将 XML 转换为这个字符串:
name: John address: New York City name: Daniel address: Los Angeles name: Joe address: Chicago<小时>
问题:
如何更改 LINQ 以过滤掉满足某些条件的繁荣?例如,如何过滤掉地址包含"New"的繁荣?在这种情况下,这将给出字符串:
name: John address: New York City
代码不应仅限于"包含"过滤器.
推荐答案
如果条件限制为相等.
Dictionary<string, string> conditions = new Dictionary<string, string> { { "name", "John" } }; XDocument document = XDocument.Load(new StringReader(xmlString)); var booms = from boomElement in document.Descendants("boom") where conditions.All(condition => (string)boomElement.Element(condition.Key) == condition.Value) // Where is used to filter the result let boomChildren = (from boomElementChild in boomElement.Elements() select String.Format("{0}: {1}", boomElementChild.Name.LocalName, boomElementChild.Value)) select String.Join(Environment.NewLine, boomChildren); var result = String.Join(Environment.NewLine + Environment.NewLine, booms);
如果不限于相等(包含、相等、<、>),则必须创建一个表示条件的结构.
// I've made Condition an abstract class to super any kind of condition. // Just derive this class with the condition you want (And, Or, Equal, <=, IsNumber, ...) public abstract class Condition { // A condition is defined by this method. Because a condition is basically: "Does the specified value satisfy the condition?" public abstract bool Satisfy(string valueToTest); } // This is the first example of condition. // I wanted to make the condition immutable (readonly) not to be able to change them. // So, all parameters of the condition are set during the construction. public sealed class EqualCondition : Condition { private readonly string value; public string Value { get { return value; } } public EqualCondition(string value) { this.value = value; } public override bool Satisfy(string valueToTest) { return value == valueToTest; // Equals condition... } } public sealed class ContainCondition : Condition { private readonly string value; public string Value { get { return value; } } public ContainCondition(string value) { this.value = value; } public override bool Satisfy(string valueToTest) { return valueToTest.Contains(valueToTest); // Contains condition } } // The dictionary is used to list the conditions applied to each element. Dictionary<string, Condition> conditions = new Dictionary<string, Condition> { { "name", new EqualCondition("John") } }; XDocument document = XDocument.Load("test.xml"); var booms = from boomElement in document.Descendants("boom") // The next line check where all conditions are satisfied for the corresponding elements where conditions.All(condition => condition.Value.Satisfy((string)boomElement.Element(condition.Key))) let boomChildren = (from boomElementChild in boomElement.Elements() select String.Format("{0}: {1}", boomElementChild.Name.LocalName, boomElementChild.Value)) select String.Join(Environment.NewLine, boomChildren); var result = String.Join(Environment.NewLine + Environment.NewLine, booms);
其他推荐答案
我会强烈输入:
public class Boom { string Name { get; set; } string Address { get; set; } public override string ToString() { return string.Format("Name: {0}{1}Address: {2}, Name, Environment.NewLine, Address); } }
因此您的查询更改为:
XDocument document = XDocument.Load(new StringReader(xmlString)); var booms = document.Descendants("boom") .Select(x => new Boom { Name = x.Element("name").Value, Address = x.Element("address").Value }) .Where(b => /*filter here!*/);
其他推荐答案
还没测试过,试试这个:
//string xmlString = ...; XDocument document = XDocument.Load(new StringReader(xmlString)); var booms = from boomElement in document.Descendants("boom").Where(x => true) let boolChildren = (from boomElementChild in boomElement.Elements() select String.Format("{0}: {1}", boomElementChild.Name.LocalName, boomElementChild.Value)) select String.Join(Environment.NewLine, boolChildren); var result = String.Join(Environment.NewLine + Environment.NewLine, booms);
用你对 x 的测试替换 true...
问题描述
I have this XML string of "booms":
<booms> <boom> <name>John</name> <address>New York City</address> </boom> <boom> <name>Daniel</name> <address>Los Angeles</address> </boom> <boom> <name>Joe</name> <address>Chicago</address> </boom> </booms>
I also have this LINQ C# code
//string xmlString = ...; XDocument document = XDocument.Load(new StringReader(xmlString)); var booms = from boomElement in document.Descendants("boom") let boolChildren = (from boomElementChild in boomElement.Elements() select String.Format("{0}: {1}", boomElementChild.Name.LocalName, boomElementChild.Value)) select String.Join(Environment.NewLine, boolChildren); var result = String.Join(Environment.NewLine + Environment.NewLine, booms);
that turns the XML into this string:
name: John address: New York City name: Daniel address: Los Angeles name: Joe address: Chicago
Question:
How can I change the LINQ to filter out booms that satisfy some condition? For example, how can I filter out booms that have an address containing "New"? In this case, this would give the string:
name: John address: New York City
The code should not be limited to only a "contains" filter though.
推荐答案
If the conditions are limited to equal.
Dictionary<string, string> conditions = new Dictionary<string, string> { { "name", "John" } }; XDocument document = XDocument.Load(new StringReader(xmlString)); var booms = from boomElement in document.Descendants("boom") where conditions.All(condition => (string)boomElement.Element(condition.Key) == condition.Value) // Where is used to filter the result let boomChildren = (from boomElementChild in boomElement.Elements() select String.Format("{0}: {1}", boomElementChild.Name.LocalName, boomElementChild.Value)) select String.Join(Environment.NewLine, boomChildren); var result = String.Join(Environment.NewLine + Environment.NewLine, booms);
If it is not limited to equal (contain, equal, <, >) you have to create a structure that will represent the condition.
// I've made Condition an abstract class to super any kind of condition. // Just derive this class with the condition you want (And, Or, Equal, <=, IsNumber, ...) public abstract class Condition { // A condition is defined by this method. Because a condition is basically: "Does the specified value satisfy the condition?" public abstract bool Satisfy(string valueToTest); } // This is the first example of condition. // I wanted to make the condition immutable (readonly) not to be able to change them. // So, all parameters of the condition are set during the construction. public sealed class EqualCondition : Condition { private readonly string value; public string Value { get { return value; } } public EqualCondition(string value) { this.value = value; } public override bool Satisfy(string valueToTest) { return value == valueToTest; // Equals condition... } } public sealed class ContainCondition : Condition { private readonly string value; public string Value { get { return value; } } public ContainCondition(string value) { this.value = value; } public override bool Satisfy(string valueToTest) { return valueToTest.Contains(valueToTest); // Contains condition } } // The dictionary is used to list the conditions applied to each element. Dictionary<string, Condition> conditions = new Dictionary<string, Condition> { { "name", new EqualCondition("John") } }; XDocument document = XDocument.Load("test.xml"); var booms = from boomElement in document.Descendants("boom") // The next line check where all conditions are satisfied for the corresponding elements where conditions.All(condition => condition.Value.Satisfy((string)boomElement.Element(condition.Key))) let boomChildren = (from boomElementChild in boomElement.Elements() select String.Format("{0}: {1}", boomElementChild.Name.LocalName, boomElementChild.Value)) select String.Join(Environment.NewLine, boomChildren); var result = String.Join(Environment.NewLine + Environment.NewLine, booms);
其他推荐答案
I would strongly type this:
public class Boom { string Name { get; set; } string Address { get; set; } public override string ToString() { return string.Format("Name: {0}{1}Address: {2}, Name, Environment.NewLine, Address); } }
So your query changes to this:
XDocument document = XDocument.Load(new StringReader(xmlString)); var booms = document.Descendants("boom") .Select(x => new Boom { Name = x.Element("name").Value, Address = x.Element("address").Value }) .Where(b => /*filter here!*/);
其他推荐答案
Haven't tested this, but try this:
//string xmlString = ...; XDocument document = XDocument.Load(new StringReader(xmlString)); var booms = from boomElement in document.Descendants("boom").Where(x => true) let boolChildren = (from boomElementChild in boomElement.Elements() select String.Format("{0}: {1}", boomElementChild.Name.LocalName, boomElementChild.Value)) select String.Join(Environment.NewLine, boolChildren); var result = String.Join(Environment.NewLine + Environment.NewLine, booms);
Replace true with your test on x...