65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 XMLDocument 和 XDocument 解析 XML 文档

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.72/5 (27投票s)

2011 年 3 月 31 日

CPOL

5分钟阅读

viewsIcon

417233

downloadIcon

7781

本文演示如何使用 "XMLDocument" 和 "XDocument" 解析 XML 文档。

引言

本文演示如何使用 "XMLDocument" 和 "XDocument" 解析 XML 文档。

背景

"XML" 和 XML 文档的解析是旧话题,我们不常直接处理 XML 文档。但偶尔,您可能会遇到需要解析一些原始 XML 文档的情况。本文旨在演示如何使用两个常用的 .NET 实用类 "XMLDocument" 和 "XDocument" 来解析 XML 文档。

Solution.JPG

随附的 Visual Studio 2010 解决方案包含两个项目

  • "XMLWebRepository" 项目是一个 ASP.NET Web 项目。此项目中的 "Student.xml" 文件是演示中使用的 XML 文件。
  • "XMLParsingExample" 项目是一个简单的 WPF "MVVM" 应用程序。我们将使用此应用程序演示如何使用 "XMLDocument" 和 "XDocument" 解析 XML 文档。

让我们首先看一下 "XMLWebRepository" 项目和 XML 文档 "Student.xml"。

要解析的 XML 文档

此演示中使用的 XML 文档位于 "XMLWebRepository" 项目中的 "Student.xml" 文件中

<?xml version="1.0" encoding="utf-8" ?>
<StudentsInformation>
  <GeneralInformation>
    <School>University of XML</School>
    <Department>Department of XML parsing</Department>
  </GeneralInformation>
  <Studentlist>
    <Student id="1" score="100" enrollment="4/30/1789"
             comment="1st and greatest president">George Washington</Student>
    <Student id="2" score="100" enrollment="3/4/1861"
             comment="Civil was. Great president!">Abraham Lincoln</Student>
    <Student id="3" score="99" enrollment="1/20/1993"
             comment="Monica Samille Lewinsky, Cool!">Bill J. Clinton</Student>
    <Student id="4" score="98" enrollment="1/20/2001" 
             comment="House price went beyond American's affordability">
		George W. Bush</Student>
    <Student id="5" score="99" enrollment="1/20/2009" comment=
             "Ridiculously low interest rate, high house price. $ worthless">
		Barack H. Obama</Student>
    <Student id="6" score="35" enrollment="4/30/2011" 
             comment="Never qualified to be the president.">Song Li</Student>
  </Studentlist>
</StudentsInformation>

如果您在解决方案资源管理器中右键单击 "Student.xml" 文件并选择 "在浏览器中查看",则会显示一个网页浏览器,如下所示

XMLInBrowser.JPG

您应该注意地址栏中的 URL "https://:7467/Student.xml"。这是 "XMLParsingExample" 项目将用于加载 XML 文档的 URL。现在让我们看一下 "XMLParsingExample" 项目,了解我们将如何使用 "XMLDocument" 和 "XDocument" 解析 "Student.xml"。

解析 XML 文档

在 "XMLParsingExample" 项目中,为了保存解析 "Student.xml" 的结果,在 "Models" 文件夹中的 "ApplicationModel.cs" 文件中创建了两个类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
 
namespace XMLParsingExample.Models
{
    public class Student
    {
        public int id { get; set; }
        public string name { get; set; }
        public int score { get; set; }
        public string enrollment { get; set; }
        public string comment { get; set; }
    }
 
    public class StudentsInformation
    {
        public string School { get; set; }
        public string Department { get; set; }
        public List<Student> Studentlist { get; set; }
 
        public StudentsInformation()
        {
            School = "N/A";
            Department = "N/A";
            Studentlist = new List<Student>();
        }
    }
}

您可能已经注意到这两个类与 "Student.xml" 文件中的信息直接相关。我们将读取 "Student.xml" 文件中的信息并将其保存到 "StudentsInformation" 类的对象中。演示如何解析 XML 文档的代码在 "Models" 文件夹中的 "XMLParsers.cs" 文件中实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
 
namespace XMLParsingExample.Models
{
    public static class XMLParsers
    {
        private static string xmlUrl = "https://:7467/Student.xml";
 
        // Parse the xml using XMLDocument class.
        public static StudentsInformation ParseByXMLDocument()
        {
            var students = new StudentsInformation();
 
            XmlDocument doc = new XmlDocument();
            doc.Load(xmlUrl);
 
            XmlNode GeneralInformationNode =
                doc.SelectSingleNode("/StudentsInformation/GeneralInformation");
            students.School =
                GeneralInformationNode.SelectSingleNode("School").InnerText;
            students.Department =
                GeneralInformationNode.SelectSingleNode("Department").InnerText;
 
            XmlNode StudentListNode =
                doc.SelectSingleNode("/StudentsInformation/Studentlist");
            XmlNodeList StudentNodeList =
                StudentListNode.SelectNodes("Student");
            foreach (XmlNode node in StudentNodeList)
            {
                Student aStudent = new Student();
                aStudent.id = Convert.ToInt16(node.Attributes
                    .GetNamedItem("id").Value);
                aStudent.name = node.InnerText;
                aStudent.score = Convert.ToInt16(node.Attributes
                    .GetNamedItem("score").Value);
                aStudent.enrollment =
                    node.Attributes.GetNamedItem("enrollment").Value;
                aStudent.comment =
                    node.Attributes.GetNamedItem("comment").Value;
 
                students.Studentlist.Add(aStudent);
            }
 
            return students;
        }
 
        // Parse the XML using XDocument class.
        public static StudentsInformation ParseByXDocument()
        {
            var students = new StudentsInformation();
 
            XDocument doc = XDocument.Load(xmlUrl);
            XElement generalElement = doc
                    .Element("StudentsInformation")
                    .Element("GeneralInformation");
            students.School = generalElement.Element("School").Value;
            students.Department = generalElement.Element("Department").Value;
 
            students.Studentlist = (from c in doc.Descendants("Student")
                           select new Student()
                           {
                               id = Convert.ToInt16(c.Attribute("id").Value),
                               name = c.Value,
                               score = Convert.ToInt16(c.Attribute("score").Value),
                               enrollment = c.Attribute("enrollment").Value,
                               comment = c.Attribute("comment").Value
                           }).ToList<Student>();
 
            return students;
        }
    }
}

静态类 "XMLParsers" 实现了两个静态方法

  • "ParseByXMLDocument" 方法演示如何使用 "XMLDocument" 解析 XML 文档。
  • "ParseByXDocument" 方法演示如何使用 "XDocument" 解析 XML 文档。

这两个方法非常相似,但是 "LINQ" 风格的 "XDocument" 使我们能够节省几行 C# 代码。这两个方法都非常简单,您阅读它们应该不会有太多问题。如果您只对如何解析 XML 文档感兴趣,可以跳过本文的其余部分。但是为了使此演示成为一个“运行”示例,我将对 "XMLParsingExample" 项目进行简要的总体介绍。

"XMLParsingExample" 应用程序

"XMLParsingExample" 项目是一个 WPF MVVM 应用程序。我有一篇专门的文章 "Silverlight MVVM 应用程序的数据和命令绑定" 来讨论如何在 MVVM 应用程序中实现数据和命令绑定。如果您感兴趣,可以查看它,这将使您阅读本文的其余部分更容易。为了帮助实现 "XMLParsingExample" 应用程序,我在 "MVVMUtilities" 文件夹中的 "BindingUtilities.cs" 文件中实现了两个实用类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.ComponentModel;
using System.Windows.Input;
 
namespace XMLParsingExample.MVVMUtilities
{
    public abstract class ViewModelBase
        : DependencyObject, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
 
        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
 
    public class RelayCommand : ICommand
    {
        private readonly Action handler;
        private bool isEnabled;
 
        public RelayCommand(Action handler)
        {
            this.handler = handler;
        }
 
