使用XPATH对XML数据进行解析

这一篇我总结一下,如何利用XPATH及相关技术对XML数据文档进行查询和处理

1. 首先还是来看一下范例数据


   
   xml version="1.0" encoding="utf-8" ?>
<Orders>
    
    --所有订单-->
  <Order OrderID="1" OrderDate="2008-12-17">
     
     --一个订单-->
    <OrderItems>
      
      --订单的明细-->
      <Item>
        <ProductID>1 
       ProductID> <Quantity>2.0 
        Quantity> <UnitPrice>25.5 
         UnitPrice>  
          Item> <Item> <ProductID>2 
           ProductID> <Quantity>2.0 
            Quantity> <UnitPrice>5.5 
             UnitPrice>  
              Item> <Item> <ProductID>3 
               ProductID> <Quantity>29.0 
                Quantity> <UnitPrice>300.5 
                 UnitPrice>  
                  Item>  
                   OrderItems>  
                    Order> <Order OrderID="2" OrderDate="2009-01-01"> <OrderItems> <Item> <ProductID>1 
                     ProductID> <Quantity>2.0 
                      Quantity> <UnitPrice>25.5 
                       UnitPrice>  
                        Item>  
                         OrderItems>  
                          Order>  
                           Orders>

这是一个典型的订单数据。Orders下面可以有一个或者多个Order,每个Order有两个属性:OrderID,OrderDate,同时,每个Order都有一个或者多个OrderItem

2. 这个数据文件的架构如下


   
   xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Orders">
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="Order">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="OrderItems">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element maxOccurs="unbounded" name="Item" minOccurs="1">
                      <xs:complexType>
                        <xs:sequence>
                          <xs:element name="ProductID" type="xs:unsignedByte" />
                          <xs:element name="Quantity" type="xs:decimal" />
                          <xs:element name="UnitPrice" type="xs:decimal" />
                        
    
    xs:sequence>
                      
     
     xs:complexType>
                    
      
      xs:element>
                   
       xs:sequence>  
        xs:complexType>  
         xs:element>  
          xs:sequence> <xs:attribute name="OrderID" type="xs:unsignedByte" use="required" /> <xs:attribute name="OrderDate" type="xs:date" use="required" />  
           xs:complexType>  
            xs:element>  
             xs:sequence>  
              xs:complexType>  
               xs:element>  
                xs:schema>

3. 下面来看看,我们如何查询某个订单

需求1:查询OrderID=1的订单,显示出来它的所有OrderItem

using System;
using System.Xml;

namespace XPathSample
{
    class Program
    {
        static void Main(string[] args)
        {
            string dataFile = "../../Order.XML";

            QueryByOrderID(dataFile, "1");

            Console.Read();

        }

        static void QueryByOrderID(string file, string orderID)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(file);

            XmlNode node = doc.SelectSingleNode("/Orders/Order[@OrderID=" + orderID + "]");
            if (node != null)
            {
                Console.WriteLine("订单编号为:{0}", node.Attributes["OrderID"].Value);
                Console.WriteLine("订单日期为:{0}", node.Attributes["OrderDate"].Value);


                XmlNodeList items = node.SelectNodes("OrderItems/Item");
                if (items != null)
                {
                    Console.WriteLine("订单明细为:{0}", items.Count);
                    foreach (XmlNode n in items)
                    {
                        Console.WriteLine("产品:{0},单价:{1},数量:{2}",
                            n.SelectSingleNode("ProductID").InnerText,
                            n.SelectSingleNode("UnitPrice").InnerText,
                            n.SelectSingleNode("Quantity").InnerText
                            );
                    }
                }
            }
        }
    }
}
image 
关于更多语法,请参考 http://www.w3school.com.cn/xpath/xpath_syntax.asp

需求2:查询所有单价大于20的订单明细记录

        static void QueryByUnitPrice(string file)
        { 
            //查询所有单价大于20的订单明细记录

            XmlDocument doc = new XmlDocument();
            doc.Load(file);

            XmlNodeList list = doc.SelectNodes("//Item[UnitPrice>20]");
            if (list != null)
            {
                foreach (XmlNode node in list)
                {
                    Console.WriteLine("订单编号:{0},订购日期:{1},产品编号:{2},单价{3},数量:{4}",
                        node.ParentNode.ParentNode.Attributes["OrderID"].Value,
                        node.ParentNode.ParentNode.Attributes["OrderDate"].Value,
                        node.SelectSingleNode("ProductID").InnerText,
                        node.SelectSingleNode("UnitPrice").InnerText,
                        node.SelectSingleNode("Quantity").InnerText
                        );
                }
            }

        }
image

 

需求3:多个条件查询。我们查询单价大于20并且数量也大于20的订单明细。

XmlNodeList list = doc.SelectNodes("//Item[UnitPrice>20 and Quantity>20]");

有关其他更多的运算符,请参考http://www.w3school.com.cn/xpath/xpath_operators.asp

 

