Say XML文件如下所示:
<root>
<book>
<title>book1Title</title>
<author>book1Author1</author>
</book>
<book>
<title>book2Title</title>
<author>book2Author1</author>
<author>book2Author2</author>
</book>
...
<book>
<title>book9Title1</title>
<title>book9Title2</title>
<author>book9Author</author>
</book>
</root>
我需要的输出如下:
<root>
<book>
<title>book1Title</title>
<author>book1Author1</author>
</book>
<book>
<title>book2Title</title>
<author>book2Author1, book2Author2</author>
</book>
...
<book>
<title>book9Title1, book9Title2</title>
<author>book9Author</author>
</book>
</root>
我的想法是使用嵌套的foreach:
foreach(var book in doc1.Root.Elements("book")) //doc1 is XDocument
{
foreach (var datafield in book)
{
//select all XElements with name datafield.Name
//put all the values to list
//delete all selected XElements
//create new XElement with name datafield.Name and write text values from list to it
}
}
但我不能这样做因为:
&#34; foreach语句不能对类型的变量进行操作 &#39; System.Xml.Linq.XElement&#39;因为&#39; System.Xml.Linq.XElement&#39;才不是 包含&#39; GetEnumerator&#39;&#34;的公开定义
即使var book是一个具有其他元素的元素,与XElement Iteration and adding it to parent问题中的情况不同。
答案 0 :(得分:2)
你可以这样做:
foreach(var book in doc1.Root.Elements("book"))
{
var authors=String.Join(",",book.Elements("author").Select(e=>e.Value));// get all authors and create the result that you need
book.Elements("author").Remove();// remove all authors from current book
book.Add(new XElement("author", authors)); // create one node with all the author's names
//Do the same with the titles
var titles=String.Join(",",book.Elements("title").Select(e=>e.Value));
book.Elements("title").Remove();
book.Add(new XElement("title", titles));
}
答案 1 :(得分:1)
听起来像xslt
的工作using System;
using System.Xml;
using System.Xml.Xsl;
using System.IO;
public class Program
{
public static void Main()
{
var xsl = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<xsl:stylesheet version=""1.0""
xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"">
<xsl:template match=""/"">
<root>
<xsl:for-each select=""root/book"">
<book>
<author>
<xsl:for-each select=""author"">
<xsl:value-of select=""current()""/>
<xsl:if test=""last() > position()"">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
</author>
<title>
<xsl:for-each select=""title"">
<xsl:value-of select=""current()""/>
<xsl:if test=""last() > position()"">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
</title>
</book>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>";
var xml = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<root>
<book>
<title>book1Title</title>
<author>book1Author1</author>
</book>
<book>
<title>book2Title</title>
<author>book2Author1</author>
<author>book2Author2</author>
</book>
<book>
<title>book9Title1</title>
<title>book9Title2</title>
<author>book9Author</author>
</book>
</root>";
string output = String.Empty;
using (StringReader srt = new StringReader(xsl)) // xslInput is a string that contains xsl
using (StringReader sri = new StringReader(xml)) // xmlInput is a string that contains xml
{
using (XmlReader xrt = XmlReader.Create(srt))
using (XmlReader xri = XmlReader.Create(sri))
{
var xslt = new XslCompiledTransform();
xslt.Load(xrt);
using (StringWriter sw = new StringWriter())
using (XmlWriter xwo = XmlWriter.Create(sw, xslt.OutputSettings)) // use OutputSettings of xsl, so it can be output as HTML
{
xslt.Transform(xri, xwo);
output = sw.ToString();
}
}
}
Console.WriteLine(output);
}
}
答案 2 :(得分:0)
这种XML不会更好用吗......
<root>
<book>
<title>book1Title</title>
<authors>
<author>book1Author1</author>
</authors>
</book>
<book>
<title>book2Title</title>
<authors>
<author>book2Author1</author>
<author>book2Author2</author>
</authors>
</book>
</root>