        public bool IsEnabled
        {
            get { return isEnabled; }
            set
            {
                if (value != isEnabled)
                {
                    isEnabled = value;
                    if (CanExecuteChanged != null)
                    {
                        CanExecuteChanged(this, EventArgs.Empty);
                    }
                }
            }
        }
 
        public bool CanExecute(object parameter)
        {
            return IsEnabled;
        }
 
        public event EventHandler CanExecuteChanged;
 
        public void Execute(object parameter)
        {
            handler();
        }
    }
}

"ViewModelBase" 类将是 MVVM 应用程序中所有视图模型的基类,"RelayCommand" 类将用于在视图模型中实现 "命令"。 "XMLParsingExample" 应用程序的简单视图模型在 "ViewModels" 文件夹中的 "MainWindowViewModel.cs" 文件中实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XMLParsingExample.MVVMUtilities;
using XMLParsingExample.Models;
 
namespace XMLParsingExample.ViewModels
{
    class MainWindowViewModel : ViewModelBase
    {
        // Properties
        private StudentsInformation studentInformation;
        public StudentsInformation StudentInformationObject
        {
            get { return studentInformation; }
            private set
            {
                studentInformation = value;
                NotifyPropertyChanged("StudentInformationObject");
            }
        }
 
        private void InitiateState()
        {
            studentInformation = new StudentsInformation();
        }
 
        // Commands
        public RelayCommand ClearResultCommand { get; private set; }
        private void ClearResult()
        {
            StudentInformationObject = new StudentsInformation();
        }
 
        public RelayCommand XMLDocumentLoadCommand { get; private set; }
        private void XMLDocumentLoad()
        {
            StudentInformationObject = XMLParsers.ParseByXMLDocument();
        }
 
        public RelayCommand XDocumentLoadCommand { get; private set; }
        private void XDocumentLoad()
        {
            StudentInformationObject = XMLParsers.ParseByXDocument();
        }
 
        private void WireCommands()
        {
            ClearResultCommand = new RelayCommand(ClearResult);
            ClearResultCommand.IsEnabled = true;
 
            XMLDocumentLoadCommand = new RelayCommand(XMLDocumentLoad);
            XMLDocumentLoadCommand.IsEnabled = true;
 
            XDocumentLoadCommand = new RelayCommand(XDocumentLoad);
            XDocumentLoadCommand.IsEnabled = true;
        }
 
        // Constructor
        public MainWindowViewModel()
        {
            InitiateState();
            WireCommands();
        }
    }
}

此视图模型类实现了一个公共属性和三个命令

  • "StudentInformationObject" 属性用于保存解析 "Student.xml" 文件获得的信息。
  • "XMLDocumentLoadCommand" 命令通过调用 "XMLParsers" 类中的 "ParseByXMLDocument" 方法,使用 "XMLDocument" 解析 "Student.xml" 文件。
  • "XDocumentLoadCommand" 命令通过调用 "XMLParsers" 类中的 "ParseByXDocument" 方法,使用 "XDocument" 解析 "Student.xml" 文件。
  • "ClearResultCommand" 命令清除 "StudentInformationObject" 属性。

此视图模型绑定到 "MainWindow.xaml" 视图

