【问题标题】:Merging of xml documentsxml文档的合并
【发布时间】:2011-10-11 13:37:55
【问题描述】:

我遇到的所有关于合并 XML 文档的解决方案都没有达到我想要的效果。让我解释一下:

XML 文档 1:

<?xml version="1.0" encoding="utf-8" ?>
<a>
    <b title="Original Section">
        <b title="Original Child Section"></b>
        <b title="Original Child Section 2"></b>
    </b>
</a>

XML 文档 2:

<?xml version="1.0" encoding="utf-8" ?>
<a>
    <b title="New Section">
        <b title="New Child Section"></b>
    </b>
    <b title="Original Section">
        <b title="Original Child Section">
            <b title="New Child For Old Section"></b>
        </b>
    </b>    
</a>

像这样进入最终文档:

<?xml version="1.0" encoding="utf-8" ?>
<a>
    <b title="Original Section">
        <b title="Original Child Section">
            <b title="New Child For Old Section"></b>
        </b>
        <b title="Original Child Section 2"></b>
    </b>    
    <b title="New Section">
        <b title="New Child Section"></b>
    </b>
</a>

文档内容相似,但可以有任意数量的子节点。我也想消除重复。我认为重复元素是具有相同属性的元素(基于属性名称和值)。有没有人看过这个实现的工作示例?我可以设想如何使用一些循环和一些递归来编写它,但对我来说,这似乎不是实现我想要的最佳方式:)

提前干杯和感谢!

* 编辑 *

既然共识是循环和递归是必须的,那么实现这一点的最优雅和最有效的方法是什么?我想这个问题的另一个基本问题是在迭代时比较节点的最佳方法是什么?

【问题讨论】:

  • 我为客户实现了类似的东西。它的工作方式基本上与您实现它的方式相同:使用循环和递归。
  • 我同意@DanielHilgarth。循环和递归基本上是完成此任务的最简单方法。
  • 好问题。标题在其直接上下文中总是唯一的吗?
  • 以上是我想要完成的大量简化视图,但在我的实际实现中,每个元素都有独特的元素。

标签: c# xml linq recursion linq-to-xml


【解决方案1】:

最终,这个问题的任何解决方案都将归结为循环和/或递归。你说的是基本的集合论,linq 可能对提炼过程很有用,但它最终会迭代两个集合并合并结果。

【讨论】:

  • 我就是这么想的。那么我想我应该修改我的问题以寻求最优雅和最有效的解决方案。
【解决方案2】:

我会写一个IEqualityComparer 来指定两个节点何时“匹配” - 即设置标题匹配规则。

class XElementComparer : IEqualityComparer<XElement>
{
    public bool Equals(XElement x, XElement y)
    {
        var xTitle = x.Attribute("title");
        var yTitle = y.Attribute("title");

        if (xTitle == null || yTitle == null) return false;

        return xTitle.Value == yTitle.Value;
    }

    public int GetHashCode(XElement obj)
    {
        return base.GetHashCode();
    }
}

然后编写一个递归方法来遍历您的 XML,合并根据比较器匹配的节点。

private XElement Merge(XElement node1, XElement node2)
{
    // trivial cases
    if (node1 == null) return node2;
    if (node2 == null) return node1;

    var elements1 = node1.Elements();
    var elements2 = node2.Elements();

    // create a merged root
    var result = new XElement(node1.Name, node1.Attribute("title")); 

    var comparer = new XElementComparer();
    var mergedNodes = elements1.Union(elements2, comparer).ToList();

    // for the union of the elements, insert their merge values
    foreach (var title in mergedNodes)
    {
        var child1 = elements1.SingleOrDefault(e => comparer.Equals(e, title));
        var child2 = elements2.SingleOrDefault(e => comparer.Equals(e, title));

        result.Add(Merge(child1, child2));
    }

    return result;
}

【讨论】:

  • 我知道变量名有点笨拙,我应该正确实现GetHashCode,但基础知识就在那里。
  • 这看起来很有希望。这正是我处理这个问题的方式,但更聪明:) 让我搞砸它,看看我能想出什么
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多