假设您有类似这样的XML:
<data>
<messages>
<message name="Person" id="P">
<field name="FirstName" required="Y" />
<field name="LastName" required="Y" />
<field name="Sex" required="N" />
</message>
<message name="Car" id="C">
<field name="Make" required="Y" />
<field name="Model" required="Y" />
<field name="Year" required="N" />
</message>
</messages>
</data>
使用Linq,您如何获得Person的所有必填字段名称列表?
我今天刚刚开始使用LINQ / XML,这就是我所得到的。
var q = from c in loaded.Descendants("field")
where (string)c.Attribute("required") == "Y" &&
// how to check the parent node (message) has an attribute (id="P")
select (string)c.Attribute("name");
foreach (string name in q)
Console.WriteLine(name);
答案 0 :(得分:2)
您可以通过执行以下操作来删除单独的foreach循环和丑陋的演员
(from c in myXML.Descendants("field")
where c.Attribute("required").Value == "Y" &&
c.Parent.Attribute("id").Value == "P"
select c.Attribute("name").Value).ToList().ForEach(s => Console.WriteLine(s.ToString()));
编辑:
由于出现了null或者可选属性的问题,这里是一个如何添加扩展方法来处理null属性的例子,你可以传递一个默认值来使用,如果一个不存在(这是第二个参数)扩展方法)。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Text;
namespace MyTestApp
{
class Program
{
static void Main(string[] args)
{
XDocument myXML = XDocument.Load(@"C:\file.xml");
(from c in myXML.Descendants("field")
where c.Attribute("required")
.GetAttributeValueOrDefault("N") == "Y" &&
c.Parent.Attribute("id").Value == "P"
select
c.Attribute("name").Value).ToList().ForEach(s => Console.WriteLine(s.ToString()));
Console.ReadLine();
}
}
public static class XLinqHelper
{
// extension method that handles an xattribute and returns the provided default if the Xattrib is null
public static string GetAttributeValueOrDefault(this XAttribute s, string defaultValue)
{
string retVal;
if (s == null)
retVal = defaultValue;
else
retVal = s.Value;
return retVal;
}
}
}
答案 1 :(得分:2)
我为消息添加了一个根元素和结束标记,以使XML有效:
XDocument loaded = XDocument.Parse(@"
<messages>
<message name=""Person"" id=""P"">
<field name=""FirstName"" required=""Y"" />
<field name=""LastName"" required=""Y"" />
<field name=""Sex"" required=""N"" />
</message>
<message name=""Car"" id=""C"">
<field name=""Make"" required=""Y"" />
<field name=""Model"" required=""Y"" />
<field name=""Year"" required=""N"" />
</message>
</messages>");
不要查找所有字段然后检查每个字段的父节点,而是查找您感兴趣的父节点,以便查看较少的字段:
IEnumerable<string> fields =
loaded.Root.Elements()
.Where(m => m.Attribute("id").Value == "P")
.Single()
.Elements("field")
.Where(f => f.Attribute("required").Value == "Y")
.Select(f => f.Attribute("name").Value);
编辑:
如果message元素包含任何其他类型的元素,则为子元素添加说明符“field”。
编辑2:
我将一个工作示例与实际数据的子集放在一起:
XDocument loaded = XDocument.Parse(@"
<fix major=""4"" minor=""4"">
<header>
</header>
<trailer>
</trailer>
<messages>
<message name=""ResendRequest"" msgtype=""2"" msgcat=""admin"">
<field name=""BeginSeqNo"" required=""Y"" />
<field name=""EndSeqNo"" required=""Y"" />
</message>
<message name=""Reject"" msgtype=""3"" msgcat=""admin"">
<field name=""RefSeqNum"" required=""Y"" />
<field name=""RefTagID"" required=""N"" />
<field name=""RefMsgType"" required=""N"" />
<field name=""SessionRejectReason"" required=""N"" />
<field name=""Text"" required=""N"" />
<field name=""EncodedTextLen"" required=""N"" />
<field name=""EncodedText"" required=""N"" />
</message>
</messages>
</fix>");
IEnumerable<string> fields =
loaded.Root.Element("messages").Elements("message")
.Where(m => m.Attribute("name").Value == "Reject")
.Single()
.Elements("field")
.Where(f => f.Attribute("required").Value == "Y")
.Select(f=>f.Attribute("name").Value);
答案 2 :(得分:1)
答案 3 :(得分:1)
考虑到提问者改变了他的xml,这个答案是完全错误的。我应该删除它。
var q = from c in loaded.Descendants("field")
where (string)c.Attribute("required") == "Y" &&
c.Parent.Attribute("id").Value == "P"
select (string)c.Attribute("name");
添加我使用的Xml,因为对正确的解决方案存在一些困惑。
XDocument loaded = XDocument.Parse(@"
<message name=""Person"" id=""P"">
<field name=""FirstName"" required=""Y"" />
<field name=""LastName"" required=""Y"" />
<field name=""Sex"" required=""N"" />
<message name=""Car"" id=""C"">
<field name=""Make"" required=""Y"" />
<field name=""Model"" required=""Y"" />
<field name=""Year"" required=""N"" />
</message>
</message>");