<Window x:Class="XMLParsingExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="XML Parsing Example" Icon="Images\Tiger-icon.png"
        FontFamily="Verdana" FontSize="12">
 
    <Window.DataContext>
        <Binding Source="{StaticResource MainWindowViewModel}" />
    </Window.DataContext>
 
    <Grid Margin="8">
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
 
        <Border Grid.Row="0" BorderThickness="1" BorderBrush="Brown"
                CornerRadius="6">
            <TextBlock Margin="15, 5, 5, 5" FontSize="18"
                       FontWeight="SemiBold" Foreground="#666666"
                       Text="XML Parsing Example"></TextBlock>
        </Border>
 
        <Border Grid.Row="1" BorderThickness="1" BorderBrush="Black"
                Margin="0,5,0,0">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="auto" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                
                <StackPanel Grid.Row="0" Orientation="Horizontal"
                            HorizontalAlignment="Right" Margin="6">
                    <Button Content="Parse XML with XMLDocument"
                            Command="{Binding Path=XMLDocumentLoadCommand}"
                            Margin="0, 0, 5, 0" />
                    <Button Content="Parse XML with XDocument"
                            Command="{Binding Path=XDocumentLoadCommand}"
                            Margin="0, 0, 5, 0" />
                    <Button Content="Clear result"
                            Command="{Binding Path=ClearResultCommand}" />
                </StackPanel>
 
                <Border Grid.Row="1" BorderThickness="1"
                        BorderBrush="Blue" Margin="5">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="auto" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        
                        <StackPanel Grid.Row="0"
                                    Orientation="Horizontal" Margin="5">
                            <TextBlock FontWeight="SemiBold">School:</TextBlock>
                            <TextBlock Margin="5, 0, 0, 0" Foreground="Green"
                                Text="{Binding Path=StudentInformationObject.School
                                , Mode=OneWay}" />
                            <TextBlock Margin="0, 0, 5, 0">,</TextBlock>
                            <TextBlock FontWeight="SemiBold">Department:</TextBlock>
                            <TextBlock Margin="5, 0, 0, 0" Foreground="Green"
                                Text="{Binding Path=StudentInformationObject.Department
                                , Mode=OneWay}" />
                        </StackPanel>
 
                        <DataGrid Grid.Row="1" Margin="5"
                                  IsReadOnly="True" ColumnHeaderHeight="30"
                              ItemsSource="{Binding Path=
				StudentInformationObject.Studentlist
                            , Mode=OneWay}" />
                    </Grid>
                </Border>
            </Grid>
        </Border> 
    </Grid>
</Window>

此 XAML 视图中有三个 "按钮"。每个按钮都绑定到视图模型中相应的命令。数据网格绑定到 "StudentInformationObject" 属性的 "Studentlist"。视图模型实例本身绑定到此 XAML 视图的 "DataContext" 作为 "StaticResource"。视图模型类的此实例在 "App.xaml" 文件中定义

<Application x:Class="XMLParsingExample.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:VM="clr-namespace:XMLParsingExample.ViewModels"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <VM:MainWindowViewModel x:Name="MainWindowViewModel" 
		x:Key="MainWindowViewModel" />
    </Application.Resources>
</Application>

现在我们完成了这个演示应用程序,我们可以开始测试运行它。

运行应用程序

将 "XMLParsingExample" 项目设置为启动项目,我们可以在调试模式下运行应用程序。应用程序启动后,我们可以单击按钮来测试应用程序。下图显示了单击 "使用 XDocument 解析 XML" 按钮时的结果。

RunApplication.JPG

关注点

  • 本文演示了如何使用 "XMLDocument" 和 "XDocument" 解析 XML 文档。
  • 为了使此演示成为一个“运行”示例,我创建了一个 WPF MVVM 应用程序。如果您只对如何解析 XML 文档感兴趣,可以跳过 WPF 应用程序的介绍。如果您不太熟悉如何创建 MVVM 应用程序,可以查看我的早期文章 "Silverlight MVVM 应用程序的数据和命令绑定"。
  • XML 和 XML 文档的解析现在是非常老的话题。您应该不常需要直接处理原始 XML 文档。但是当您需要这样做时,本文提供了一个“运行”示例,说明如何使用 "XMLDocument" 和 "XDocument" 解析 XML 文档。
  • 在功能方面,"XMLDocument" 与 "LINQ" 风格的 "XDocument" 非常相似。选择哪一个由您自己决定。根据此链接,"XMLDocument" 不适用于 Silverlight 应用程序。因此,如果您正在使用 Silverlight 应用程序,则需要使用 "XDocument"。
  • 在我完成这篇文章时,我注意到 "Student.xml" 文件中有一个错字。我本想对林肯总统说“内战。伟大的总统!”(Civil war. Great president!),但我写成了“内战。(Civil was.) 伟大的总统!”。我希望这不会影响您阅读本文。我将来会更好地校对我的帖子。
  • 我希望您喜欢我的文章,希望本文能以某种方式帮助您。

历史

  • 这是本文的第一个修订版。
© . All rights reserved.