C# 检查多个XML文件
我从我原来的帖子中重新措辞: 我有两个XML文件,它们分别与给定的年份相关。例如,18/19和17/18。它们符合相同的结构,下面是其中一个文件的小样本。我想要的是,在C#中,比较这些文件中的所有记录,其中的名字、姓氏、NI编号和出生日期相同,但学习者参考编号不同。我需要能够比较,然后只将这些记录推送到数据表中,这样我就可以将它们推送到电子表格中(我可以做的电子表格位)。我目前有以下作为起点,但仍然非常卡住 首先,我按下了导入按钮,用于:C# 检查多个XML文件,c#,xml-parsing,C#,Xml Parsing,我从我原来的帖子中重新措辞: 我有两个XML文件,它们分别与给定的年份相关。例如,18/19和17/18。它们符合相同的结构,下面是其中一个文件的小样本。我想要的是,在C#中,比较这些文件中的所有记录,其中的名字、姓氏、NI编号和出生日期相同,但学习者参考编号不同。我需要能够比较,然后只将这些记录推送到数据表中,这样我就可以将它们推送到电子表格中(我可以做的电子表格位)。我目前有以下作为起点,但仍然非常卡住 首先,我按下了导入按钮,用于: private void Btn_Imp
private void Btn_Import_Click(object sender, RoutedEventArgs e)
{
ILRChecks.ILRReport.CrossYear();}
然后看一看最终将文件推送到我的位置的类:
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:
嗯,您可以递归地遍历这两个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}]");
}
静态字符串AppendPrefix(字符串oldPrefix,字符串添加)=>
oldPrefix==“”?添加:$“{oldPrefix}.{addition}”;
静态空比较器元素(字符串前缀、XElement d1、XElement d2)
{
//1.比较名称
var newPrefix=AppendPrefix(前缀,d1.Name.ToString());
如果(d1.Name!=d2.Name)
{
控制台写入线(
$“名称不匹配:{newPrefix}!={AppendPrefix(prefix,d2.Name.ToString())}”);
返回;
}
//2.比较属性
var attrs=d1.Attributes().OrderBy(a=>a.Name);
var unpairedAttributes=新哈希集(d2.Attributes());
foreach(属性中的var attr)
{
var otherAttr=d2.Attributes(attr.Name).SingleOrDefault();
if(otherAttr==null)
{
WriteLine($“无新属性:{newPrefix}/{attr.Name}”);
继续;
}
未配对属性。删除(其他属性);
如果(属性值!=其他属性值)
控制台写入线(
$“属性值不匹配:{newPrefix}/{Attr.Name}:{Attr.value}!={otherAttr.value}”);
}
foreach(未配对属性中的var attr)
WriteLine($“无旧属性:{newPrefix}/{attr.Name}”);
//3.比较子元素
var leftNodes=d1.Nodes().ToList();
var rightNodes=d2.Nodes().ToList();
var smallerCount=Math.Min(leftNodes.Count,righnodes.Count);
对于(int i=0;ismallerCount)
WriteLine($“旧文件中的额外{leftNodes.Count-smallerCount}节点”);
if(rightNodes.Count>smallerCount)
WriteLine($“新文件中的额外{rightNodes.Count-smallerCount}节点”);
}
静态void比较节点(字符串前缀、int索引、XNode n1、XNode n2)
{
if(n1.NodeType!=n2.NodeType)
{
WriteLine($“节点类型不匹配:{prefix}/[{index}]”);
返回;
}
开关(n1.节点类型)
{
case XmlNodeType.Element:
比较元素(前缀,(XElement)n1,(XElement)n2);
打破
案例XmlNodeType.Text:
CompareText(前缀,索引,(XText)n1,(XText)n2);
打破
}
}
静态void CompareText(字符串前缀、int索引、XText t1、XText t2)
{
如果(t1.Value!=t2.Value)
WriteLine($“在{prefix}[{index}]处的文本不匹配”);
}
用法:
XDocument d1 = <get document #1 from somewhere>,
d2 = <get document #2 from somewhere>;
CompareNodes("", 0, d1.Root, d2.Root);
XDocument d1=,
d2=;
比较节点(“”,0,d1.根,d2.根);
显然,您不应该写入控制台,而应该写入相应的电子表格
请注意,我忽略了属性重新排序,而不是子节点重新排序(这似乎是正确的)。在我看来,从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*/);
}
private static bool CheckXmlDocument(字符串xmlPathCheck)
{
//如果需要从多个文件中提取值,请传入一个数组或列表并在其上循环,获取值
//XmlDocument将允许您编辑和阅读文档
//还有另一个选项可以使用XPathDocument和XPathNavigator,但它是只读的
var doc=新的XmlDocument();
//这可能引发各种异常,因此可能需要添加一些处理
文档加载(xmlPathCheck);
//获取元素时,根据文档的布局,您有一些选项
//如果所需节点由“id”标识,请使用以下选项:
var namelement=doc.GetElementById(“名称”);
//如果所需节点由“标记”标识,请使用以下命令:
var nameNodeList=doc.GetElementsByTagName(“名称”);
//如果知道所需特定节点的xpath,请使用以下命令:
var selectNameNode=doc.SelectSingleNode(“the/xpath/to/the/node”);
//如果有多个节点具有相同的XPath,请使用以下命令:
var selectNameList=doc.SelectNodes(“the/xpath/that/may/match/many/nodes”);
//获取该值取决于是否有XmlNode、XmlElement或XmlNodeList
//如果只有一个XmlElement或XmlNode,则可以通过以下方式之一获取值,具体取决于文档的布局:
var name=namelement.InnerText;
name=namelement.InnerXml;
//如果您有一个XmlNodeList,则必须遍历节点以找到所需的节点,如下所示:
foreach(nameNodeList中的变量节点)
{
//这里使用一些条件来确定它是否是您想要的元素/节点(取决于您的xml布局)
if(节点为XmlNode)
{
name=n.InnerText;
}
}
//对所有值都这样做
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*/);
}