Как работать с XML в С#

Каков наилучший способ работы с документами XML, XSD и т.д. в С# 2.0?

Какие классы использовать и т.д. Каковы наилучшие методы анализа и создания XML-документов и т.д.

РЕДАКТИРОВАТЬ:.Net 3.5 также приветствуются.

Ответ 1

Основные средства чтения и записи в С# 2.0 выполняются с помощью класса XmlDocument. Вы можете загрузить большинство своих настроек непосредственно в XmlDocument через XmlReader, который он принимает.

Загрузка XML напрямую

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

Загрузка XML из файла

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

Я нахожу самый простой/быстрый способ чтения XML-документа с помощью XPath.

Чтение XML-документа с использованием XPath (использование XmlDocument, которое позволяет нам редактировать)

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

Если вам нужно работать с документами XSD для проверки XML-документа, вы можете использовать это.

Проверка XML-документов в отношении схем 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 на каждом Node (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
}

Написание XML-документа (вручную)

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

(ОБНОВЛЕНИЕ 1)

В .NET 3.5 вы используете XDocument для выполнения подобных задач. Однако разница заключается в том, что у вас есть преимущество в выполнении запросов Linq для выбора точных данных, которые вам нужны. С добавлением инициализаторов объектов вы можете создать запрос, который даже возвращает объекты вашего собственного определения прямо в самом запросе.

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

(ОБНОВЛЕНИЕ 2)

Хорошим способом в .NET 3.5 является использование XDocument для создания XML ниже. Это приводит к тому, что код выглядит аналогичным образом с желаемым выходом.

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

создает

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

Все остальное не удается, вы можете проверить эту статью MSDN, в которой есть много примеров, которые я обсуждал здесь и более. http://msdn.microsoft.com/en-us/library/aa468556.aspx

Ответ 2

Это зависит от размера; для небольших и средних размеров xml, DOM, таких как XmlDocument (любые версии С#/. NET) или XDocument (.NET 3.5/С# 3.0) является очевидным победителем. Для использования xsd вы можете загрузить xml с помощью XmlReader, и XmlReader принимает (to Create) a XmlReaderSettings. Объекты XmlReaderSettings имеют свойство Schemas, которое может использоваться для проверки xsd (или dtd).

Для написания xml применяются те же самые вещи, отмечая, что немного легче разместить контент с LINQ-to-XML (XDocument), чем старый XmlDocument.

Однако, для огромного xml, DOM может выделять слишком много памяти, и в этом случае вам может понадобиться напрямую использовать XmlReader/XmlWriter.

Наконец, для управления xml вы можете использовать XslCompiledTransform (слой xslt).

Альтернативой работе с xml является работа с объектной моделью; вы можете использовать xsd.exe для создания классов, представляющих xsd-совместимую модель, и просто загружать xml как объекты, управлять им с помощью OO и затем снова сериализуйте эти объекты; вы делаете это с помощью XmlSerializer.

Ответ 3

Ответ nyxtom очень хорош. Я бы добавил несколько вещей:

Если вам нужен доступ только для чтения к XML-документу, XPathDocument является гораздо более легким объектом, чем XmlDocument.

Недостатком использования XPathDocument является то, что вы не можете использовать знакомые методы SelectNodes и SelectSingleNode XmlNode. Вместо этого вы должны использовать инструменты, которые предоставляет IXPathNavigable: используйте CreateNavigator для создания XPathNavigator и используйте XPathNavigator для создания XPathNodeIterator для перебора списков узлов, которые вы найдете через XPath. Обычно это требует еще нескольких строк кода, чем методы XmlDocument.

Но: классы XmlDocument и XmlNode реализуют IXPathNavigable, поэтому любой код, который вы пишете для использования этих методов в XPathDocument, также будет работать на XmlDocument. Если вы привыкли писать против IXPathNavigable, ваши методы могут работать против любого объекта. (Вот почему использование XmlNode и XmlDocument в сигнатурах метода помечено FxCop.)

С сожалением, XDocument и XElementXNode и XObject) не реализуют IXPathNavigable.

Еще одна вещь, отсутствующая в nyxtom ответе, - XmlReader. Обычно вы используете XmlReader, чтобы избежать накладных расходов на синтаксический анализ XML-потока в объектной модели до того, как вы начнете его обрабатывать. Вместо этого вы используете XmlReader для обработки входного потока один XML node за раз. Это, по сути,.NET ответ на SAX. Это позволяет писать очень быстрый код для обработки очень больших XML-документов.

XmlReader также обеспечивает простейший способ обработки фрагментов документа XML, например. поток элементов XML без элемента, который возвращает параметр SQL Server FOR XML RAW.

Код, который вы пишете с помощью XmlReader, как правило, очень тесно связан с форматом прочитанного XML. Использование XPath позволяет вашему коду быть намного, гораздо более слабо связан с XML, поэтому он, как правило, правильный ответ. Но когда вам нужно использовать XmlReader, вам это действительно нужно.

Ответ 5

Прежде всего, ознакомьтесь с новыми классами XDocument и XElement, поскольку они являются улучшением по сравнению с предыдущим семейством XmlDocument.

  • Они работают с LINQ
  • Они быстрее и легче.

Тем не менее, вам, возможно, придется использовать старые классы для работы с устаревшим кодом - особенно с предварительно созданными прокси. В этом случае вам нужно будет ознакомиться с некоторыми шаблонами для взаимодействия между этими классами обработки XML.

Я думаю, что ваш вопрос довольно широк и потребует слишком многого в одном ответе, чтобы дать подробности, но это первый общий ответ, который я думал, и служит началом.

Ответ 6

Если вы работаете в .NET 3.5, и вы не боитесь экспериментального кода, вы можете проверить LINQ на XSD (http://blogs.msdn.com/xmlteam/archive/2008/02/21/linq-to-xsd-alpha-0-2.aspx), который будет генерировать .NET-классы из XSD (включая встроенные правила из XSD).

Затем он имеет возможность писать прямо в файл и читать из файла, гарантируя, что он соответствует правилам XSD.

Я определенно предлагаю иметь XSD для любого документа XML, с которым вы работаете:

  • Позволяет выполнять правила в XML
  • Позволяет другим видеть, как XML будет/будет структурирован.
  • Может использоваться для проверки XML

Я нахожу, что Liquid XML Studio - отличный инструмент для создания XSD, и он бесплатный!

Ответ 7

Если вы создаете типизированный набор данных в дизайнере, вы автоматически получаете xsd, строго типизированный объект и можете загружать и сохранять xml с одной строкой кода.

Ответ 8

Мое личное мнение, как программист на С#, заключается в том, что лучший способ справиться с XML в С# - делегировать эту часть кода проекту VB.NET. В .NET 3.5 VB.NET имеет XML-литералы, которые делают работу с XML более интуитивной. См. Здесь, например:

Обзор LINQ to XML в Visual Basic

(Обязательно установите страницу для отображения кода VB, а не кода С#.)

Я бы написал остальную часть проекта в С#, но обработал XML в проекте VB с ссылкой.

Ответ 9

Запись XML с помощью класса 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>

Ответ 10

Ответ на куки хороший... но вот подробные инструкции о том, как создать строго типизированный объект из XSD (или XML) и сериализовать/десериализовать в нескольких строках кода:

Инструкции

Ответ 11

nyxtom,

Не следует ли совпадение "doc" и "xdoc" в примере 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();