為 XmlNode.SelectNodes 加上排序功能
測試資料
<Item a='1' b='5' c='9' m='9'/>
<Item a='2' b='6' c='9' m='9'/>
<Item a='3' b='7' c='9' m='9'/>
<Item a='4' b='8' c='9' m='1'/>
<Item a='5' b='9' c='9' m='1'/>
<Item a='6' b='0' c='5' m='1'/>
<Item a='7' b='1' c='5' m='1'/>
<Item a='8' b='2' c='5' m='5'/>
<Item a='9' b='3' c='5' m='5'/>
<Item a='0' b='4' c='5' m='5'/>
<Item a='A' b='5' c='5' m='5'/>
</Config>
測試結果
1. 依 c 及 b 屬性排序
2. b 屬性改由大到小排序
a=6 b=0 c=5 m=1
a=7 b=1 c=5 m=1
a=8 b=2 c=5 m=5
a=9 b=3 c=5 m=5
a=0 b=4 c=5 m=5
a=A b=5 c=5 m=5
a=1 b=5 c=9 m=9
a=2 b=6 c=9 m=9
a=3 b=7 c=9 m=9
a=4 b=8 c=9 m=1
a=5 b=9 c=9 m=1
c,-b
a=A b=5 c=5 m=5
a=0 b=4 c=5 m=5
a=9 b=3 c=5 m=5
a=8 b=2 c=5 m=5
a=7 b=1 c=5 m=1
a=6 b=0 c=5 m=1
a=5 b=9 c=9 m=1
a=4 b=8 c=9 m=1
a=3 b=7 c=9 m=9
a=2 b=6 c=9 m=9
a=1 b=5 c=9 m=9
測試程式
{
var xml = new XmlDocument();
xml.LoadXml(@"<Config>
<Item a='1' b='5' c='9' m='9'/>
<Item a='2' b='6' c='9' m='9'/>
<Item a='3' b='7' c='9' m='9'/>
<Item a='4' b='8' c='9' m='1'/>
<Item a='5' b='9' c='9' m='1'/>
<Item a='6' b='0' c='5' m='1'/>
<Item a='7' b='1' c='5' m='1'/>
<Item a='8' b='2' c='5' m='5'/>
<Item a='9' b='3' c='5' m='5'/>
<Item a='0' b='4' c='5' m='5'/>
<Item a='A' b='5' c='5' m='5'/>
</Config>");
var keepRunning = true;
while (keepRunning)
{
var command = Console.ReadLine();
switch (command)
{
case "/exit":
case "/quit":
keepRunning = false;
break;
default:
try
{
foreach (var i in xml.SelectNodes("/Config/Item", command))
{
foreach (XmlAttribute a in i.Attributes)
Console.Write("{0}={1} ", a.Name, a.Value);
Console.WriteLine();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
break;
}
}
}
核心程式
{
public static IEnumerable<XmlNode> SelectNodes(this XmlNode node, string xpath, string orderby)
{
var sorter = Sorter.Create(orderby);
return
sorter == null
? node.SelectNodes(xpath).AsEnumerable()
: sorter.Sort(node.SelectNodes(xpath));
}
private static IEnumerable<XmlNode> AsEnumerable(this XmlNodeList list)
{
foreach (XmlNode i in list)
yield return i;
}
private static string Attrib(this XmlNode node, string name, string defaultValue)
{
return (node.Attributes[name] == null)
? defaultValue
: node.Attributes[name].Value;
}
class Sorter
{
public string Key { get; set; }
public bool Descending { get; set; }
public Sorter Next { get; set; }
private IOrderedEnumerable<XmlNode> Sort(IOrderedEnumerable<XmlNode> list)
{
var flow = (Next != null ? 0x10 : 0x00) + (Descending ? 0x01 : 0x00);
switch (flow)
{
case 0x11: return Next.Sort(list.ThenByDescending(o => o.Attrib(Key, "")));
case 0x10: return Next.Sort(list.ThenBy(o => o.Attrib(Key, "")));
case 0x01: return list.ThenByDescending(o => o.Attrib(Key, ""));
case 0x00: return list.ThenBy(o => o.Attrib(Key, ""));
}
throw new Exception("!!!");
}
public IEnumerable<XmlNode> Sort(XmlNodeList nodes)
{
var flow = (Next != null ? 0x10 : 0x00) + (Descending ? 0x01 : 0x00);
switch (flow)
{
case 0x11: return Next.Sort(nodes.AsEnumerable().OrderByDescending(o => o.Attrib(Key, "")));
case 0x10: return Next.Sort(nodes.AsEnumerable().OrderBy(o => o.Attrib(Key, "")));
case 0x01: return nodes.AsEnumerable().OrderByDescending(o => o.Attrib(Key, ""));
case 0x00: return nodes.AsEnumerable().OrderBy(o => o.Attrib(Key, ""));
}
return null;
}
public static Sorter Create(string orderby)
{
if (string.IsNullOrEmpty(orderby)) return null;
var fields = orderby.Split(',');
var list = new List<Sorter>();
foreach (var i in fields)
{
var s = i.Trim();
var desc = s.StartsWith("-");
var key = desc ? s.Substring(1) : s;
if (string.IsNullOrEmpty(key)) continue;
list.Add(new Sorter { Key = key, Descending = desc });
}
for (int i = 1; i < list.Count; i++)
list[i - 1].Next = list[i];
if (list.Count > 0) return list[0];
return null;
}
}
}