c# 合并两个 XML 时出错

本文关键字:两个 XML 出错 合并 | 更新日期: 2023-09-27 17:56:23

我正在尝试将两个结构相同但数据不同的XML合并为一个。

我收到此错误:A node of type Document cannot be added to content.

下面是我的代码

var productElements =
    testGroupProvider.GetTestGroup().ProductTests.Select(
        productTest => new XElement(xNamespace + "Product",
            new XElement(xNamespace + "ExternalId", productTest.ProductNameKey),
            new XElement(xNamespace + "Name", testGroupProvider.GetProductName(productTest)),
            new XElement(xNamespace + "ImageUrl", ChoiceBaseHostName + GetProductImageUrl(productTest, TargetDatabase))));
var root = new XDocument(
    new XElement(xNamespace + "Feed",
        new XAttribute("xmlns", xNamespace),
        new XAttribute("name", BVFeedsName),
        new XAttribute("incremental", "true"),
        new XAttribute("extractDate", DateTime.Now.ToString("o")),
        new XElement(xNamespace + "Categories",
            new XElement(xNamespace + "Category",
                new XElement(xNamespace + "ExternalId", testGroupProvider.GetProductGroup().Id),
                new XElement(xNamespace + "Name", testGroupProvider.GetProductGroup().Name),
        testGroupProvider.GetTestGroup().Name),
        new XElement(xNamespace + "Products", productElements)));

var filePath = @"D:'testXML'test.xml";
XElement xml = XElement.Load(filePath);
xml.Add(root);
xml.Save(filePath);

谁能告诉我我做错了什么。

这是测试中的 XML 结构.xml

<?xml version="1.0" encoding="utf-8"?>
<Feed xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6" name="Choice" incremental="true" extractDate="2016-07-12T15:24:44.5732750+10:00">
  <Categories>
    <Category>
      <ExternalId>{09B3B4FB-F5CF-4522-BE96-4C4B535580C3}</ExternalId>
      <Name>Cereal and muesli</Name>
    </Category>
  </Categories>
  <Products>
    <Product>
      <ExternalId>coles-almond-hazelnut-macadamia-cluster-fusions</ExternalId>
      <Name>Coles Almond, Hazelnut &amp; Macadamia Cluster Fusions</Name>
       <ImageUrl></ImageUrl>
    </Product>
  </Products>
</Feed>

第二个 XML 具有相同的结构,具有不同的产品

<?xml version="1.0" encoding="utf-8"?>
<Feed xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6" name="Choice" incremental="true" extractDate="2016-07-12T15:24:44.5732750+10:00">
  <Categories>
    <Category>
      <ExternalId>{12}</ExternalId>
      <Name>cat1</Name>
    </Category>
  </Categories>
  <Products>
    <Product>
      <ExternalId>Id</ExternalId>
      <Name>Ccoles</Name>
       <ImageUrl></ImageUrl>
    </Product>
  </Products>
</Feed>

我想像下面这样组合它们

  <?xml version="1.0" encoding="utf-8"?>
    <Feed xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6" name="Choice" incremental="true" extractDate="2016-07-12T15:24:44.5732750+10:00">
      <Categories>
        <Category>
          <ExternalId>{09B3B4FB-F5CF-4522-BE96-4C4B535580C3}</ExternalId>
          <Name>Cereal and muesli</Name>
        </Category>
         <Category>
          <ExternalId>{12}</ExternalId>
          <Name>cat1</Name>
        </Category>
      </Categories>
      <Products>
        <Product>
          <ExternalId>coles-almond-hazelnut-macadamia-cluster-fusions</ExternalId>
          <Name>Coles Almond, Hazelnut &amp; Macadamia Cluster Fusions</Name>
           <ImageUrl></ImageUrl>
        </Product>
        <Product>
          <ExternalId>Id</ExternalId>
          <Name>Ccoles</Name>
           <ImageUrl></ImageUrl>
        </Product>
      </Products>
    </Feed>

c# 合并两个 XML 时出错

xml 文档必须只有一个根

使用您附加的文档,您可以将xml.Add(root);替换为以下内容(即,它将一个根下的每个节点添加到另一个 xml 根)

foreach (var child in root.Root.Elements())
{
    xml.Element(child.Name.ToString()).Add(child.Nodes());
}

编辑 - 进一步概括

您可以使用 2 XElement s 的 Merge 扩展名概括上述代码,使其如下所示

foreach (var child in root.Elements())
{
    xml.Element(child.Name.ToString()).Merge(child, xNamespace + "ExternalId");
}

定义了扩展名

public static void Merge(this XElement root1, XElement root2, XName element_id)
{
    root1.Add(root2.Elements().Except(root1.Elements(), new MyComparer(element_id)));
}

使用 XML 比较器

public class MyComparer : IEqualityComparer<XElement>
{
    private XName _element_id;
    public MyComparer(XName element_id)
    {
        _element_id = element_id;
    }
    public bool Equals(XElement x, XElement y)
    {
        return x.Element(_element_id).Value.Equals(y.Element(_element_id).Value);
    }
    public int GetHashCode(XElement el)
    {
        return el.Element(_element_id).Value.GetHashCode();
    }
}

选择要添加的正确节点和要添加的正确节点。

var filePath = @"D:'testXML'test.xml";
XElement xml = XElement.Load(filePath);
var xmlCategories = xml.Descendants("Categories").First();
var rootCategories = root.Descendants("Category");
xmlCategories.Add(rootCategories);
var xmlProducts = xml.Descendants("Products").First();
var rootProducts = root.Descendants("Product");
xmlProducts.Add(rootProducts);
xml.Save(filePath);

清楚你在做什么。

试试这个

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication2
{
    class Program
    {
        const string FILENAME1 = @"c:'temp'test1.xml";
        const string FILENAME2 = @"c:'temp'test2.xml";
        static void Main(string[] args)
        {
            XDocument doc1 = XDocument.Load(FILENAME1);
            XDocument doc2 = XDocument.Load(FILENAME2);
            XElement category1 = doc1.Descendants().Where(x => x.Name.LocalName == "Categories").FirstOrDefault();
            XElement category2 = doc2.Descendants().Where(x => x.Name.LocalName == "Categories").FirstOrDefault();
            category1.Add(category2.Descendants());

            XElement product1 = doc1.Descendants().Where(x => x.Name.LocalName == "Products").FirstOrDefault();
            XElement product2 = doc2.Descendants().Where(x => x.Name.LocalName == "Products").FirstOrDefault();
            product1.Add(product2.Descendants());
        }
    }

}

试试这个,对不起VB

    'second is The second XML has the same structure with different products
    Dim combined As XElement = New XElement(test) 'create copy of test.xml
    combined.<Categories>.LastOrDefault.Add(second.<Categories>.Elements)
    combined.<Products>.LastOrDefault.Add(second.<Products>.Elements)

    'if test can be used to combine then
    test.<Categories>.LastOrDefault.Add(second.<Categories>.Elements)
    test.<Products>.LastOrDefault.Add(second.<Products>.Elements)

结果是

<Feed name="Choice" incremental="true" extractDate="2016-07-12T15:24:44.5732750+10:00" xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6">
  <Categories>
    <Category>
      <ExternalId>{09B3B4FB-F5CF-4522-BE96-4C4B535580C3}</ExternalId>
      <Name>Cereal and muesli</Name>
    </Category>
    <Category>
      <ExternalId>{12}</ExternalId>
      <Name>cat1</Name>
    </Category>
  </Categories>
  <Products>
    <Product>
      <ExternalId>coles-almond-hazelnut-macadamia-cluster-fusions</ExternalId>
      <Name>Coles Almond, Hazelnut &amp; Macadamia Cluster Fusions</Name>
      <ImageUrl></ImageUrl>
    </Product>
    <Product>
      <ExternalId>Id</ExternalId>
      <Name>Ccoles</Name>
      <ImageUrl></ImageUrl>
    </Product>
  </Products>
</Feed>

我使用的测试数据是

    Dim test As XElement =
        <Feed xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6" name="Choice" incremental="true" extractDate="2016-07-12T15:24:44.5732750+10:00">
            <Categories>
                <Category>
                    <ExternalId>{09B3B4FB-F5CF-4522-BE96-4C4B535580C3}</ExternalId>
                    <Name>Cereal and muesli</Name>
                </Category>
            </Categories>
            <Products>
                <Product>
                    <ExternalId>coles-almond-hazelnut-macadamia-cluster-fusions</ExternalId>
                    <Name>Coles Almond, Hazelnut &amp; Macadamia Cluster Fusions</Name>
                    <ImageUrl></ImageUrl>
                </Product>
            </Products>
        </Feed>
    Dim second As XElement =
        <Feed xmlns="http://www.bazaarvoice.com/xs/PRR/ProductFeed/5.6" name="Choice" incremental="true" extractDate="2016-07-12T15:24:44.5732750+10:00">
            <Categories>
                <Category>
                    <ExternalId>{12}</ExternalId>
                    <Name>cat1</Name>
                </Category>
            </Categories>
            <Products>
                <Product>
                    <ExternalId>Id</ExternalId>
                    <Name>Ccoles</Name>
                    <ImageUrl></ImageUrl>
                </Product>
            </Products>
        </Feed>

XElements可以像这样加载

    test = XElement.Load("PATH")
    second = XElement.Load("second PATH")

并像这样保存

    test.Save("PATH")
    second.Save("second PATH")
    combined.Save("combined PATH")