Jak radzić sobie z XML w C#

Jaki jest najlepszy sposób radzenia sobie z dokumentami XML, XSD itp. W C # 2.0?

Jakich klas używać itd. Jakie są najlepsze praktyki parsowania i tworzenia dokumentów XML itp.

EDIT:. Net 3.5 sugestie są również mile widziane.

 77
Author: Zapnologica, 2008-10-21

12 answers

W C# 2.0 podstawowe sposoby odczytu i zapisu wykonywane są za pomocą klasy XmlDocument. Możesz załadować większość swoich ustawień bezpośrednio do dokumentu XmlDocument za pomocą akceptowanego przez niego programu XmlReader.

Wczytywanie XML bezpośrednio

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

Ładowanie XML z pliku

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

Uważam, że najprostszym/najszybszym sposobem odczytania dokumentu XML jest użycie XPath.

Odczyt dokumentu XML za pomocą XPath (za pomocą XmlDocument, który pozwala nam edytować)

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

Jeśli musisz pracować z dokumentami XSD, aby zweryfikować dokument XML, możesz tego użyć.

Walidacja dokumentów XML na schematach 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); }
XML-XSD-XSD-XSD-XSD-XSD-XSD-XSD-XSD-XSD-XSD-XSD-XSD-XSD-XSD-XSD]}
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
}

Zapisywanie dokumentu XML (ręcznie)

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

(Aktualizacja 1)

W. NET 3.5, używasz XDocument do wykonywania podobnych zadań. Różnica polega jednak na tym, że masz tę zaletę, że wykonujesz zapytania Linq, aby wybrać dokładne dane, których potrzebujesz. Po dodaniu inicjalizatorów obiektów można utworzyć zapytanie, które zwraca nawet obiekty o własnej definicji bezpośrednio w samym zapytaniu.

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

(Aktualizacja 2)

Dobrym sposobem w. NET 3.5 jest użycie XDocument do tworzenia XML jest poniżej. To sprawia, że kod pojawia się w podobnym wzorze do pożądanego wyjścia.

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

Tworzy

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

Wszystko inne zawodzi, możesz sprawdzić ten artykuł MSDN, który ma wiele przykładów, które omówiłem tutaj i więcej. http://msdn.microsoft.com/en-us/library/aa468556.aspx

 166
Author: nyxtom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-15 12:10:30

W przypadku plików xml o małych i średnich rozmiarach oczywistym zwycięzcą jest DOM, taki jak XmlDocument (dowolne wersje C#/. NET) lub XDocument (. NET 3.5/C# 3.0). Aby używać xsd, można załadować xml za pomocą XmlReader, A XmlReader akceptuje (to Create) an XmlReaderSettings. Obiekty XmlReaderSettings mają właściwość Schemas , która może być użyta do walidacji XSD (lub dtd).

Do pisania xml stosuje się te same rzeczy, zauważając że trochę łatwiej jest układać zawartość za pomocą LINQ-to-XML (XDocument) niż starszy XmlDocument.

Jednak dla ogromnego xml, DOM może chomp zbyt dużo pamięci, w takim przypadku może być konieczne użycie XmlReader/XmlWriter bezpośrednio.

Wreszcie, do manipulowania xml możesz użyć XslCompiledTransform (warstwy xslt).

Alternatywą dla pracy z xml jest praca z modelem obiektowym; możesz użyć xsd.exe do tworzenia klas, które reprezentują model zgodny z xsd i po prostu załaduj XML jako obiekty , manipuluj nim za pomocą OO, a następnie ponownie serializuj te obiekty; robisz to za pomocą XmlSerializer.

 29
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-21 05:48:22

Odpowiedź Nyxtom jest bardzo dobra. Dodałbym jeszcze kilka rzeczy:

Jeśli potrzebujesz dostępu tylko do odczytu dokumentu XML, XPathDocument jest znacznie lżejszym obiektem niż XmlDocument.

Minusem używania XPathDocument jest to, że nie można używać znanych metod SelectNodes i SelectSingleNode XmlNode. Zamiast tego, musisz użyć narzędzi IXPathNavigable: użyj CreateNavigator, aby utworzyć XPathNavigator, i użyj XPathNavigator, aby utworzyć XPathNodeIteratorS, aby iterować listy węzłów znalezionych przez XPath. To ogólnie wymaga kilku linijek kodu więcej niż metody XmlDocument.

Ale: klasy XmlDocument i XmlNode implementują IXPathNavigable, więc każdy kod, który napiszesz, aby użyć tych metod na XPathDocument będzie również działał na XmlDocument. Jeśli przyzwyczaisz się do pisania przeciwko IXPathNavigable, twoje metody mogą działać przeciwko każdemu obiektowi. (Dlatego używanie XmlNode i XmlDocument w podpisach metod jest oznaczane przez FxCop.)

, XDocument i XElement (oraz XNode i XObject) nie implementują IXPathNavigable.

Kolejna rzecz nie odpowiedź nyxtom brzmi XmlReader. Zazwyczaj używa się XmlReader, aby uniknąć napowietrznego parsowania strumienia XML do modelu obiektowego przed rozpoczęciem jego przetwarzania. Zamiast tego używasz XmlReader do przetwarzania strumienia wejściowego po jednym węźle XML na raz. Jest to zasadniczo odpowiedź. NET NA SAX. Pozwala pisać bardzo szybki kod do przetwarzania bardzo dużych dokumentów XML.

XmlReader zapewnia również najprostszy sposób przetwarzania fragmentów dokumentów XML, np. strumień elementów XML bez zwraca element, który SQL Server dla XML RAW.

Kod, który piszesz za pomocą XmlReader, jest na ogół bardzo ściśle powiązany z formatem XML, który czytasz. Korzystanie z XPath pozwala na dużo, dużo bardziej luźne połączenie kodu z XML, dlatego jest to ogólnie właściwa odpowiedź. Ale kiedy musisz użyć XmlReader, naprawdę tego potrzebujesz.

 12
Author: Robert Rossney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-21 18:51:26

Przede wszystkim poznaj nowe klasy XDocumenti XElement, ponieważ są one ulepszeniem w stosunku do poprzedniej rodziny XmlDocument.

  1. pracują z LINQ
  2. Są szybsze i lżejsze]}

