删除 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 中的重复元素

看起来您必须先修复 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];
相关文章: