Come rimuovere gli attributi duplicati da XML con C #

c# html-agility-pack validation xml

Domanda

Sto analizzando alcuni file XML da un fornitore di terze parti e sfortunatamente non è sempre un XML ben formato poiché a volte alcuni elementi contengono attributi duplicati.

Non ho il controllo sulla fonte e non so quali elementi possono avere attributi duplicati né conosco i nomi degli attributi duplicati in anticipo.

Ovviamente, il caricamento del contenuto in un oggetto XMLDocument genera una XmlException sugli attributi duplicati, quindi, sebbene io possa utilizzare un XmlReader per passare attraverso l'elemento XML per elemento e gestire gli attributi duplicati quando arrivo all'elemento offendente.

Tuttavia, l' XmlException viene sollevata su reader.Read() - prima che abbia la possibilità di insepct gli attributi dell'elemento.

Ecco un metodo di esempio per dimostrare il problema:

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

C'è un altro modo per analizzare l'input e rimuovere gli attributi duplicati senza dover utilizzare le espressioni regolari e la manipolazione delle stringhe?

Risposta accettata

Ho trovato una soluzione pensando all'XML come documento HTML. Quindi, utilizzando la libreria Html Agility Pack open source, sono riuscito a ottenere XML valido.

Il trucco era di salvare prima l'xml con un'intestazione HTML.
Quindi sostituisci la dichiarazione XML
<?xml version="1.0" encoding="utf-8" ?>
con una dichiarazione HTML come questa:
!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Una volta che i contenuti sono stati salvati su file, questo metodo restituirà un documento XML valido.

// 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;
}

I nodi dell'attributo duplicati vengono automaticamente rimossi con i valori degli attributi successivi che sovrascrivono quelli precedenti.


Risposta popolare

Ok, pensa di aver bisogno di cogliere l'errore:

Quindi dovresti essere in grado di utilizzare i seguenti metodi:

reader.MoveToFirstAttribute();

e

reader.MoveToFirstAttribute();

per ottenere le seguenti proprietà:

reader.MoveToFirstAttribute();

Questo ti consentirà di ottenere tutti i valori degli attributi.




Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché