Umgang mit XML in C #

85

Was ist der beste Weg, um mit XML-Dokumenten, XSD usw. in C # 2.0 umzugehen?

Welche Klassen werden verwendet? Usw. Was sind die Best Practices für das Parsen und Erstellen von XML-Dokumenten usw.

EDIT: .Net 3.5 Vorschläge sind ebenfalls willkommen.

Malik Daud Ahmad Khokhar
quelle
Wenn Sie auch versuchen, eine praktikablere Lösung zu finden, ignorieren Sie dies. Es ist alt, eine .NET-Bibliothek. Verwenden Sie stattdessen XDocument, und Sie sparen sich das frustrierte Ausstechen der Augen
VRE

Antworten:

177

Das primäre Mittel zum Lesen und Schreiben in C # 2.0 erfolgt über die XmlDocument- Klasse. Sie können die meisten Ihrer Einstellungen über den akzeptierten XmlReader direkt in das XmlDocument laden.

XML direkt laden

XmlDocument document = new XmlDocument();
document.LoadXml("<People><Person Name='Nick' /><Person Name='Joe' /></People>");

Laden von XML aus einer Datei

XmlDocument document = new XmlDocument();
document.Load(@"C:\Path\To\xmldoc.xml");
// Or using an XmlReader/XmlTextReader
XmlReader reader = XmlReader.Create(@"C:\Path\To\xmldoc.xml");
document.Load(reader);

Ich finde, der einfachste / schnellste Weg, ein XML-Dokument zu lesen, ist die Verwendung von XPath.

Lesen eines XML-Dokuments mit XPath (Verwenden von XmlDocument, mit dem wir es bearbeiten können)

XmlDocument document = new XmlDocument();
document.LoadXml("<People><Person Name='Nick' /><Person Name='Joe' /></People>");

// Select a single node
XmlNode node = document.SelectSingleNode("/People/Person[@Name = 'Nick']");

// Select a list of nodes
XmlNodeList nodes = document.SelectNodes("/People/Person");

Wenn Sie mit XSD-Dokumenten arbeiten müssen, um ein XML-Dokument zu validieren, können Sie dies verwenden.

Validieren von XML-Dokumenten anhand von XSD-Schemas

XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidateType = ValidationType.Schema;
settings.Schemas.Add("", pathToXsd); // targetNamespace, pathToXsd

XmlReader reader = XmlReader.Create(pathToXml, settings);
XmlDocument document = new XmlDocument();

try {
    document.Load(reader);
} catch (XmlSchemaValidationException ex) { Trace.WriteLine(ex.Message); }

Validierung von XML gegen XSD an jedem Knoten (UPDATE 1)

XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidateType = ValidationType.Schema;
settings.Schemas.Add("", pathToXsd); // targetNamespace, pathToXsd
settings.ValidationEventHandler += new ValidationEventHandler(settings_ValidationEventHandler);

XmlReader reader = XmlReader.Create(pathToXml, settings);
while (reader.Read()) { }

private void settings_ValidationEventHandler(object sender, ValidationEventArgs args)
{
    // e.Message, e.Severity (warning, error), e.Error
    // or you can access the reader if you have access to it
    // reader.LineNumber, reader.LinePosition.. etc
}

Schreiben eines XML-Dokuments (manuell)

XmlWriter writer = XmlWriter.Create(pathToOutput);
writer.WriteStartDocument();
writer.WriteStartElement("People");

writer.WriteStartElement("Person");
writer.WriteAttributeString("Name", "Nick");
writer.WriteEndElement();

writer.WriteStartElement("Person");
writer.WriteStartAttribute("Name");
writer.WriteValue("Nick");
writer.WriteEndAttribute();
writer.WriteEndElement();

writer.WriteEndElement();
writer.WriteEndDocument();

writer.Flush();

(UPDATE 1)

In .NET 3.5 verwenden Sie XDocument, um ähnliche Aufgaben auszuführen. Der Unterschied besteht jedoch darin, dass Sie den Vorteil haben, Linq-Abfragen durchzuführen, um genau die Daten auszuwählen, die Sie benötigen. Durch Hinzufügen von Objektinitialisierern können Sie eine Abfrage erstellen, die sogar Objekte Ihrer eigenen Definition direkt in der Abfrage selbst zurückgibt.

    XDocument doc = XDocument.Load(pathToXml);
    List<Person> people = (from xnode in doc.Element("People").Elements("Person")
                       select new Person
                       {
                           Name = xnode.Attribute("Name").Value
                       }).ToList();

(UPDATE 2)

Eine gute Möglichkeit in .NET 3.5 ist die Verwendung von XDocument zum Erstellen von XML. Dadurch erscheint der Code in einem ähnlichen Muster wie die gewünschte Ausgabe.

XDocument doc =
        new XDocument(
              new XDeclaration("1.0", Encoding.UTF8.HeaderName, String.Empty),
              new XComment("Xml Document"),
              new XElement("catalog",
                    new XElement("book", new XAttribute("id", "bk001"),
                          new XElement("title", "Book Title")
                    )
              )
        );

schafft

<!--Xml Document-->
<catalog>
  <book id="bk001">
    <title>Book Title</title>
  </book>
</catalog>

Alles andere schlägt fehl. Sie können diesen MSDN-Artikel lesen, der viele Beispiele enthält, die ich hier und mehr besprochen habe. http://msdn.microsoft.com/en-us/library/aa468556.aspx

Nyxtom
quelle
3
Vielleicht möchten Sie darauf hinweisen, dass Sie XDocument im letzten Beispiel verwenden, da XDocument ganz anders ist als XmlDocument
Aaron Powell
2
Korrektur; es gibt kein C # 3.5; du meinst .NET 3.5 und C # 3.0
Marc Gravell
Oh, und die "on the fly" [Objektinitialisierer] würden mit C # 3.0 und XmlDocument weitgehend gleich funktionieren - immer noch eine gute Antwort, obwohl (+1)
Marc Gravell
Es könnte erwähnenswert sein, dass die Verwendung eines XPathDocument viel effizienter ist, wenn Sie ein Dokument laden, um es mit XPath abzufragen (und nicht zu bearbeiten)
Oliver Hallam,
Wird diese Schemaüberprüfung Knoten für Knoten durchgeführt? Wenn nicht, gibt es eine Möglichkeit, dies Knoten für Knoten zu tun?
Malik Daud Ahmad Khokhar
30

Es hängt von der Größe ab; Für kleine bis mittelgroße XML- Dateien ist ein DOM wie XmlDocument (beliebige C # /. NET-Versionen) oder XDocument (.NET 3.5 / C # 3.0) der offensichtliche Gewinner. Für die Verwendung von xsd können Sie xml mit einem XmlReader laden , und ein XmlReader akzeptiert (zum Erstellen ) XmlReaderSettings . Die XmlReaderSettings-Objekte verfügen über eine Schemas- Eigenschaft, mit der eine xsd- (oder dtd-) Validierung durchgeführt werden kann.

Für das Schreiben von XML gelten dieselben Dinge, wobei zu beachten ist, dass das Layouten von Inhalten mit LINQ-to-XML (XDocument) etwas einfacher ist als mit dem älteren XmlDocument.

Bei großen XML-Dateien kann ein DOM jedoch zu viel Speicherplatz beanspruchen. In diesem Fall müssen Sie möglicherweise XmlReader / XmlWriter direkt verwenden.

Schließlich möchten Sie zum Bearbeiten von XML möglicherweise XslCompiledTransform (eine xslt-Ebene) verwenden.

Die Alternative zur Arbeit mit XML besteht darin, mit einem Objektmodell zu arbeiten. Mit xsd.exe können Sie Klassen erstellen, die ein xsd-kompatibles Modell darstellen. Laden Sie die XML-Datei einfach als Objekte , bearbeiten Sie sie mit OO und serialisieren Sie diese Objekte erneut. Sie tun dies mit XmlSerializer .

Marc Gravell
quelle
Bearbeiten (Hinzufügen / Unterstützen von Elementen) eines großen XML-Dokuments (40.000 Zeilen). Was ist der beste Weg? Ich habe früher LINQ-to-XML verwendet.
Neyoh
12

Die Antwort von nyxtom ist sehr gut. Ich würde ein paar Dinge hinzufügen:

Wenn Sie schreibgeschützten Zugriff auf ein XML-Dokument benötigen, XPathDocumentist dies ein viel leichteres Objekt als XmlDocument.

Der Nachteil der Verwendung XPathDocumentist, dass Sie nicht die bekannten SelectNodesund SelectSingleNodeMethoden von verwenden können XmlNode. Stattdessen müssen Sie die folgenden Tools verwenden IXPathNavigable: Verwenden Sie CreateNavigatorzum Erstellen eines XPathNavigatorund verwenden Sie das XPathNavigatorzum Erstellen von XPathNodeIterators, um die über XPath gefundenen Knotenlisten zu durchlaufen. Dies erfordert im Allgemeinen einige Codezeilen mehr als die XmlDocumentMethoden.

Aber: Die Klassen XmlDocumentund XmlNodeimplementieren IXPathNavigable, sodass jeder Code, den Sie schreiben, um diese Methoden auf einem zu verwenden XPathDocument, auch auf einem funktioniert XmlDocument. Wenn Sie sich daran gewöhnt haben, dagegen zu schreiben IXPathNavigable, können Ihre Methoden gegen beide Objekte arbeiten. (Aus diesem Grund wird die Verwendung von XmlNodeund XmlDocumentin Methodensignaturen von FxCop gekennzeichnet.)

Bedauerlicherweise XDocumentund XElement(und XNodeund XObject) nicht implementieren IXPathNavigable.

Eine andere Sache, die in Nyxtoms Antwort nicht vorhanden ist, ist XmlReader. Im Allgemeinen XmlReadervermeiden Sie den Aufwand für das Parsen des XML-Streams in ein Objektmodell, bevor Sie mit der Verarbeitung beginnen. Stattdessen verwenden Sie a XmlReader, um den Eingabestream jeweils für einen XML-Knoten zu verarbeiten. Dies ist im Wesentlichen die Antwort von .NET auf SAX. Sie können damit sehr schnellen Code für die Verarbeitung sehr großer XML-Dokumente schreiben.

XmlReader bietet auch die einfachste Möglichkeit, XML-Dokumentfragmente zu verarbeiten, z. B. den Stream von XML-Elementen ohne einschließendes Element, das von der FOR XML RAW-Option von SQL Server zurückgegeben wird.

Der Code, mit dem Sie schreiben, XmlReaderist im Allgemeinen sehr eng an das Format des gelesenen XML gekoppelt. Durch die Verwendung von XPath kann Ihr Code viel, viel lockerer mit dem XML gekoppelt werden, weshalb dies im Allgemeinen die richtige Antwort ist. Aber wenn Sie es brauchen, brauchen XmlReaderSie es wirklich.

Robert Rossney
quelle
3
Beachten Sie, dass es eine Erweiterungsmethode XPathNavigator CreateNavigator(this XNode node)zum Erstellen einer XPathNavigatoraus XNode(einschließlich der abgeleiteten Klasse XDocument) gibt.
Dave
5

Lernen Sie zunächst die neuen Klassen XDocument und XElement kennen , da sie eine Verbesserung gegenüber der vorherigen XmlDocument-Familie darstellen.

  1. Sie arbeiten mit LINQ
  2. Sie sind schneller und leichter

Jedoch , müssen Sie unter Umständen noch die alten Klassen zur Arbeit mit Legacy - Code verwenden - besonders zuvor generierten Proxies. In diesem Fall müssen Sie sich mit einigen Mustern für die Interaktion zwischen diesen XML-Verarbeitungsklassen vertraut machen.

Ich denke, Ihre Frage ist ziemlich weit gefasst und würde zu viel in einer einzigen Antwort erfordern, um Details anzugeben, aber dies ist die erste allgemeine Antwort, an die ich gedacht habe, und dient als Anfang.

Hurst
quelle
Ich bin damit einverstanden, dass sie (XDocument usw.) großartig sind, aber das OP fragte nach C # 2.0.
Marc Gravell
2

Wenn Sie in .NET 3.5 arbeiten und keine Angst vor experimentellem Code haben, können Sie LINQ to XSD ( http://blogs.msdn.com/xmlteam/archive/2008/02/21/linq-to-) überprüfen. xsd-alpha-0-2.aspx ), das .NET-Klassen aus einer XSD generiert (einschließlich integrierter Regeln aus der XSD).

Es kann dann direkt in eine Datei schreiben und aus einer Datei lesen, um sicherzustellen, dass sie den XSD-Regeln entspricht.

Ich empfehle auf jeden Fall eine XSD für jedes XML-Dokument, mit dem Sie arbeiten:

  • Ermöglicht das Erzwingen von Regeln in XML
  • Ermöglicht anderen zu sehen, wie das XML strukturiert ist / sein wird
  • Kann zur Validierung von XML verwendet werden

Ich finde, dass Liquid XML Studio ein großartiges Tool zum Generieren von XSDs ist und kostenlos ist!

Aaron Powell
quelle
1

Wenn Sie im Designer ein typisiertes Dataset erstellen, erhalten Sie automatisch eine xsd, ein stark typisiertes Objekt, und können die XML mit einer Codezeile laden und speichern.

Peter C.
quelle
Ich hatte großen Erfolg mit DataSets. Sie sind auch sehr freundlich mit Datenbanken.
User1
1

Meine persönliche Meinung als C # -Programmierer ist, dass der beste Weg, mit XML in C # umzugehen, darin besteht, diesen Teil des Codes an ein VB .NET-Projekt zu delegieren. In .NET 3.5 verfügt VB .NET über XML-Literale, die den Umgang mit XML wesentlich intuitiver machen. Siehe hier zum Beispiel:

Übersicht über LINQ to XML in Visual Basic

(Stellen Sie sicher, dass auf der Seite VB-Code und nicht C # -Code angezeigt wird.)

Ich würde den Rest des Projekts in C # schreiben, aber das XML in einem referenzierten VB-Projekt behandeln.

Ryan Lundy
quelle
Es lohnt sich nicht, nur für XML-Literal zu vb zu wechseln. XML behandelt nur Literale. Wenn die XML als Parameter übergeben wird, bietet die XML-Literal-Unterstützung nicht viele Vorteile. Stattdessen wird die Legacy-Syntax von vb.net das glückliche Programmiererlebnis von C # ruinieren.
Gqqnbig
1

Schreiben von XML mit der XmlDocument-Klasse

//itemValues is collection of items in Key value pair format
//fileName i name of XML file which to creatd or modified with content
    private void WriteInXMLFile(System.Collections.Generic.Dictionary<string, object> itemValues, string fileName)
    {
        string filePath = "C:\\\\tempXML\\" + fileName + ".xml";
        try
        {

            if (System.IO.File.Exists(filePath))
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(filePath);                   

                XmlNode rootNode = doc.SelectSingleNode("Documents");

                XmlNode pageNode = doc.CreateElement("Document");
                rootNode.AppendChild(pageNode);


                foreach (string key in itemValues.Keys)
                {

                    XmlNode attrNode = doc.CreateElement(key);
                    attrNode.InnerText = Convert.ToString(itemValues[key]);
                    pageNode.AppendChild(attrNode);
                    //doc.DocumentElement.AppendChild(attrNode);

                }
                doc.DocumentElement.AppendChild(pageNode);
                doc.Save(filePath);
            }
            else
            {
                XmlDocument doc = new XmlDocument();
                using(System.IO.FileStream fs = System.IO.File.Create(filePath))
                {
                    //Do nothing
                }

                XmlNode rootNode = doc.CreateElement("Documents");
                doc.AppendChild(rootNode);
                doc.Save(filePath);

                doc.Load(filePath);

                XmlNode pageNode = doc.CreateElement("Document");
                rootNode.AppendChild(pageNode);

                foreach (string key in itemValues.Keys)
                {                          
                    XmlNode attrNode = doc.CreateElement(key);                           
                    attrNode.InnerText = Convert.ToString(itemValues[key]);
                    pageNode.AppendChild(attrNode);
                    //doc.DocumentElement.AppendChild(attrNode);

                }
                doc.DocumentElement.AppendChild(pageNode);

                doc.Save(filePath);

            }
        }
        catch (Exception ex)
        {

        }

    }

OutPut look like below
<Dcouments>
    <Document>
        <DocID>01<DocID>
        <PageName>121<PageName>
        <Author>Mr. ABC<Author>
    <Dcoument>
    <Document>
        <DocID>02<DocID>
        <PageName>122<PageName>
        <Author>Mr. PQR<Author>
    <Dcoument>
</Dcouments>
Anil Rathod
quelle
0

Nyxtom,

Sollten "doc" und "xdoc" in Beispiel 1 nicht übereinstimmen?

XDocument **doc** = XDocument.Load(pathToXml);
List<Person> people = (from xnode in **xdoc**.Element("People").Elements("Person")
                   select new Person
                   {
                       Name = xnode.Attribute("Name").Value
                   }).ToList();
mokumaxCraig
quelle
Ich habe eine Bearbeitung zur Genehmigung der Antwort eingereicht, auf die Sie sich beziehen. Dies sollte jedoch eigentlich ein Kommentar und keine Antwort sein.
David Thompson
Danke David. Einverstanden, würde es mir nicht erlauben, zu der Zeit zu kommentieren. Nicht sicher warum.
MokumaxCraig
0

Cookeys Antwort ist gut ... aber hier finden Sie detaillierte Anweisungen zum Erstellen eines stark typisierten Objekts aus einer XSD (oder XML) und zum Serialisieren / Deserialisieren in wenigen Codezeilen:

Anleitung

Steve Horn
quelle
"Die Seite, nach der Sie gesucht haben, existiert nicht." :(
Ian Grainger
0

Wenn Sie jemals Daten zwischen XmlNode<=> XNode<=> konvertieren müssen XElement
(z. B. um LINQ zu verwenden), können diese Erweiterungen für Sie hilfreich sein:

public static class MyExtensions
{
    public static XNode GetXNode(this XmlNode node)
    {
        return GetXElement(node);
    }

    public static XElement GetXElement(this XmlNode node)
    {
        XDocument xDoc = new XDocument();
        using (XmlWriter xmlWriter = xDoc.CreateWriter())
            node.WriteTo(xmlWriter);
        return xDoc.Root;
    }

    public static XmlNode GetXmlNode(this XElement element)
    {
        using (XmlReader xmlReader = element.CreateReader())
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(xmlReader);
            return xmlDoc;
        }
    }

    public static XmlNode GetXmlNode(this XNode node)
    {
        return GetXmlNode(node);
    }
}

Verwendung:

XmlDocument MyXmlDocument = new XmlDocument();
MyXmlDocument.Load("MyXml.xml");
XElement MyXElement = MyXmlDocument.GetXElement(); // Convert XmlNode to XElement
List<XElement> List = MyXElement.Document
   .Descendants()
   .ToList(); // Now you can use LINQ
...
Michael Hutter
quelle