如何使用C#从XML中删除重复的属性

Cat*_*h22 6 c# xml validation html-agility-pack

我正在从第三方提供程序解析一些XML文件,不幸的是,它并不总是格式良好的XML,因为有时某些元素包含重复的属性.

我无法控制源,我不知道哪些元素可能有重复的属性,也不知道重复的属性名称.

显然,将内容加载到XMLDocument对象中会在重复属性上引发XmlException,因此我可以使用a XmlReader逐个元素地逐步执行XML元素,并在到达有问题的元素时处理重复的属性.

然而,在我有机会对元素的属性进行插入之前,它XmlException被提升了reader.Read().

以下是演示此问题的示例方法:

public static void ParseTest()
{
    const string xmlString = 
        @"<?xml version='1.0'?>
        <!-- This is a sample XML document -->
        <Items dupattr=""10"" id=""20"" dupattr=""33"">
            <Item>test with a child element <more/> stuff</Item>
        </Items>";

    var output = new StringBuilder();
    using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
    {
        XmlWriterSettings ws = new XmlWriterSettings();
        ws.Indent = true;
        using (XmlWriter writer = XmlWriter.Create(output, ws))
        {
            while (reader.Read())   /* Exception throw here when Items element encountered */
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.Element:
                        writer.WriteStartElement(reader.Name);
                        if (reader.HasAttributes){ /* CopyNonDuplicateAttributes(); */}
                        break;
                    case XmlNodeType.Text:
                        writer.WriteString(reader.Value);
                        break;
                    case XmlNodeType.XmlDeclaration:
                    case XmlNodeType.ProcessingInstruction:
                        writer.WriteProcessingInstruction(reader.Name, reader.Value);
                        break;
                    case XmlNodeType.Comment:
                        writer.WriteComment(reader.Value);
                        break;
                    case XmlNodeType.EndElement:
                        writer.WriteFullEndElement();
                        break;
                }
            }

        }
    }
    string str = output.ToString();
}
Run Code Online (Sandbox Code Playgroud)

有没有其他方法来解析输入并删除重复的属性,而不必使用正则表达式和字符串操作?

Cat*_*h22 4

我通过将 XML 视为 HTML 文档找到了解决方案。然后使用开源Html Agility Pack库,我能够获得有效的 XML。

诀窍是首先使用 HTML 标头保存 xml。
因此,将 XML 声明替换
<?xml version="1.0" encoding="utf-8" ?>
为 HTML 声明,如下所示:
!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

将内容保存到文件后,此方法将返回有效的 XML 文档。

// Requires reference to HtmlAgilityPack
public XmlDocument LoadHtmlAsXml(string url)
{
    var web = new HtmlWeb();

    var m = new MemoryStream();
    var xtw = new XmlTextWriter(m, null);

    // Load the content into the writer
    web.LoadHtmlAsXml(url, xtw);

    // Rewind the memory stream
    m.Position = 0;

    // Create, fill, and return the xml document
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml((new StreamReader(m)).ReadToEnd());
    return xmlDoc;
}
Run Code Online (Sandbox Code Playgroud)

重复的属性节点会自动删除,后面的属性值会覆盖前面的属性值。