删除 XML 中的重复元素
本文关键字:元素 XML 删除 | 更新日期: 2023-09-27 18:33:22
我的项目需要将输入XML文件转换为DataTable的功能。我使用以下代码来执行此操作。
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
dataSourceFileStream.Seek(0, SeekOrigin.Begin);
ds.ReadXml(dataSourceFileStream);
dt = ds.Tables[0];
除非输入XML具有重复的元素,否则这将安静地工作,例如,如果XML文件如下所示:
<?xml version="1.0" encoding="iso-8859-1"?>
<DocumentElement>
<data>
<DATE>27 September 2013</DATE>
<SCHEME>Test Scheme Name</SCHEME>
<NAME>Mr John</NAME>
<SCHEME>Test Scheme Name</SCHEME>
<TYPE>1</TYPE>
</data>
</DocumentElement>
正如你在上面看到的,元素 SCHEME 出现了两次。 当这种XML文件出现时ds.ReadXml(dataSourceFileStream);
无法返回正确的数据表。
有什么更好的方法来解决这个问题吗?
看起来您必须先修复 XML。您可以使用 XDocument 和关联的类来执行此操作。但首先你需要创建一个 EqualComparer,它根据名称比较两个 XElements:
public class MyEqualityComparer : IEqualityComparer<XElement>
{
public bool Equals(XElement x, XElement y)
{
return x.Name == y.Name;
}
public int GetHashCode(XElement obj)
{
return obj.Name.GetHashCode();
}
}
现在试试这个:
var comparer = new MyEqualityComparer();
XDocument.Load(dataSourceFileStream);
var doc = XDocument.Parse(data);
var dataElements = doc.Element("DocumentElement").Elements("data");
foreach (var dataElement in dataElements)
{
var childElements = dataElement.Elements();
var distinctElements = childElements.Distinct(comparer).ToArray();
if (distinctElements.Length != childElements.Count())
{
dataElement.Elements().Remove();
foreach (var item in distinctElements)
dataElement.Add(item);
}
}
using (var stream = new MemoryStream())
{
var writer = new StreamWriter(stream);
doc.Save(writer);
stream.Seek(0, 0);
var ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
var mode = ds.ReadXml(stream);
var dt = ds.Tables[0];
}
这将是您问题的快速解决方法。但我强烈建议鼓励数据提供者修复 XML
好的。
如我之前的评论中所述,您可以创建自己的XmlTextReader来修补/忽略某些元素。这个想法是,这个读者检查他是否已经阅读了相同深度的元素。如果是这种情况,请前进到结束元素。
class MyXmlReaderPatcher : XmlTextReader
{
private readonly HashSet<string> _currentNodeElementNames = new HashSet<string>();
public MyXmlReaderPatcher(TextReader reader) : base(reader)
{ }
public override bool Read()
{
var result = base.Read();
if (this.Depth == 1)
{
_currentNodeElementNames.Clear();
}
else if (this.Depth==2 && this.NodeType == XmlNodeType.Element)
{
if (_currentNodeElementNames.Contains(this.Name))
{
var name = this.Name;
do {
result = base.Read();
if (result == false)
return false;
} while (this.NodeType != XmlNodeType.EndElement && this.Name != name);
result = this.Read();
}
else
{
_currentNodeElementNames.Add(this.Name);
}
}
return result;
}
}
您所要做的就是在您的 ds 之间链接新阅读器。ReadXml() 和您的文件流:
var myReader = new MyXmlReaderPatcher(dataSourceFileStream);
var ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
var mode = ds.ReadXml(myReader);
var dt = ds.Tables[0];