【问题标题】:c# join XML files produce duplicates using Linq DefaultIfEmpty()c# 使用 Linq DefaultIfEmpty() 连接 XML 文件产生重复
【发布时间】:2015-08-10 01:54:14
【问题描述】:

我正在尝试对两个 XML 文档执行 leftOuterJoin,但是我目前使用的方式似乎从 fileone 返回了一些奇怪的重复部分(在下面的代码中解释)。我尝试了很多方法,但无法弄清楚如何做到这一点。有人可以帮忙解决这个问题吗?提前谢谢了!

文件:

<fileone>

    <Book BookID="dog"> Dog </Book>

    <Book BookID="cat"> Cat </Book>

</fileone>

文件二:

<filetwo>

       <Edition BID="cat" OrderID="100"> about cat</Edition>

       <Edition BID="cat" OrderID="200">more about cat</Edition>

</RightSeq>

我正在寻找的是(bookID=BID 上的左外连接):

<item>
   <Book BookID="cat"> Dog </Book>
</item>
<item>
    <Book BookID="cat"> Cat </Book>
    <Edition BID="cat" OrderID="100"> about cat</Edition>
</item>
<item>
    <Book BookID="cat"> Cat </Book>
    <Edition BID="cat" OrderID="200"> more cat</Edition>
</item>

我的(错误)代码:

      var result = from a in fileone.Descendants()
      join b in secondxdoc.Descendants()
     on (string)a.Attribute("BookID") equal (string)b.Attribute("BID") into inners
      from ele in inners.DefaultIfEmpty()

      select new XElement("item", new XElement(a), ele == null ? null : new XElement(ele));
        var output = new XElement("LeftOuterJoin", result);         
    }

当前错误结果:

<item>
   <fileone>  
       <Book BookID="dog"> Dog </Book> // this entire <fileone> bit is unwanted
       <Book BookID="cat"> Cat </Book>  //I don't know what I've done wrong
   </fileone> 
</item>
    <item>
   <Book BookID="cat"> Dog </Book>
</item>
<item>
    <Book BookID="cat"> Cat </Book>
    <Edition BID="cat" OrderID="100"> about cat</Edition>
</item>
<item>
    <Book BookID="cat"> Cat </Book>
    <Edition BID="cat" OrderID="200"> more cat</Edition>
</item>  

【问题讨论】:

    标签: c# xml linq join duplicates


    【解决方案1】:

    不需要的第一个 &lt;item&gt; 元素是将根元素 &lt;fileone&gt; 与第二个文件的后代连接的结果。如果要跳过根元素,请将 fileone.Descendants() 替换为 fileone.Root.Descendants()

    var result = from a in fileone.Root.Descendants()
                 join b in secondxdoc.Descendants()
                    on (string)a.Attribute("BookID") equal (string)b.Attribute("BID") into inners
                 from ele in inners.DefaultIfEmpty()
                 select new XElement("item", a, ele);
    var output = new XElement("LeftOuterJoin", result);
    

    Dotnetfiddle Demo

    【讨论】:

      【解决方案2】:

      我在不使用传统 linq 的情况下得到了结果。如果 fileone 在 filetwo 中没有匹配项,则连接不会给出结果。

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Xml;
      using System.Xml.Linq;
      
      namespace ConsoleApplication1
      {
          class Program
          {
              static void Main(string[] args)
              {
                  string input1 =
                     "<fileone>" +
                         "<Book BookID=\"dog\"> Dog </Book>" +
                         "<Book BookID=\"cat\"> Cat </Book>" +
                     "</fileone>";
                  XDocument fileone = XDocument.Parse(input1);
      
                  string input2 =
                     "<filetwo>" +
                            "<Edition BID=\"cat\" OrderID=\"100\"> about cat</Edition>" +
                            "<Edition BID=\"cat\" OrderID=\"200\">more about cat</Edition>" +
                     "</filetwo>";
                  XDocument secondxdoc = XDocument.Parse(input2);
      
                  //<item>
                  //   <Book BookID="cat"> Dog </Book>
                  //</item>
                  //<item>
                  //    <Book BookID="cat"> Cat </Book>
                  //    <Edition BID="cat" OrderID="100"> about cat</Edition>
                  //</item>
                  //<item>
                  //    <Book BookID="cat"> Cat </Book>
                  //    <Edition BID="cat" OrderID="200"> more cat</Edition>
                  //</item>
                  XElement output = new XElement("Root");
                  foreach (XElement item in fileone.Descendants("Book"))
                  {
                      string bookId = item.Attribute("BookID").Value;
                      List<XElement> bookTwoItems = secondxdoc.Descendants("Edition").Where(x => x.Attribute("BID").Value == bookId).ToList();
                      if (bookTwoItems.Count  == 0)
                      {
                          XElement newItem = new XElement("item");
                          output.Add(newItem);
                          newItem.Add(item);
                      }
                      else
                      {
                          foreach (XElement bookTwoItem in bookTwoItems)
                          {
                              XElement newItem = new XElement("item");
                              output.Add(newItem);
                              newItem.Add(item);
                              newItem.Add(bookTwoItem);
                          }
                      }
                      
                  }
              
              }
          }
      }
      ​

      让它与左外连接一起工作

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Xml;
      using System.Xml.Linq;
      
      namespace ConsoleApplication1
      {
          class Program
          {
              static void Main(string[] args)
              {
                  string input1 =
                     "<fileone>" +
                         "<Book BookID=\"dog\"> Dog </Book>" +
                         "<Book BookID=\"cat\"> Cat </Book>" +
                     "</fileone>";
                  XDocument fileone = XDocument.Parse(input1);
      
                  string input2 =
                     "<filetwo>" +
                            "<Edition BID=\"cat\" OrderID=\"100\"> about cat</Edition>" +
                            "<Edition BID=\"cat\" OrderID=\"200\">more about cat</Edition>" +
                     "</filetwo>";
                  XDocument secondxdoc = XDocument.Parse(input2);
      
                  //<item>
                  //   <Book BookID="cat"> Dog </Book>
                  //</item>
                  //<item>
                  //    <Book BookID="cat"> Cat </Book>
                  //    <Edition BID="cat" OrderID="100"> about cat</Edition>
                  //</item>
                  //<item>
                  //    <Book BookID="cat"> Cat </Book>
                  //    <Edition BID="cat" OrderID="200"> more cat</Edition>
                  //</item>
                  var results = (from one in fileone.Descendants("Book")
                                 join two in secondxdoc.Descendants("Edition") on one.Attribute("BookID").Value equals two.Attribute("BID").Value into inners
                                 from two in inners.DefaultIfEmpty()
                                 select new { fileone = one, filetwo = two == null ? null : two }).ToList(); 
                  XElement output = new XElement("Root");
                  foreach (var item in results)
                  {
                      XElement newItem = new XElement("item");
                      output.Add(newItem);
                      newItem.Add(item.fileone);
                      if (item.filetwo  != null)
                      {
                              newItem.Add(item.filetwo);
                      }
      
                  }
      
              }
          }
      }
      ​
      

      或者这个方法

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Xml;
      using System.Xml.Linq;
      
      namespace ConsoleApplication1
      {
          class Program
          {
              static void Main(string[] args)
              {
                  string input1 =
                     "<fileone>" +
                         "<Book BookID=\"dog\"> Dog </Book>" +
                         "<Book BookID=\"cat\"> Cat </Book>" +
                     "</fileone>";
                  XDocument fileone = XDocument.Parse(input1);
      
                  string input2 =
                     "<filetwo>" +
                            "<Edition BID=\"cat\" OrderID=\"100\"> about cat</Edition>" +
                            "<Edition BID=\"cat\" OrderID=\"200\">more about cat</Edition>" +
                     "</filetwo>";
                  XDocument secondxdoc = XDocument.Parse(input2);
      
                  //<item>
                  //   <Book BookID="cat"> Dog </Book>
                  //</item>
                  //<item>
                  //    <Book BookID="cat"> Cat </Book>
                  //    <Edition BID="cat" OrderID="100"> about cat</Edition>
                  //</item>
                  //<item>
                  //    <Book BookID="cat"> Cat </Book>
                  //    <Edition BID="cat" OrderID="200"> more cat</Edition>
                  //</item>
                  XElement output = new XElement("Root");
                  var results = (from one in fileone.Descendants("Book")
                                 join two in secondxdoc.Descendants("Edition") on one.Attribute("BookID").Value equals two.Attribute("BID").Value into inners
                                 from two in inners.DefaultIfEmpty()
                                 select new { fileone = one, filetwo = two == null ? null : two })
                                 .Select(x => x.filetwo == null ? new XElement("item", x.fileone) : new XElement("item", new object[] { x.fileone, x.filetwo }));
                  foreach (var item in results)
                  {
                      output.Add(item);
                  }
              }
          }
      }
      ​
      

      【讨论】:

        猜你喜欢
        • 2013-02-04
        • 1970-01-01
        • 1970-01-01
        • 2022-01-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多