帮助合并 XML 数据

发布于 2024-08-07 04:35:43 字数 1129 浏览 4 评论 0原文

我有两个 XMLDocument,其中包含一些相似的信息,但还有其他节点包含两者之间的不同信息。

我正在使用 XMLSerialization 将数据放入如图所示的结构 此处

我知道您可以使用数据集合并 XML 文件,如下所示 here 但我想以某种方式将我看到的第一个文档序列化到我的类中,然后将第二个文档附加到我的类结构中。

有什么想法如何做到这一点或者有更好的方法吗?在信息相似的第二个文档上,我很乐意用第二个文档数据覆盖它,例如每个文档都有一个日期,因此我的日期属性可以是第二个文档的日期属性。

这是数据

<ROOT>
<ID>2</ID>
<PART>4a</PART>
<NAME>JEFF</NAME>
<ADDRESS>
    <ST>10001</ST>
    <ID>123456789</ID>
</ADDRESS>
<PARTNUMBER>001</PARTNUMBER>
<DATE>2009 -06-05T16.18.05</DATE>
</ROOT>


<ROOT>
<ID>2</ID>
<PART>4b</PART>
<NAME>JEFF</NAME>
<RELATIVE>
    <ST>10001</ST>
    <ID>1234567890QWERTYUIOP</ID>
</RELATIVE>
<PARTNUMBER>002</PARTNUMBER>
<DATE>2009 -06-05T16.17.41</DATE>
</ROOT>

I have two XMLDocuments that contain some similar information but there are other nodes that contain different information between the two.

I am using XMLSerialization to put my data into a structure as shown here

I know you can merge XML files by using a DataSet as shown here but I want to somehow serialize the first document I see into my class and then append the second document to my class structure.

Any ideas how to do that or is there a better approach? On the second document where the information is similar I am happy to overwrite it with the second document data for example each document has a DATE so my Date property can be that of the second document.

Here is the data

<ROOT>
<ID>2</ID>
<PART>4a</PART>
<NAME>JEFF</NAME>
<ADDRESS>
    <ST>10001</ST>
    <ID>123456789</ID>
</ADDRESS>
<PARTNUMBER>001</PARTNUMBER>
<DATE>2009 -06-05T16.18.05</DATE>
</ROOT>


<ROOT>
<ID>2</ID>
<PART>4b</PART>
<NAME>JEFF</NAME>
<RELATIVE>
    <ST>10001</ST>
    <ID>1234567890QWERTYUIOP</ID>
</RELATIVE>
<PARTNUMBER>002</PARTNUMBER>
<DATE>2009 -06-05T16.17.41</DATE>
</ROOT>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

请恋爱 2024-08-14 04:35:43

你可以这样做:

void Main()
{
    string xml1 = @"<ROOT>
    <ID>2</ID>
    <PART>4a</PART>
    <NAME>JEFF</NAME>
    <ADDRESS>
        <ST>10001</ST>
        <ID>123456789</ID>
    </ADDRESS>
    <PARTNUMBER>001</PARTNUMBER>
    <DATE>2009 -06-05T16.18.05</DATE>
    </ROOT>";


    string xml2 = @"<ROOT>
    <ID>2</ID>
    <PART>4b</PART>
    <NAME>JEFF</NAME>
    <RELATIVE>
        <ST>10001</ST>
        <ID>1234567890QWERTYUIOP</ID>
    </RELATIVE>
    <PARTNUMBER>002</PARTNUMBER>
    <DATE>2009 -06-05T16.17.41</DATE>
    </ROOT>";

    var doc1 = XDocument.Parse(xml1);
    var doc2 = XDocument.Parse(xml2);

    XDocument doc = MergeDocuments(doc1, doc2);
    doc.Dump();
}

static XDocument MergeDocuments(XDocument doc1, XDocument doc2)
{
    var root = MergeElements(doc1.Root, doc2.Root);
    return new XDocument(root);
}

