前言:BLOG开设至今尚未有实质性的文章发表,为了不至于又像本人的MSN Space一样每7个月更新一次,特逼迫自己将上个学期在学习XML时的一些收获通过自己的语言表达出来,权当滥竽充数,请各位大侠斧正。


    XML(eXtensible Markup Language),是近些年流行起来的一种语言。这种语言并非一种编程语言,而是更类似于用来编写静态网页的HTML(HyperText Markup Lanuage)语言。这从他们的名字上就可以看出来,结尾都是“标记语言”(Markup Language)。事实上,这两种语言也的确都是从SGML(Standard Generalized Markup Language)语言简化而来,导致他们都有同样的Family Name - Markup Language。这里就不更多地介绍相关的语言,而是假设各位读者已经在一定程度上掌握了XML语言的基本知识,而且也对M$的.NET开发环境有了一定的掌握。如果希望对XML语言本身有更深入的了解,请登录http://www.xml.org.cn/index.html 并查阅相关的资料。
    本BLOG并非教科书,所以我们就不必讲太多的理论知识,而是先看一下这么一个并不复杂的XML文档:

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE 手机信息 SYSTEM "手机信息.DTD">

<手机信息>
    
<手机>
        
<品牌  型号="6030">诺基亚</品牌>
        
<部分技术参数>
            
<兼容网络制式>
                
<网络制式>GSM 900</网络制式>
                
<网络制式>GSM 1800</网络制式>
            
</兼容网络制式>
            
<手机类型>直板</手机类型>
            
<体积>
                
<>104mm</>
                
<>44mm</>
                
<>18mm</>
            
</体积>
            
<重量>90克</重量>
        
</部分技术参数>
        
<售价>1150.00元</售价>
    
</手机>
    
<手机>
        
<品牌 型号="V3">摩托罗拉</品牌>
        
<部分技术参数>
            
<手机类型>折叠</手机类型>
            
<兼容网络制式>
                
<网络制式>GSM 850</网络制式>
                
<网络制式>GSM 900</网络制式>
                
<网络制式>GSM 1800</网络制式>
                
<网络制式>GSM 1900</网络制式>
            
</兼容网络制式>
            
<体积>
                
<>98mm</>
                
<>53mm</>
                
<>14mm</>
            
</体积>
            
<重量>95克</重量>
        
</部分技术参数>
        
<售价>3180.00元</售价>
    
</手机>
    
<手机>
        
<品牌 型号="SGH-D508">三星</品牌>
        
<部分技术参数>
            
<手机类型>滑盖</手机类型>
            
<兼容网络制式>
                
<网络制式>GSM 900</网络制式>
                
<网络制式>GSM 1800</网络制式>
                
<网络制式>GSM 1900</网络制式>
            
</兼容网络制式>
            
<体积>
                
<>93.5mm</>
                
<>45.7mm</>
                
<>23.5mm</>
            
</体积>
            
<重量>99克</重量>
        
</部分技术参数>
        
<售价>4380.00元</售价>
    
