Як поводитися з XML на C #


85

Який найкращий спосіб мати справу з XML-документами, XSD тощо в C # 2.0?

Які класи використовувати тощо. Які найкращі практики аналізу та створення XML-документів тощо

РЕДАГУВАТИ: .Net 3.5 пропозиції також вітаються.


Для тих, хто також намагається знайти більш дієве рішення, ігноруйте це. Це стара бібліотека .NET. Замість цього використовуйте XDocument, і ви врятуєте розчаровані очі
AER

Відповіді:


178

Основний засіб читання та письма на 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


3
Можливо, ви хочете зазначити, що ви використовуєте XDocument в останньому прикладі, оскільки XDocument зовсім відрізняється від XmlDocument
Аарон Пауелл,

2
Корекція; немає С # 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 мають властивість Schemas, яке можна використовувати для перевірки xsd (або dtd).

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

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

Нарешті, для маніпулювання xml ви можете використовувати XslCompiledTransform (шар xslt).

Альтернативою роботі з xml є робота з об’єктною моделлю; Ви можете використовувати xsd.exe для створення класів, що представляють xsd-сумісну модель, і просто завантажити xml як об'єкти , маніпулювати ним за допомогою OO, а потім знову серіалізувати ці об'єкти; ви робите це за допомогою XmlSerializer .


Для маніпулювання (додавання / доповнення елементів) великим XML-документом (40 тис. Рядків). Який найкращий спосіб? Раніше я використовував LINQ-to-XML.
Neyoh

12

Відповідь 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 за раз. Це, по суті, відповідь .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 тощо) чудові, але ОП запитав про 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's. Вони також дуже дружні з базами даних.
Користувач1

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

Відповідь Cookey хороша ... але ось докладні інструкції про те, як створити сильно набраний об'єкт із XSD (або XML) та серіалізувати / десеріалізувати в декількох рядках коду:

Інструкції


"Сторінка, яку ви шукали, не існує." :(
Ian Grainger

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
...
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.