c#合并两个给出错误的XML

时间:2016-07-12 06:01:38

标签: c# .net xml c#-4.0 xml-parsing

我正在尝试将具有相同结构但不同数据的两个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);

任何人都可以告诉我我做错了什么。

这是test.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>

4 个答案:

答案 0 :(得分:1)

选择要添加的正确节点并更正要添加的节点。

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);

要清楚你正在做什么。

答案 1 :(得分:1)

xml文档必须只有一个根

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

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

编辑 - 进一步概括

您可以使用Merge扩展名2 XElement对上述代码进行概括,使其内容如下所示

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();
    }
}

答案 2 :(得分:1)

Try this

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());
        }
    }


}

答案 3 :(得分:1)

试试这个,抱歉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")