【问题标题】:How to merge xml streams如何合并xml流
【发布时间】:2015-06-25 18:51:43
【问题描述】:

我有多个这种格式的 xml 流:

xml1:

<?xml version="1.0" encoding="utf-8"?>
<Node>
      <NodeA>test1</NodeA>
      <NodeB>test2</NodeB>
      <NodeC>
         <Att>test4</Att>
         <Value1>1.0</Value1>
      </NodeC>
</Node>
<Node>
      <NodeA>test1</NodeA>
      <NodeB>test7</NodeB>
      <NodeC>
         <Att>test8</Att>
         <Value1>2.0</Value1>
      </NodeC>
</Node>
...

xmlN:

<?xml version="1.0" encoding="utf-8"?>
<Node>
      <NodeA>test1</NodeA>
      <NodeB>test2</NodeB>
      <NodeC>
         <Att>test4</Att>
         <ValueN>5.0</ValueN>
      </NodeC>
</Node>
<Node>
      <NodeA>test1</NodeA>
      <NodeB>test7</NodeB>
      <NodeC>
         <Att>test8</Att>
         <ValueN>6.0</ValueN>
      </NodeC>
</Node>
<Node>
      <NodeA>test9</NodeA>
      <NodeB>test8</NodeB>
      <NodeC>
         <Att>test8</Att>
         <ValueN>6.0</ValueN>
      </NodeC>
</Node>

我希望合并后的 xml 看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<Node>
      <NodeA>test1</NodeA>
      <NodeB>test2</NodeB>
      <NodeNEW>test4</Att>
      <Value1>1.0</Value1>
      <ValueN>5.0</ValueN>
</Node>
<Node>
      <NodeA>test1</NodeA>
      <NodeB>test7</NodeB>
      <NodeNEW>test8</NodeNEW>
      <Value1>2.0</Value1>
      <ValueN>6.0</ValueN>
</Node>
<Node>
      <NodeA>test9</NodeA>
      <NodeB>test8</NodeB>
      <NodeNEW>test8</NodeNew>
      <Value1></Value1>
      <ValueN>6.0</ValueN>

</Node>

所以我创建了具有不同 Value1 的唯一键 NodeA>NodeB>NodeNEW,如果此唯一键未出现在其各自的 xml 中,则不会分配任何内容。

最有效的方法是什么?

【问题讨论】:

  • 反序列化、合并、序列化。
  • 您是否尝试过创建相应的模型,然后使用xmlElement 等xml 属性标记属性,然后加载您的模型。然后以编程方式将它们合并到第三个模型中,然后使用 xml 序列化器序列化到新的 xml 中。请参阅此处的代码msdn.microsoft.com/en-us/library/…

标签: c# xml


【解决方案1】:

下面的代码应该会给你想要的结果,如果它没有发布,它不会显示以前节点的值,但你可以玩弄它并让它工作。这里的想法是使用 XMLReader 读取项目并在同一迭代中更新现有节点。

    static void Main(string[] args) {

  //Ideally you should have well formed xml with root element as eg given below
  //but since it is stream it is possible but not sure how much control you have on it.
  //eg: <Nodes><Node1/><Node2/>...</Nodes> 

  //Reading your data from locally stored stream files
  var streamFiles=new[] { @"C:\temp\stack\xml1.xml", @"C:\temp\stack\xmlN.xml" };

  var dict = new Dictionary<int,XElement>();

  foreach(var streamFile in streamFiles) {
    using(var reader=XmlReader.Create(streamFile, new XmlReaderSettings { ConformanceLevel=ConformanceLevel.Fragment })) {
      var nodeNo=0;
      while(reader.MoveToContent()==XmlNodeType.Element) {
        var element=XNode.ReadFrom(reader) as XElement;
        //Now merge the data. Yahoo
        XElement currentElement;
        if(!dict.TryGetValue(nodeNo, out currentElement)) {
          currentElement = new XElement("Node");
          dict.Add(nodeNo, currentElement);
        }

        foreach(var el in element.Elements().Where(e => !e.HasElements)) {
          currentElement.SetElementValue(el.Name, el.Value);
        }

        currentElement.SetElementValue("NodeNEW",
          element.Elements().Where(e => e.HasElements)
            .SelectMany(e => e.Elements()
              .Where(w => w.Name=="Att"))
            .FirstOrDefault().Value);

        currentElement.Add(element.Elements().Where(e => e.HasElements)
          .SelectMany(e => e.Elements()
            .Where(w => w.Name!="Att")));

        nodeNo++;
      }
    }
  }

  using(var writer=XmlWriter.Create(@"C:\temp\stack\xmlMerged.xml",
    new XmlWriterSettings {
      ConformanceLevel=ConformanceLevel.Fragment,
      Indent=true
    })) {
    foreach(var element in dict.Values) {
      element.WriteTo(writer);
    }
  }
}

【讨论】:

  • 感谢您指出。我养成了使用下划线的习惯,但是在您发表评论后,它的用法现在很清楚了。也更新了代码。
  • “不发布就不会显示之前节点的值”是什么意思?查看您的实现,它是如何在 Value1 之后添加 ValueN 作为额外条目的?
  • 我不明白它如何检查现有的“NodeA>NodeB>NodeNEW”组合是否已经存在。您似乎只使用数字作为字典中的键。
  • 1.在最后一个合并节点的示例中,不会生成空的 Value1 标记。为了解决这个问题,所有以前的序列号都将被迭代。
猜你喜欢
  • 2013-08-31
  • 1970-01-01
  • 1970-01-01
  • 2011-08-28
  • 1970-01-01
  • 2023-01-22
  • 2018-05-24
  • 2021-04-27
  • 1970-01-01
相关资源
最近更新 更多