static XElement MergeElements(XElement e1, XElement e2)
{
    var attrComparer = new XAttributeEqualityComparer();
    var nameComparer = new XNameComparer();

    var attributes = e2.Attributes().Union(e1.Attributes(), attrComparer).Cast<XNode>();

    var elements1 = e1.Elements().OrderBy(e => e.Name, nameComparer).ToArray();
    var elements2 = e2.Elements().OrderBy(e => e.Name, nameComparer).ToArray();
    var elements = new List<XNode>();
    int i1 = 0, i2 = 0;
    while (i1 < elements1.Length && i2 < elements2.Length)
    {
        XElement e = null;
        int compResult = nameComparer.Compare(elements1[i1].Name, elements2[i2].Name);
        if (compResult < 0)
        {
            e = elements1[i1];
            i1++;
        }
        else if (compResult > 0)
        {
            e = elements2[i2];
            i2++;
        }
        else
        {
            e = MergeElements(elements1[i1], elements2[i2]);
            i1++;
            i2++;
        }
        elements.Add(e);
    }
    while (i1 < elements1.Length)
    {
        elements.Add(elements1[i1]);
        i1++;
    }
    while (i2 < elements2.Length)
    {
        elements.Add(elements2[i2]);
        i2++;
    }

    var nodes = attributes.Concat(elements).ToArray();
    string value = null;
    if (elements.Count == 0)
    {
        if (!string.IsNullOrEmpty(e1.Value))
            value = e1.Value;
        if (!string.IsNullOrEmpty(e2.Value))
            value = e2.Value;
    }
    if (value != null)
        return new XElement(e1.Name, nodes, value);
    else
        return new XElement(e1.Name, nodes);
}

class XNameComparer : IComparer<XName>
{
    public int Compare(XName x, XName y)
    {
        int result = string.Compare(x.Namespace.NamespaceName, y.Namespace.NamespaceName);
        if (result == 0)
            result = string.Compare(x.LocalName, y.LocalName);
        return result;
    }
}

class XAttributeEqualityComparer : IEqualityComparer<XAttribute>
{
    public bool Equals(XAttribute x, XAttribute y)
    {
        return x.Name == y.Name;
    }

    public int GetHashCode(XAttribute x)
    {
        return x.Name.GetHashCode();
    }
}

You can do something like that :

void Main()
{
    string xml1 = @"<ROOT>
    <ID>2</ID>
    <PART>4a</PART>
    <NAME>JEFF</NAME>
    <ADDRESS>
        <ST>10001</ST>
        <ID>123456789</ID>
    </ADDRESS>
    <PARTNUMBER>001</PARTNUMBER>
    <DATE>2009 -06-05T16.18.05</DATE>
    </ROOT>";


    string xml2 = @"<ROOT>
    <ID>2</ID>
    <PART>4b</PART>
    <NAME>JEFF</NAME>
    <RELATIVE>
        <ST>10001</ST>
        <ID>1234567890QWERTYUIOP</ID>
    </RELATIVE>
    <PARTNUMBER>002</PARTNUMBER>
    <DATE>2009 -06-05T16.17.41</DATE>
    </ROOT>";

    var doc1 = XDocument.Parse(xml1);
    var doc2 = XDocument.Parse(xml2);

    XDocument doc = MergeDocuments(doc1, doc2);
    doc.Dump();
}

static XDocument MergeDocuments(XDocument doc1, XDocument doc2)
{
    var root = MergeElements(doc1.Root, doc2.Root);
    return new XDocument(root);
}