Jednakże , Być może będziesz musiał nadal używać starych klas do pracy ze starszym kodem - szczególnie wcześniej wygenerowanych proxy. W takim przypadku musisz zapoznać się z niektórymi wzorami współdziałania między tymi Klasy obsługi XML.

Myślę, że twoje pytanie jest dość szerokie i wymagałoby zbyt wiele w jednej odpowiedzi, aby podać szczegóły, ale jest to pierwsza ogólna odpowiedź, o której pomyślałem i służy jako początek.

 4
Author: hurst,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-21 05:47:40

101 próbek Linq

Http://msdn.microsoft.com/en-us/library/bb387098.aspx

I próbki Linq do XML

Http://msdn.microsoft.com/en-us/vbasic/bb688087.aspx

I myślę, że Linq ułatwia XML.

 4
Author: emremp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-21 06:51:24

Jeśli pracujesz w. NET 3.5 i nie boisz się kodu eksperymentalnego możesz sprawdzić LINQ to XSD ( http://blogs.msdn.com/xmlteam/archive/2008/02/21/linq-to-xsd-alpha-0-2.aspx ), które generują klasy. NET z XSD (w tym wbudowane reguły z XSD).

Następnie ma możliwość zapisu bezpośrednio do pliku i odczytu z pliku, zapewniając, że jest zgodny z regułami XSD.

Zdecydowanie sugeruję posiadanie XSD dla każdego dokumentu XML, który pracujesz z:

  • pozwala na egzekwowanie reguł w XML
  • pozwala innym zobaczyć, jak XML jest/ będzie strukturą
  • może być używany do walidacji XML

Uważam, że Liquid XML Studio to świetne narzędzie do generowania XSD i jest darmowe!

 2
Author: Aaron Powell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-21 06:49:49

Jeśli utworzysz wpisany zestaw danych w Projektancie, automatycznie otrzymasz XSD, silnie wpisany obiekt i możesz załadować i zapisać xml za pomocą jednej linii kodu.

 1
Author: Peter C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-21 16:41:01

Moja osobista opinia, jako programisty C#, jest taka, że najlepszym sposobem radzenia sobie z XML w C # jest delegowanie tej części kodu do projektu VB. NET. W. NET 3.5, VB. NET ma literały XML, które sprawiają, że radzenie sobie z XML jest znacznie bardziej intuicyjne. Zobacz tutaj, na przykład:

Przegląd LINQ do XML w Visual Basic

(upewnij się, że strona wyświetla kod VB, a nie kod C#.)

Resztę projektu napisałbym w C#, ale obsługiwał XML w odwołanym VB projekt.

 1
Author: Ryan Lundy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-31 18:57:44

Zapis XML z klasą 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
Author: Anil Rathod,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-09 10:18:31

Nyxtom,

Czy "doc" i "xdoc" nie powinny pasować do przykładu 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();
 0
Author: mokumaxCraig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-29 14:40:03

Odpowiedź Cookeya jest dobra... ale tutaj są szczegółowe instrukcje jak utworzyć silnie wpisany obiekt z XSD (lub XML) i serialize/deserialize w kilku wierszach kodu:

Instrukcje

 0
Author: Steve Horn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-26 17:45:40

Jeśli kiedykolwiek będziesz musiał przekonwertować dane pomiędzy XmlNode XNode XElement
(np. w celu użycia LINQ) to rozszerzenie może być pomocne dla Ciebie:

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

Użycie:

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
...
 0
Author: Michael Hutter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-28 11:21:10