</手机>
</手机信息>


     如果各位博友(这么称呼貌似某指甲钳牌子)们对XML有一定了解的话,就会发现此XML文档基本包含了XML中的一些基本要素。接下来,我们就由浅入深,简单介绍一下如何在.NET环境下利用C#语言来对该XML文档进行读取。当然,在讲解之前,我还是让大家了解一下.NET环境下对XML文档进行处理的两种机制。
    一. 流模型
        流模型最早的代表应该是SAX(Simple API for XML),它是一种“推”模型。.NET环境下也有类似的(而不是相同的)处理机制,即利用XmlReader和XmlWriter对文件进行读和写。在这种处理机制下,该模型只能对XML文档进行顺序读取与写入。顺序读取/写入的意思就是说如果该对象已经读取/写入了XML文档中的某个节点,那么它就无法回过头去对之前的节点在进行读取或者修改了。这种机制类似于.NET环境下的DataReader,每次该对象只是按顺序读取一条数据库记录并把指针指向下一条记录,直到数据表结尾再无记录可读为止。如果要想再回过头去读之前的记录已经是不可能的事情了,除非再从第一条记录开始从头读取。此种机制的优点很明显,它只需要很小的内存空间,XML文档越大时优势越明显(原因在下文会进行解释),而并不需要多少额外的空间,所以说,流模型比较适合XML文档很大且并不需要进行修改的情况
    二. DOM(Document Object Model)文档对象模型
        该模型简单来说,就是将XML文档中的各节点按照一个“树”的形式存放在内存中。相信大家对于数据结构都或多或少有一些了解,我在这里就不多废话。这种模型的优点和缺点都很明显,就需要按照实际情况进行选择了。优点就是既然各节点都被放入了内存中,那么可以对XML文档中的任意一个节点进行删除以及修改操作,也可以将一个新的节点任意添加在某个位置,或是将某个节点移动到别处,同时由于这种操作都是直接在内存中完成的,所以速度很快。缺点是由于该机制要求将整个XML文档事先载入内存,所以对于非常大的文档来说,这个载入过程就可能会花去比较长的时间,而且更大的一个问题是整一个XML文档“树”在内存中所占的空间会随着文档的增大急剧增长。所以说,DOM比较适合需要处理的XML文档不太大而且又需要对该文档进行修改的情况。 

    本文先介绍如何利用XmlReader对XML文档进行读取操作,其他的相关内容会在以后的系列中推出。首先,有必要介绍一下.NET Framework中XmlReader这个类。
    事实上,XmlReader只是一个抽象类,并不能直接被用来创建一个实例,实际应用中使用的是其下的三个子类:XmlTextReader,用来读取XML文档中的节点信息;XmlNodeReader,用来对XmlNode中的数据进行顺序读取;XmlValidatingReader,用来按照预置的DTD或者Xml Schema对相应的XML文档进行有效性验证。这里将介绍的是XmlTextReader这个类:(详细信息请参考MSDN)
    I. XmlTextReader的常用属性:
            1. XmlTextReader.NodeType —— 获取当前节点的类型(返回XmlNodeType枚举型)。
            2. XmlTextReader.Value —— 获取当前节点的文本值,返回的值取决于节点的NodeType属性
            3. XmlTextReader.IsEmptyElement —— 获取一个值,该值指示当前节点是否为空元素(例如,<MyElement/>)
            4. XmlTextReader.Name —— 获取当前节点的限定名(如 ACompany:book),返回的值取决于节点的NodeType属性。
    II. XmlTextReader的常用方法:
            1. XmlTextReader.Read —— 从流中读取下一个节点。如果读取成功,返回true,如果不成功,返回false。在实际使用中通常使用while循环来遍历XML文档中的所有节点。
            2. XmlTextReader.Close —— 关闭用来读取XML文档的XmlTextReader,在读取完毕后务必调用该方法,否则极易导致“该文件被其他程序所占用”的错误。
            3. XmlTextReader.MoveToNextAttribute —— 将当前“游标”移动到当前节点的下一个属性上,若当前“游标”指向的是某个元素节点(XmlNodeType.Element),则移动到该元素的第一个属性上。若之后没有其他属性,则返回false。
            
    以下是一段C#语言编写的遍历XML文档各节点并输出相关信息的代码(修改自MSDN示例)

     本文先介绍如何利用XmlReader对XML文档进行读取操作,其他的相关内容会在以后的系列中推出。首先,有必要介绍一下.NET Framework中XmlReader这个类。    事实上,XmlReader只是一个抽象类,并不能直接被用来创建一个实例,实际应用中使用的是其下的三个子类:XmlTextReader,用来读取XML文档中的节点信息;XmlNodeReader,用来对XmlNode中的数据进行顺序读取;XmlValidatingReader,用来按照预置的DTD或者Xml Schema对相应的XML文档进行有效性验证。这里将介绍的是XmlTextReader这个类:(详细信息请参考MSDN)    I. XmlTextReader的常用属性:            1. XmlTextReader.NodeType —— 获取当前节点的类型(返回XmlNodeType枚举型)。            2. XmlTextReader.Value —— 获取当前节点的文本值,返回的值取决于节点的NodeType属性            3. XmlTextReader.IsEmptyElement —— 获取一个值,该值指示当前节点是否为空元素(例如,<MyElement/>)            4. XmlTextReader.Name —— 获取当前节点的限定名(如 ACompany:book),返回的值取决于节点的NodeType属性。    II. XmlTextReader的常用方法:            1. XmlTextReader.Read —— 从流中读取下一个节点。如果读取成功,返回true,如果不成功,返回false。在实际使用中通常使用while循环来遍历XML文档中的所有节点。            2. XmlTextReader.Close —— 关闭用来读取XML文档的XmlTextReader,在读取完毕后务必调用该方法,否则极易导致“该文件被其他程序所占用”的错误。            3. XmlTextReader.MoveToNextAttribute —— 将当前“游标”移动到当前节点的下一个属性上,若当前“游标”指向的是某个元素节点(XmlNodeType.Element),则移动到该元素的第一个属性上。若之后没有其他属性,则返回false。                以下是一段C#语言编写的遍历XML文档各节点并输出相关信息的代码(修改自MSDN示例)

