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

C# 如何使用LINQ到XML连接具有相同名称和值的所有子元素,c#,xml,linq,C#,Xml,Linq,假设XML文件如下所示: <root> <book> <title>book1Title</title> <author>book1Author1</author> </book> <book> <title>book2Title</title> <author>book2Author1</author>

假设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>
但我不能这样做,因为:

“foreach语句无法对类型为的变量进行操作 “System.Xml.Linq.XElement”是因为“System.Xml.Linq.XElement”不是 包含“GetEnumerator”的公共定义


尽管VarBook是一个有其他元素的元素,但与所讨论的情况不同。

这个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>

书名
书籍1作者1
书名
第2册作者1
书籍2作者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));
}

听起来像是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);
    }
}
使用系统;
使用System.Xml;
使用System.Xml.Xsl;
使用System.IO;
公共课程
{
公共静态void Main()
{
var xsl=@”
位置()“”>
, 
位置()“”>
, 
";
var xml=@”
书名
书籍1作者1
书名
第2册作者1
书籍2作者2
第9册标题1
第9册标题2
第九册作者
";
字符串输出=string.Empty;
使用(StringReader srt=new StringReader(xsl))//xslInput是一个包含xsl的字符串
使用(StringReader sri=new StringReader(xml))//xmlInput是一个包含xml的字符串
{
使用(XmlReader xrt=XmlReader.Create(srt))
使用(XmlReader xri=XmlReader.Create(sri))
{
var xslt=新的XslCompiledTransform();
Load(xrt);
使用(StringWriter sw=new StringWriter())
使用(xmlwriterxwo=XmlWriter.Create(sw,xslt.OutputSettings))//使用xsl的OutputSettings,这样它就可以作为HTML输出
{
Transform(xri,xwo);
输出=sw.ToString();
}
}
}
控制台写入线(输出);
}
}

嗯。。。虽然每本书可以有多个作者(在这种情况下,它将是一个作者列表),但每本书只能有一个标题。可能是@Monty的副本,可能是不同语言的标题。。。这都不重要,谢谢你!我打算使用second foreach来运行Tour来检查并对中的每个子元素执行此操作,这样我就不必为不同的子元素编写相同的行,也不必知道有多少行以及它们的名称。确实可以,但我不能更改xml:/感谢您的努力:)我应该提出我的第一个问题。。。octavioccl的快速解决方案做得很好,而且……如果这是“他们”想要的,我很同情你☺
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));
}
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);
    }
}