static XElement MergeElements(XElement e1, XElement e2)
{
    var attrComparer = new XAttributeEqualityComparer();
    var nameComparer = new XNameComparer();

    var attributes = e2.Attributes().Union(e1.Attributes(), attrComparer).Cast<XNode>();

    var elements1 = e1.Elements().OrderBy(e => e.Name, nameComparer).ToArray();
    var elements2 = e2.Elements().OrderBy(e => e.Name, nameComparer).ToArray();
    var elements = new List<XNode>();
    int i1 = 0, i2 = 0;
    while (i1 < elements1.Length && i2 < elements2.Length)
    {
        XElement e = null;
        int compResult = nameComparer.Compare(elements1[i1].Name, elements2[i2].Name);
        if (compResult < 0)
        {
            e = elements1[i1];
            i1++;
        }
        else if (compResult > 0)
        {
            e = elements2[i2];
            i2++;
        }
        else
        {
            e = MergeElements(elements1[i1], elements2[i2]);
            i1++;
            i2++;
        }
        elements.Add(e);
    }
    while (i1 < elements1.Length)
    {
        elements.Add(elements1[i1]);
        i1++;
    }
    while (i2 < elements2.Length)
    {
        elements.Add(elements2[i2]);
        i2++;
    }

    var nodes = attributes.Concat(elements).ToArray();
    string value = null;
    if (elements.Count == 0)
    {
        if (!string.IsNullOrEmpty(e1.Value))
            value = e1.Value;
        if (!string.IsNullOrEmpty(e2.Value))
            value = e2.Value;
    }
    if (value != null)
        return new XElement(e1.Name, nodes, value);
    else
        return new XElement(e1.Name, nodes);
}

class XNameComparer : IComparer<XName>
{
    public int Compare(XName x, XName y)
    {
        int result = string.Compare(x.Namespace.NamespaceName, y.Namespace.NamespaceName);
        if (result == 0)
            result = string.Compare(x.LocalName, y.LocalName);
        return result;
    }
}

class XAttributeEqualityComparer : IEqualityComparer<XAttribute>
{
    public bool Equals(XAttribute x, XAttribute y)
    {
        return x.Name == y.Name;
    }

    public int GetHashCode(XAttribute x)
    {
        return x.Name.GetHashCode();
    }
}
小清晰的声音 2024-08-14 04:35:43

托马斯的回答真的很棒。然而,尽管它在给定的 XML 上运行得非常好,但我发现它在带有属性的 XML 上遇到了一些问题(尽管代码理论上确实可以处理它)。

然而,尝试从 XAttribute 转换为 XNode 时,这一行会抛出 InvalidCastException:

var nodes = attributes.Concat(elements).ToArray();

尽管如此,我发现以下更改对我有用。而不是

var attributes = e2.Attributes().Union(e1.Attributes(), attrComparer).Cast<XNode>();
...
var nodes = attributes.Concat(elements).ToArray();
...
if (value != null)
    return new XElement(e1.Name, nodes, value);
else
    return new XElement(e1.Name, nodes);

尝试这个:

var attributes = e2.Attributes().Union(e1.Attributes(), attrComparer);
...
// var nodes = attributes.Concat(elements).ToArray();
...
if (value != null)
    return new XElement(e1.Name, attributes, elements, value);
else
    return new XElement(e1.Name, attributes, elements);

似乎对我有用,尽管我不是这些问题的专家。这仅供其他遇到此问题的人参考。

编辑:此外,请注意 doc.Dump() 对我来说不存在,并且在编译时会中断。我正在使用.NET 3.5;也许汤姆的答案取决于不同的版本(3.0?),这也可能解释我收到的错误消息?

Thomas' answer is really great. However although it worked perfectly well on the given XML, I found it had some trouble on XML with attributes (although the code does theoretically deal with it).

However this line would throw an InvalidCastException trying to convert from XAttribute to XNode:

var nodes = attributes.Concat(elements).ToArray();

Nonetheless I found that the following changes worked for me. Instead of

var attributes = e2.Attributes().Union(e1.Attributes(), attrComparer).Cast<XNode>();
...
var nodes = attributes.Concat(elements).ToArray();
...
if (value != null)
    return new XElement(e1.Name, nodes, value);
else
    return new XElement(e1.Name, nodes);

Try this:

var attributes = e2.Attributes().Union(e1.Attributes(), attrComparer);
...
// var nodes = attributes.Concat(elements).ToArray();
...
if (value != null)
    return new XElement(e1.Name, attributes, elements, value);
else
    return new XElement(e1.Name, attributes, elements);

Seems to work for me, though I'm no expert on these matters. This is just an FYI for anyone else who comes across this.

EDIT: In addition, note that doc.Dump() doesn't exist for me and breaks when compiling. I'm using .NET 3.5; perhaps Tom's answer depended on a different version (3.0?), and that might also account for the error messages I got?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文