using System;
using System.IO;
using System.Text;
using System.Xml;//务必注意:不要忘了引入System.Xml命名空间

public class Sample
{

    
private const String filename = "c:\\mobilephoneinfo.xml";//将要读取的文件路径(包括文件名)赋给字符串变量filename

    
public static void Main()
    
{

        XmlTextReader reader 
= null;//声明一个XmlTextReader类型的变量reader,但还未创建实例

        
try
        
{
            reader 
= new XmlTextReader(filename);
            
//通过调用构造函数,创建一个XmlTextReader实例
            reader.WhitespaceHandling = WhitespaceHandling.None;
            
//将该XmlTextReader设置为忽略文本中的空格

            
while (reader.Read())
            
//调用Read()方法,按顺序读取各节点信息 
            {
                
switch (reader.NodeType) 
                
//判断当前节点类型
                {
                    
case XmlNodeType.Element:
                        Console.Write(
"<{0}", reader.Name);
                        
while (reader.MoveToNextAttribute())
                        
{
                            Console.Write(
"{0} = \"{1}\"", reader.Name, reader.Value); 
                              //若当前节点为元素类型,则遍历当前节点中的所有属性并输出属性名及属性值
                        }

                        Console.Write(
">");
                        
//若当前节点为元素类型,则输出元素名(包含前缀),并由一对尖括号括起来。
                        break;
                    
case XmlNodeType.Text:
                        Console.Write(reader.Value);
                        
//若当前节点为文本类型,则输出相应的值
                        break;
                    
case XmlNodeType.CDATA:
                        Console.Write(
"<![CDATA[{0}]]>", reader.Value);
                        
//若当前节点为CDATA,输出相应的文本
                        break;
                    
case XmlNodeType.ProcessingInstruction:
                        Console.Write(
"<?{0} {1}?>", reader.Name, reader.Value);
                        
//若当前节点为PI(处理指令),则输出PI的名称与具体的PI的文本
                        break;
                    
case XmlNodeType.Comment:
                        Console.Write(
"<!--{0}-->", reader.Value);
                        
//若节点类型为注释,则输出注释
                        break;
                    
case XmlNodeType.XmlDeclaration:
                        Console.Write(
"<? xml {0} ?>", reader.Value);
                        
//若节点类型为Xml文档声明,则输出声明
                        break;
                    
case XmlNodeType.Document:
                        
break;
                    
case XmlNodeType.DocumentType:
                        Console.Write(
"<!DOCTYPE {0} [{1}]", reader.Name, reader.Value);
                        
//此种情况多在内部DTD中出现
                        break;
                    
case XmlNodeType.EntityReference:
                        Console.Write(reader.Name);
                        
//若当前节点为实体引用(典型的如&nbsp; &gt; 等)
                        break;
                    
case XmlNodeType.EndElement:
                        Console.Write(
"</{0}>", reader.Name);
                        
//若当前节点为结束元素,则输出元素名,并由</ 与 > 括起来
                        break;
                }

            }

        }

        
catch (Exception ex)
        
{
            Console.WriteLine(ex.ToString());
        }

        
finally
        
{
            
if (reader != null)
            
{
                reader.Close();
                
//若reader不为空,关闭reader(事先判断reader是否为空很重要,若由于某些原因reader这个实例没有被成功创建,直接调用reader的Close()方法就会出现错误。)
            }

            Console.ReadLine();
        }

    }

}
 // End class


使用该程序对之前的那个XML文档读取后显示如下(为了简单起见,没有考虑输出格式的问题)


    至此,XML文档读取完毕。若需要更详细的介绍,可以仔细参考MSDN,也可以参考:《基于XML 的 ASP.NET开发》,清华大学出版社,Dan Wahlin 著。
    下期将介绍XmlTextWriter的使用。 

posted on 2006-01-29 15:18  牛蛙  阅读(3021)  评论(3编辑  收藏  举报