如何使用C#從XML中刪除重複的屬性

c# html-agility-pack validation xml

我正在從第三方提供程序解析一些XML文件,不幸的是,它並不總是格式良好的XML,因為有時某些元素包含重複的屬性。

我無法控制源,我不知道哪些元素可能有重複的屬性,也不知道重複的屬性名稱。

顯然,將內容加載到XMLDocument對象會在重複屬性上引發XmlException,因此我可以使用XmlReader逐個元素地逐步執行XML元素,並在到達有問題的元素時處理重複的屬性。

但是,在我有機會對元素的屬性進行插入之前,會在reader.Read()reader.Read() XmlException

以下是演示此問題的示例方法:

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();
}

有沒有其他方法來解析輸入並刪除重複的屬性,而不必使用正則表達式和字符串操作?

一般承認的答案

我通過將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;
}

自動刪除重複屬性節點,後面的屬性值覆蓋先前的屬性值。


熱門答案

好吧,你認為你需要抓住錯誤:

然後你應該能夠使用以下方法:

reader.MoveToFirstAttribute();

reader.MoveToFirstAttribute();

獲取以下屬性:

reader.MoveToFirstAttribute();

這將使您能夠獲取所有屬性值。




許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因