如何使用LINQ to XML连接具有相同名称值的所有子元素

时间:2016-03-10 22:55:13

标签: c# xml linq

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问题中的情况不同。

3 个答案:

答案 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>