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

85

Как лучше всего работать с XML-документами, XSD и т. Д. В C # 2.0?

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

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

Малик Дауд Ахмад Хохар
источник
Игнорируйте это тем, кто также пытается найти более работоспособное решение. Это старая библиотека .NET. Вместо этого используйте XDocument, и вы спасете, выколачивая глаза от разочарования
AER

Ответы:

177

Основные средства чтения и записи в C # 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 на каждом узле (ОБНОВЛЕНИЕ 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

Nyxtom
источник
3
Вы можете указать, что вы используете XDocument в последнем примере, поскольку XDocument сильно отличается от XmlDocument
Аарон Пауэлл,
2
Исправление; нет C # 3.5; вы имеете в виду .NET 3.5 и C # 3.0
Марк Грейвелл
о, и «на лету» [инициализаторы объектов] будут работать в основном одинаково с C # 3.0 и XmlDocument - все же хороший ответ, хотя (+1)
Марк Грейвелл
Возможно, стоит упомянуть, что если вы загружаете документ для запроса с помощью XPath (а не для редактирования), то использование XPathDocument будет намного эффективнее,
Оливер Халлам,
Выполняется ли проверка схемы узел за узлом? Если нет, есть ли способ сделать это узел за узлом?
Малик Дауд Ахмад Хохар
30

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

То же самое применимо и к написанию xml, но при этом следует отметить, что компоновка содержимого с помощью LINQ-to-XML (XDocument) немного проще, чем с помощью более старого XmlDocument.

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

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

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

Марк Гравелл
источник
Для управления (добавления / поддержки элементов) большим XML-документом (40 тыс. Строк). Какой лучший способ? Раньше я использовал LINQ-to-XML.
Neyoh
12

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

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

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

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

К сожалению, XDocumentи XElement( XNodeи XObject) не реализуют IXPathNavigable.

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

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

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

Роберт Россни
источник
3
Обратите внимание, что существует метод расширения XPathNavigator CreateNavigator(this XNode node)для создания XPathNavigatorиз XNode(который включает производный класс XDocument).
Дэйв
5

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

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

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

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

торопиться
источник
Я согласен, что они (XDocument и т. Д.) Великолепны, но OP спросил о C # 2.0.
Марк Грейвелл
2

Если вы работаете в .NET 3.5 и не боитесь экспериментального кода, вы можете проверить LINQ to 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, и он бесплатный!

Аарон Пауэлл
источник
2

Написание 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>
Анил Ратод
источник
1

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

Питер С
источник
Я добился большого успеха с DataSet. Они также очень дружелюбны с базами данных.
User1
1

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

Обзор LINQ to XML в Visual Basic

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

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

Райан Ланди
источник
Переходить на vb только для XML-литерала не стоит. XML работает только с литералами. Если xml передается в качестве параметра, поддержка литерала XML не дает вам особых преимуществ. Вместо этого устаревший синтаксис vb.net испортит приятный опыт программирования на C #.
Gqqnbig
0

Никстом

Разве «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();
мокумаксКрэйг
источник
Я отправил на утверждение ответ, на который вы ссылаетесь, однако это действительно должен был быть комментарий, а не ответ.
Дэвид Томпсон
Спасибо, Дэвид. Согласен, в то время это не позволяло мне комментировать. Не знаю почему.
mokumaxCraig
0

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

инструкции

Стив Хорн
источник
«Страница, которую вы искали, не существует». :(
Ян Грейнджер
0

Если вам когда-нибудь понадобится преобразовать данные между XmlNode<=> XNode<=> XElement
(например, чтобы использовать LINQ), эти расширения могут быть вам полезны:

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

Применение:

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
...
Майкл Хаттер
источник