检查多个XML文件

时间:2019-02-07 16:09:01

标签: c# xml-parsing

我从原始帖子中重新措辞: 我有两个XML文件,它们分别与给定的年份有关。例如18/19和17/18。它们符合相同的结构,下面是这些文件之一的小样本。我想要的是,在C#中,比较这些文件中的所有记录,其中给定名称,姓氏,NI编号和出生日期相同,但学习者编号则不同。我需要能够进行比较,然后仅将这些记录推送到数据表中,以便随后将它们推送到电子表格中(我可以做的电子表格位)。我目前将以下内容作为起点,但仍然非常困难。

首先,我需要按下导入按钮:

        private void Btn_Import_Click(object sender, RoutedEventArgs e)
    {


        ILRChecks.ILRReport.CrossYear();}

然后看一下Class,最终将文件推送到我的位置:

using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ILRValidation;
using InfExcelExtension;

namespace ILRChecks
{
internal static partial class ILRReport
{
    internal static void CrossYear()
    {
        DataSet ds_CrossYearChecks = 
ILRValidation.Validation.CrossYearChecks(Global.fileNames);

        string output = Path.Combine(Global.foldername, "ULIN_Issues" + 
".xlsx");


        ds_CrossYearChecks.ToWorkBook(output);




    }
}
}

这就是我要坚持的一点,它是发现差异的结果:

using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ILRValidation
{
public static partial class Validation
{
    public static DataSet CrossYearChecks(DataSet ds_CrossYearChecks)
    {
        return CrossYearChecks(ds_CrossYearChecks);
    }

    public static DataSet CrossYearChecks(string[] xmlPath)
    {

        DataSet ds_xmlCrossYear = new DataSet();


        return CrossYearChecks(ds_xmlCrossYear);
    }
}
}

XML:

<Learner>
<LearnRefNumber></LearnRefNumber>
<ULN></ULN>
<FamilyName></FamilyName>
<GivenNames></GivenNames>
<DateOfBirth></DateOfBirth>
<Ethnicity></Ethnicity>
<Sex></Sex>
<LLDDHealthProb></LLDDHealthProb>
<NINumber></NINumber>
<PriorAttain></PriorAttain>
<MathGrade></MathGrade>
<EngGrade></EngGrade>
<PostcodePrior></PostcodePrior>
<Postcode></Postcode>
<AddLine1></AddLine1>
<AddLine3></AddLine3>
<Email></Email>

2 个答案:

答案 0 :(得分:1)

好吧,您可以递归地遍历两个XML文件并写下所有遇到的更改。诸如此类的东西应该会有所帮助:

static string AppendPrefix(string oldPrefix, string addition) =>
    oldPrefix == "" ? addition : $"{oldPrefix}.{addition}";

static void CompareElements(string prefix, XElement d1, XElement d2)
{
    // 1. compare names
    var newPrefix = AppendPrefix(prefix, d1.Name.ToString());
    if (d1.Name != d2.Name)
    {
        Console.WriteLine(
            $"Name mismatch: {newPrefix} != {AppendPrefix(prefix, d2.Name.ToString())}");
        return;
    }

    // 2. compare attributes
    var attrs = d1.Attributes().OrderBy(a => a.Name);
    var unpairedAttributes = new HashSet<XAttribute>(d2.Attributes());
    foreach (var attr in attrs)
    {
        var otherAttr = d2.Attributes(attr.Name).SingleOrDefault();
        if (otherAttr == null)
        {
            Console.WriteLine($"No new attr: {newPrefix}/{attr.Name}");
            continue;
        }

        unpairedAttributes.Remove(otherAttr);
        if (attr.Value != otherAttr.Value)
            Console.WriteLine(
                $"Attr value mismatch: {newPrefix}/{attr.Name}: {attr.Value} != {otherAttr.Value}");
    }
    foreach (var attr in unpairedAttributes)
        Console.WriteLine($"No old attr: {newPrefix}/{attr.Name}");

    // 3. compare subelements
    var leftNodes = d1.Nodes().ToList();
    var rightNodes = d2.Nodes().ToList();
    var smallerCount = Math.Min(leftNodes.Count, rightNodes.Count);
    for (int i = 0; i < smallerCount; i++)
        CompareNodes(newPrefix, i, leftNodes[i], rightNodes[i]);
    if (leftNodes.Count > smallerCount)
        Console.WriteLine($"Extra {leftNodes.Count - smallerCount} nodes at old file");
    if (rightNodes.Count > smallerCount)
        Console.WriteLine($"Extra {rightNodes.Count - smallerCount} nodes at new file");
}

static void CompareNodes(string prefix, int index, XNode n1, XNode n2)
{
    if (n1.NodeType != n2.NodeType)
    {
        Console.WriteLine($"Node type mismatch: {prefix}/[{index}]");
        return;
    }

    switch (n1.NodeType)
    {
        case XmlNodeType.Element:
            CompareElements(prefix, (XElement)n1, (XElement)n2);
            break;
        case XmlNodeType.Text:
            CompareText(prefix, index, (XText)n1, (XText)n2);
            break;
    }
}

static void CompareText(string prefix, int index, XText t1, XText t2)
{
    if (t1.Value != t2.Value)
        Console.WriteLine($"Text mismatch at {prefix}[{index}]");
}

用法:

XDocument d1 = <get document #1 from somewhere>,
          d2 = <get document #2 from somewhere>;

CompareNodes("", 0, d1.Root, d2.Root);

很明显,您不必写到控制台,而应该写到适当的电子表格。

请注意,我忽略的是属性重新排序,而不是子节点重新排序(这似乎是正确的)。

答案 1 :(得分:0)

在我看来,您在从xml提取所需的值时遇到问题,对吗?

正如其他人在评论中提到的那样,在不知道xml布局的情况下,不可能为您的案例提供具体的示例。如果您编辑问题以包含xml示例,我们将为您提供更多帮助。

以下是一些有关如何从xml中提取值的常规示例:

private static bool CheckXmlDocument(string xmlPathCheck)
{
    // if you have multiple files from which you need to extract values, pass in an array or List<string> and loop over it, fetching the values

    // XmlDocument will allow you to edit the document as well as read it
    // there's another option to use XPathDocument and XPathNavigator but it's read-only
    var doc = new XmlDocument();

    // this can throw various exceptions so might want to add some handling
    doc.Load(xmlPathCheck);

    // getting the elements, you have some options depending on the layout of the document
    // if the nodes you want are identified by 'id' use this:
    var nameElement = doc.GetElementById("name");

    // if the nodes you want are identified by 'tag', use this:
    var nameNodeList = doc.GetElementsByTagName("name");

    // if you know the xpath to the specific node you want, use this:
    var selectNameNode = doc.SelectSingleNode("the/xpath/to/the/node");

    // if there are several nodes that have the same xpaths, use this:
    var selectNameList = doc.SelectNodes("the/xpath/that/may/match/many/nodes");

    // getting the value depends on the if you have an XmlNode, XmlElement or XmlNodeList
    // if you have a single XmlElement or XmlNode you can get the value one of these ways depending on the layout of your document:
    var name = nameElement.InnerText;
    name = nameElement.InnerXml;

    // if you have an XmlNodeList, you'll have to iterate through the nodes to find the one you want, like this:
    foreach (var node in nameNodeList)
    {
        // here use some condition that will determine if its the element/node you want or not (depends on your xml layout)
        if (node is XmlNode n)
        {
            name = n.InnerText;
        }
    }

    // do that for all the values you want to compare, then compare them
    return CheckValues(/*the values to compare*/);
}

XmlDocument

XmlNode

XmlElement