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

时间:2011-07-07 11:14:21

标签: c# xml validation html-agility-pack

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

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

显然,将内容加载到XMLDocument对象会对重复属性引发XmlException,因此我可以使用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();
}

是否有其他方法可以解析输入并删除重复的属性而无需使用正则表达式和字符串操作?

2 个答案:

答案 0 :(得分:3)

我通过将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;
}

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

答案 1 :(得分:0)

好的,你认为你需要抓住错误:

然后你应该可以使用以下方法:

reader.MoveToFirstAttribute();

reader.MoveToNextAttribute()

获取以下属性:

reader.Value
reader.Name

这将使您能够获取所有属性值。