[英]What is the best way to sort xml elements by attribute values in c#/.net 3.5
I have a XML file with data like: 我有一个XML文件,其数据如下:
<Details>
<TableDef>
<Column Name="Calldate" HeaderName="Calldate" SourceColumnName="Calldate" IsHidden = "false" Position="4" />
<Column Name="Issue" HeaderName="Issues" SourceColumnName="Issues" IsHidden = "false" Position="3" />
<Column Name="ParamortizedValue" HeaderName="paramortizedvalue" SourceColumnName="Value" IsHidden = "false" Position="1" />
<Column Name="PercentBondTotal" HeaderName="percentbondtotal" SourceColumnName="Percentage" IsHidden = "false" Position="2" />
</TableDef>
</Details>
I was wondering what would be the best and efficient way to filter and sort the elements by an attribute so that I can use that sorted elements further in my code? 我想知道按属性对元素进行过滤和排序的最佳,有效方法是什么,以便可以在代码中进一步使用排序后的元素?
In above example, I want to filter by "IsHidden = false" and then sort the elements by "Position" attribute. 在上面的示例中,我想按“ IsHidden = false”进行过滤,然后按“ Position”属性对元素进行排序。
I have the following code that will read all the elements without any sort: 我有以下代码,无需任何排序即可读取所有元素:
var doc = XDocument.Load("data.xml");
var nodeTableDefInfo = doc.XPathSelectElements("/Details");
var elements = nodeTableDefInfo.Elements("TableDef").Elements();
foreach (var e in elements)
{
//want to work on the sorted elements
}
Guys, Thanks for all the solutions. 伙计们,感谢您提供的所有解决方案。 before I could read your solution I came up with this: 在我读懂您的解决方案之前,我想出了这一点:
var elements = nodeTableDefInfo.Elements("TableDef").Elements();
var sortedElements = (from element in elements
where element.Attribute("IsHidden").Value == "false"
orderby element.Attribute("Position").Value ascending
select element);
foreach (var e in sortedElements)
{
//work on the sorted elements
}
Now, after going through the solutions, I really liked the solution and explanation provided by GFK
. 现在,在完成解决方案之后,我真的很喜欢GFK
提供的解决方案和说明。 I guess I need some handling for nulls. 我想我需要对null进行一些处理。 Thanks all. 谢谢大家
Use some more LINQ! 再使用一些LINQ!
var sortedElements =
from element in elements
let hiddenAttribute = element.Attribute("IsHidden")
let positionAttribute = element.Attribute("Position")
where hiddenAttribute != null
&& positionAttribute != null
&& hiddenAttribute.Value == "false"
let position = int.Parse(positionAttribute)
orderby position
select element;
foreach (var e in sortedElements)
{
// ...
}
Edit: also, what I do usually with LINQ-to-XML is create an anonymous type so I can parse once and for all the attributes into strongly typed values (and handle missing or invalid values), like: 编辑:此外,我通常使用LINQ-to-XML进行的工作是创建一个匿名类型,这样我就可以将所有属性一次解析为强类型值(并处理缺失或无效值),例如:
int parsedInt;
var sortedElements =
from element in elements
let hiddenAttribute = element.Attribute("IsHidden")
let positionAttribute = element.Attribute("Position")
// add other attributes here
select new
{
IsHidden = hiddenAttribute == null || hiddenAttribute.Value != "false",
Position = positionAttribute == null || !int.TryParse(positionAttribute.Value, out parsedInt)
? default(int?)
: parsedInt,
// add other parsed attributes here
};
This way, all operations is made easier, like sorting or filtering: 这样,使所有操作变得更容易,例如排序或过滤:
foreach(var element in sortedElements.Where(e => !e.IsHidden).OrderBy(e => e.Position)
{
// ...
}
var tableDefs = nodeTableDefInfo.Elements("TableDef").Elements();
foreach(var column in tableDefs.Where(x=>
x.Attributes("IsHidden") != null &&
bool.Parse(x.Attributes("IsHidden").value) == false &&
x.Attributes("Position") != null)
.OrderBy(x=>int.Parse(x.Attributes("Position"))
Try Linq2XML. 尝试使用Linq2XML。
XDocument ip = XDocument.Load(Server.MapPath("~/data.xml"));
var op = ip.Descendants("Column")
.Where(node => node.Attribute("IsHidden").Value == "false")
.OrderBy(node => int.Parse(node.Attribute("Position").Value))
.ToList();
Now, op
will be List<XElement>
. 现在, op
将为List<XElement>
。 Use for
or foreach
to manipulate it. 使用for
或foreach
进行操作。
linq.. linq ..
string str = @"
<Details>
<TableDef>
<Column Name='Calldate' HeaderName='Calldate' SourceColumnName='Calldate' IsHidden='false' Position='4' />
<Column Name='Issue' HeaderName='Issues' SourceColumnName='Issues' IsHidden='false' Position='3' />
<Column Name='ParamortizedValue' HeaderName='paramortizedvalue' SourceColumnName='Value' IsHidden = 'false' Position='1' />
<Column Name='PercentBondTotal' HeaderName='percentbondtotal' SourceColumnName='Percentage' IsHidden = 'false' Position='2' />
</TableDef>
</Details>";
XDocument xml = XDocument.Parse(str);
List<XElement> columns = (from t in xml.Descendants("TableDef").Descendants("Column") where (bool)t.Attribute("IsHidden") == false orderby (int)t.Attribute("Position") ascending select t).ToList();
Sample approach: 示例方法:
var list = new List<KeyValuePair<string, XElement>>();
foreach(var element in elements)
{
list.Add(new KeyValuePair<string,XElement>(
element.Attribute("someAttr").Value,
element));
}
var sorted = from entry in list
orderby entry.Value.Attribute("someAttr").Value
select entry;
// just test:
foreach (var entry in sorted)
{
Debug.WriteLine(String.Format("attribute value: {0} - element: {1}", entry.Key, entry.Value.ToString()));
}
We're retrieving your chosen attribute values and treat it as an index. 我们正在检索您选择的属性值,并将其视为索引。
We create a dictionary (a list of key-value pairs to be precise, as those values may not be unique) and then we just sort the list by the key. 我们创建一个字典(精确的键值对列表,因为这些值可能不是唯一的),然后我们按键对列表进行排序。
I assume that this attribute will be present for every XElement
- if that's not the case, you need to check for null of course. 我假设每个XElement
都将存在此属性-如果不是这种情况,则当然需要检查是否为null。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.