use linq aggregate function to build xml string?
I've used this in the past to build comma seperated lists:
var list = new List<int>{1,2,3};
var retVal = list.Select(i=>i.ToString()).Aggregate((a,b) => a+", "+b);
Works great.
I'm trying to do the same sort of 开发者_如何转开发thing to 'wrap' each element as an xml node.
Something like:
Aggregate((a, b) => string.Format("<ID>{0}</ID><ID>{1}</ID>", a,b))
Can't quite seem to make it work though. Is it possible? Or is there an easier way entirely?
Thanks.
Blindy's answer will certainly work, but I'd personally use:
var list = new List<int> {1, 2, 3};
var joined = string.Join("", list.Select(x => "<ID>" + x + "</ID>")
.ToArray());
I personally find that easier to read and understand than the aggregation. I believe it will be more efficient, too - although that will only matter for large lists.
Or is there an easier way entirely?
List<int> list = new List<int>{1, 2, 3};
var xmlNodes = list.Select(i => new XElement("ID", i));
XElement xml = new XElement("Data", xmlNodes);
Console.WriteLine(xml);
Shouldn't it be like:
Aggregate((a, b) => string.Format("{0}<ID>{1}</ID>", a,b))
You're adding to a
new nodes.
There are a number of ways to achieve this but I suspect the correct answer is "it depends". Your original example for creating a CSV string uses the string concatenation operator; the recommended approach is to use the StringBuilder class for this purpose. And in .Net 4.0 there is a new overload for the string.Join() method that is a whole lot simpler to use and understand.
// .Net 3.5
var list = new List<int>{1,2,3};
var csv = list.Aggregate(new StringBuilder(),
(sb, i) => sb.Append(i).Append(','),
sb => { if (sb.Length > 0) sb.Length--; return sb.ToString(); });
// .Net 4.0
var csv1 = string.Join(",", list);
If your intention is to create an XML Document rather than a string then David B's answer above is a good option:
var xml = new XElement("Root", list.Select(i => new XElement("ID", i)));
// <Root>
// <ID>1</ID>
// <ID>2</ID>
// <ID>3</ID>
// </Root>
For creating XML strings I prefer to avoid explicitly coding opening and closing tags. In your example it would be difficult to get the element name "ID" incorrect in either opening or closing tags but I think of this in terms of the DRY principle. On occasion I have forgotten to modify the closing tag for an element when I have modified the opening tag e.g. in config files. Using XElement avoids this issue completely:
// .Net 3.5
var xml1 = list.Aggregate(new StringBuilder(),
(sb, i) => sb.Append(new XElement("ID", i)),
sb => sb.ToString());
// .Net 4.0
var xml2 = string.Join("", list.Select (i => new XElement("ID", i)));
// both xml1 & xml2 contain "<ID>1</ID><ID>2</ID><ID>3</ID>"
Performance of Aggregate() versus string.Join(), string.Join() wins every time (with the fairly limited/basic test case I used).
精彩评论