4. 如何处理命名空间的问题。

假设,我们的数据文件含有命名空间,那么在查询的时候应该如何处理呢?


   
   xml version="1.0" encoding="utf-8" ?>
<Orders xmlns:d="http://www.xizhang.com">
    
    --所有订单-->
  <d:Order OrderID="1" OrderDate="2008-12-17"> 
       --一个订单-->
    <OrderItems>
     
     --订单的明细-->
      <Item>
        <ProductID>1
      
      ProductID>
        <Quantity>2.0 
       Quantity> <UnitPrice>25.5 
        UnitPrice>  
         Item> <Item> <ProductID>2 
          ProductID> <Quantity>2.0 
           Quantity> <UnitPrice>5.5 
            UnitPrice>  
             Item> <Item> <ProductID>3 
              ProductID> <Quantity>29.0 
               Quantity> <UnitPrice>300.5 
                UnitPrice>  
                 Item>  
                  OrderItems>  
                   d:Order>  <Order OrderID="2" OrderDate="2009-01-01"> <OrderItems> <Item> <ProductID>1 
                    ProductID> <Quantity>2.0 
                     Quantity> <UnitPrice>25.5 
                      UnitPrice>  
                       Item>  
                        OrderItems>  
                         Order>  
                          Orders>
我们添加了一个命名空间,请注意,此时第一个订单(带d前缀的)和第二个订单(不带d前缀的)就不同了。
 
如果我们要查询第一个订单的所有Item,那么该如何写代码呢?
        static void QueryWithNamespace(string file)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(file);

            XmlNamespaceManager xnm = new XmlNamespaceManager(doc.NameTable);
            xnm.AddNamespace("d", "http://www.xizhang.com");

            XmlNode order = doc.SelectSingleNode("/Orders/d:Order[@OrderID=1]",xnm);
            Console.WriteLine("订单编号:{0}", order.Attributes["OrderID"].Value);
            Console.WriteLine("订单日期:{0}", order.Attributes["OrderDate"].Value);
            XmlNodeList items = order.SelectNodes("OrderItems/Item");
            if (items != null)
            {
                Console.WriteLine("订单明细为:{0}", items.Count);
                foreach (XmlNode n in items)
                {
                    Console.WriteLine("产品:{0},单价:{1},数量:{2}",
                        n.SelectSingleNode("ProductID").InnerText,
                        n.SelectSingleNode("UnitPrice").InnerText,
                        n.SelectSingleNode("Quantity").InnerText
                        );
                }
            }
        }
 
image 

 

5. 如何使用LINQ TO XML查询

LINQ TO XML是.NET 3.5中的一个重大增强,极大地方便了我们编写对XML文档的查询

要使用该功能,必须引用两个程序集(如果你当前的项目并没有使用最新的.NET Framework 3.5的话)

image

这两个程序集在如下的目录:C:/Program Files/Reference Assemblies/Microsoft/Framework/v3.5

image

出现这个警告,请点击 “是”

image

但是,仍然有个警告。要想去除这个警告,请选中该程序集,按F4

image

将“特定版本”设置为false。

这样就可以了。

然后,我们需要添加两个using语句,导入两个命名空间

using System.Linq;
using System.Xml.Linq;

编写查询的方法

        static void QueryWithNamespaceByLinq(string file)
        {
            XDocument doc = XDocument.Load(file);
            XNamespace xnamespace = "http://www.xizhang.com";

            

            var query = from order in doc.Element("Orders").Elements(xnamespace + "Order")
                        select order;

            foreach (var item in query)
            {
                Console.WriteLine("订单编号:{0}", item.Attribute("OrderID").Value);
                Console.WriteLine("订单日期:{0}", item.Attribute("OrderDate").Value);

                var items = from orderitem in item.Descendants("Item")
                            select orderitem;

                foreach (var subitem in items)
                {
                    Console.WriteLine("产品:{0},单价:{1},数量:{2}",
                        subitem.Element("ProductID").Value,
                        subitem.Element("UnitPrice").Value,
                        subitem.Element("Quantity").Value
                        );
                }

            }
        }

image

大家可能会说,这样看起来LINQ TO XML的语法并没有太多优势,因为几乎差不多。但其实LINQ TO XML还是有很多很好的特性的,例如排序,聚合,分组,联接等等,而且在构造XML文档这一方面可以说是很好,很强大。有兴趣的朋友可以参考有关的学习资料

本文由作者: 陈希章 于 2009/6/20 15:08:13 发布在: http://www.cnblogs.com/chenxizhang/
本文版权归作者所有,可以转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
更多博客文章,以及作者对于博客引用方面的完整声明以及合作方面的政策,请参考以下站点: 陈希章的博客中心
本文是使用 博客同步和管理系统自动于2009/6/20 15:08:17 从 陈希章@博客园 同步过来的。原文地址: http://www.cnblogs.com/chenxizhang/archive/2009/06/20/1507352.html ,发表于2009/6/20 7:08:00.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值