So entfernen Sie doppelte Attribute aus XML mit C #

c# html-agility-pack validation xml

Frage

Ich analysiere einige XML-Dateien von einem Drittanbieter und leider ist es nicht immer wohlgeformtes XML, da manchmal einige Elemente doppelte Attribute enthalten.

Ich habe keine Kontrolle über die Quelle und ich weiß nicht, welche Elemente doppelte Attribute haben, noch kenne ich die doppelten Attributnamen im Voraus.

Offensichtlich löst das Laden des Inhalts in ein XMLDocument Objekt eine XmlException für die doppelten Attribute aus, so dass ich einen XmlReader , um das XML-Element XmlReader und mit den doppelten Attributen XmlReader zu werden, wenn ich zu dem fehlerhaften Element komme.

Die XmlException wird jedoch in reader.Read() bevor ich die Attribute des Elements erkennen kann.

Hier ist eine Beispielmethode, um das Problem zu demonstrieren:

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

Gibt es eine andere Möglichkeit, die Eingabe zu analysieren und die doppelten Attribute zu entfernen, ohne reguläre Ausdrücke und Zeichenfolgenmanipulation zu verwenden?

Akzeptierte Antwort

Ich fand eine Lösung, indem ich XML als HTML-Dokument betrachtete. Dann konnte ich mithilfe der Open-Source- HTML-Agility-Pack- Bibliothek gültige XML- Dateien abrufen .

Der Trick bestand darin, das XML zuerst mit einem HTML-Header zu speichern.
Ersetzen Sie die XML-Deklaration
<?xml version="1.0" encoding="utf-8" ?>
mit einer HTML-Deklaration wie folgt:
!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Sobald der Inhalt in einer Datei gespeichert wurde, gibt diese Methode ein gültiges XML-Dokument zurück.

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

Die doppelten Attributknoten werden automatisch mit den späteren Attributwerten entfernt, wobei die früheren überschrieben werden.


Beliebte Antwort

Ok, denke du musst den Fehler abfangen:

Dann sollten Sie die folgenden Methoden verwenden können:

reader.MoveToFirstAttribute();

und

reader.MoveToNextAttribute()

um die folgenden Eigenschaften zu erhalten:

reader.Value
reader.Name

Dadurch können Sie alle Attributwerte abrufen.



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum