Come gestire XML in C #


85

Qual è il modo migliore per gestire documenti XML, XSD ecc. In C # 2.0?

Quali classi utilizzare ecc. Quali sono le migliori pratiche per analizzare e creare documenti XML, ecc.

EDIT: anche i suggerimenti .Net 3.5 sono i benvenuti.


Per coloro che cercano anche di trovare una soluzione più praticabile, ignoralo. È vecchia una libreria .NET. Usa invece XDocument e risparmierai di cavarti gli occhi per la frustrazione
AER

Risposte:


177

Il mezzo principale di lettura e scrittura in C # 2.0 viene eseguito tramite la classe XmlDocument . È possibile caricare la maggior parte delle impostazioni direttamente in XmlDocument tramite XmlReader che accetta.

Caricamento diretto di XML

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

Caricamento di XML da un file

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

Trovo che il modo più semplice / veloce per leggere un documento XML sia usare XPath.

Leggere un documento XML utilizzando XPath (utilizzando XmlDocument che ci consente di modificare)

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");

Se è necessario lavorare con documenti XSD per convalidare un documento XML, è possibile utilizzarlo.

Convalida di documenti XML rispetto a schemi XSD

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

Convalida di XML rispetto a XSD in ogni nodo (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
}

Scrittura di un documento XML (manualmente)

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

(AGGIORNAMENTO 1)

In .NET 3.5 si utilizza XDocument per eseguire attività simili. La differenza, tuttavia, è che hai il vantaggio di eseguire query Linq per selezionare i dati esatti di cui hai bisogno. Con l'aggiunta di inizializzatori di oggetti è possibile creare una query che restituisce anche oggetti di propria definizione direttamente nella query stessa.

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

(AGGIORNAMENTO 2)

Un bel modo in .NET 3.5 è usare XDocument per creare XML è sotto. Questo fa apparire il codice in un modello simile all'output desiderato.

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")
                    )
              )
        );

crea

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

Tutto il resto fallisce, puoi consultare questo articolo MSDN che contiene molti esempi che ho discusso qui e altro ancora. http://msdn.microsoft.com/en-us/library/aa468556.aspx


3
Potresti voler sottolineare che stai usando XDocument nell'ultimo esempio poiché XDocument è abbastanza diverso da XmlDocument
Aaron Powell

2
Correzione; non c'è C # 3.5; intendi .NET 3.5 e C # 3.0
Marc Gravell

oh, e gli [inizializzatori di oggetti] "al volo" funzionerebbero in gran parte allo stesso modo con C # 3.0 e XmlDocument - comunque una buona risposta, anche se (+1)
Marc Gravell

Potrebbe valere la pena ricordare che se si carica un documento per eseguire una query con XPath (e non per modificarlo), l'utilizzo di un XPathDocument sarà molto più efficiente
Oliver Hallam

Questa convalida dello schema viene eseguita nodo per nodo? In caso contrario, c'è un modo per farlo nodo per nodo?
Malik Daud Ahmad Khokhar,

30

Dipende dalle dimensioni; per XML di piccole e medie dimensioni, un DOM come XmlDocument (qualsiasi versione C # /. NET) o XDocument (.NET 3.5 / C # 3.0) è il vincitore ovvio. Per l'utilizzo di xsd, è possibile caricare xml utilizzando un XmlReader e un XmlReader accetta (per creare ) un XmlReaderSettings . Gli oggetti XmlReaderSettings hanno schemi proprietà che può essere utilizzata per eseguire la convalida xsd (o dtd).

Per la scrittura di xml, si applicano le stesse cose, notando che è un po 'più facile disporre il contenuto con LINQ-to-XML (XDocument) rispetto al vecchio XmlDocument.

Tuttavia, per un XML enorme, un DOM potrebbe masticare troppa memoria, nel qual caso potrebbe essere necessario utilizzare XmlReader / XmlWriter direttamente.

Infine, per manipolare xml potresti voler usare XslCompiledTransform (un livello xslt).

L'alternativa a lavorare con xml è lavorare con un modello a oggetti; è possibile utilizzare xsd.exe per creare classi che rappresentano un modello conforme a xsd e caricare semplicemente l'xml come oggetti , manipolarlo con OO e quindi serializzare nuovamente quegli oggetti; lo fai con XmlSerializer .


Per manipolare (aggiungere / suppr elementi) un grande documento XML (40k righe). Qual è il modo migliore? Usavo LINQ-to-XML.
Neyoh

12

La risposta di nyxtom è molto buona. Aggiungerei un paio di cose:

Se è necessario l'accesso in sola lettura a un documento XML, XPathDocumentè un oggetto molto più leggero di XmlDocument.

Lo svantaggio dell'utilizzo XPathDocumentè che non puoi usare i metodi familiari SelectNodese SelectSingleNodedi XmlNode. Invece, devi usare gli strumenti che IXPathNavigablefornisce: usa CreateNavigatorper creare un XPathNavigatore usa XPathNavigatorper creare XPathNodeIterators per scorrere gli elenchi di nodi che trovi tramite XPath. Ciò richiede generalmente alcune righe di codice in più rispetto aXmlDocument metodi.

Ma: le classi XmlDocumente vengono XmlNodeimplementate IXPathNavigable, quindi qualsiasi codice che scrivi per usare questi metodi su un file XPathDocumentfunzionerà anche su un file XmlDocument. Se ti abitui a scrivere contro IXPathNavigable, i tuoi metodi possono funzionare contro entrambi gli oggetti. (Questo è il motivo per cui l'utilizzo di XmlNodeeXmlDocument nelle firme del metodo è contrassegnato da FxCop.)

Purtroppo, XDocumente XElement(e XNodee XObject) non implementare IXPathNavigable.

Un'altra cosa non presente nella risposta di nyxtom è XmlReader. In genere si utilizza XmlReaderper evitare il sovraccarico di analizzare il flusso XML in un modello a oggetti prima di iniziare a elaborarlo. Invece, usi un fileXmlReader per elaborare il flusso di input un nodo XML alla volta. Questa è essenzialmente la risposta di .NET a SAX. Ti consente di scrivere codice molto veloce per l'elaborazione di documenti XML di grandi dimensioni.

XmlReader fornisce inoltre il modo più semplice per elaborare i frammenti di documenti XML, ad esempio il flusso di elementi XML senza elementi inclusi restituiti dall'opzione FOR XML RAW di SQL Server.

Il codice che scrivi usando XmlReaderè generalmente molto strettamente accoppiato al formato dell'XML che sta leggendo. L'uso di XPath consente al tuo codice di essere accoppiato molto, molto più liberamente all'XML, motivo per cui è generalmente la risposta giusta. Ma quando hai bisogno di usarlo XmlReader, ne hai davvero bisogno.


3
Si noti che esiste un metodo di estensione XPathNavigator CreateNavigator(this XNode node)per creare un XPathNavigatorda un XNode(che include la classe derivata XDocument).
Dave

5

Prima di tutto, impara a conoscere le nuove classi XDocument e XElement , perché sono un miglioramento rispetto alla precedente famiglia XmlDocument.

  1. Lavorano con LINQ
  2. Sono più veloci e più leggeri

Tuttavia , potrebbe essere necessario utilizzare ancora le vecchie classi per lavorare con il codice legacy, in particolare i proxy generati in precedenza. In tal caso, sarà necessario acquisire familiarità con alcuni modelli per l'interoperabilità tra queste classi di gestione XML.

Penso che la tua domanda sia abbastanza ampia e richiederebbe troppo in una singola risposta per fornire dettagli, ma questa è la prima risposta generale a cui ho pensato e serve come inizio.


Sono d'accordo che (XDocument ecc.) Siano fantastici, ma l'OP ha chiesto informazioni su C # 2.0.
Marc Gravell


2

Se stai lavorando in .NET 3.5 e non hai paura del codice sperimentale, puoi controllare LINQ to XSD ( http://blogs.msdn.com/xmlteam/archive/2008/02/21/linq-to- xsd-alpha-0-2.aspx ) che genererà classi .NET da un XSD (comprese le regole incorporate dall'XSD).

Ha quindi la capacità di scrivere direttamente su un file e leggere da un file assicurandosi che sia conforme alle regole XSD.

Consiglio vivamente di avere un XSD per qualsiasi documento XML con cui lavori:

  • Consente di applicare le regole nell'XML
  • Consente ad altri di vedere come è / sarà strutturato l'XML
  • Può essere utilizzato per la convalida di XML

Trovo che Liquid XML Studio sia un ottimo strumento per generare XSD ed è gratuito!


2

Scrittura di XML con la classe XmlDocument

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

1

Se crei un set di dati digitato nel designer, ottieni automaticamente un xsd, un oggetto fortemente tipizzato, e puoi caricare e salvare l'xml con una riga di codice.


Ho avuto un grande successo con DataSet. Sono anche molto amichevoli con i database.
Utente1

1

La mia opinione personale, come programmatore C #, è che il modo migliore per gestire XML in C # è delegare quella parte del codice a un progetto VB .NET. In .NET 3.5, VB .NET ha XML Literals, che rendono la gestione di XML molto più intuitiva. Vedi qui, ad esempio:

Panoramica di LINQ to XML in Visual Basic

(Assicurati di impostare la pagina per visualizzare il codice VB, non il codice C #.)

Scriverei il resto del progetto in C #, ma gestirò l'XML in un progetto VB referenziato.


Non vale la pena passare a vb solo per XML letterale. XML si occupa solo di letterali. Se l'xml viene passato come parametro, il supporto letterale XML non offre molti vantaggi. Invece, la sintassi legacy di vb.net rovinerà la felice esperienza di programmazione di C #.
Gqqnbig

0

nyxtom,

"Doc" e "xdoc" non dovrebbero corrispondere nell'esempio 1?

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

Ho inviato una modifica per l'approvazione alla risposta a cui ti riferisci, tuttavia questo avrebbe dovuto essere un commento, non una risposta.
David Thompson

Grazie David. D'accordo, non mi avrebbe permesso di commentare in quel momento. Non so perché.
mokumaxCraig

0

La risposta di Cookey è buona ... ma qui ci sono istruzioni dettagliate su come creare un oggetto fortemente tipizzato da un XSD (o XML) e serializzare / deserializzare in poche righe di codice:

Istruzioni


"La pagina che stavi cercando non esiste." :(
Ian Grainger

0

Se hai bisogno di convertire i dati tra XmlNode<=> XNode<=> XElement
(ad es. Per usare LINQ), queste estensioni potrebbero esserti utili:

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

Utilizzo:

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
...
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.