[CF Skills]XML on Windows Mobile (C#)

摘要
Windows Mobile上的XML相关类,并利用它们高效地操作XML文件()

Keywords
.Net Compact Framework, Windows Mobile, XML

两年以前张欣同学曾经做过一期Webcast谈到了这相关的内容,详见:
http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?
EventID=1032328201&EventCategory=3&culture=zh-CN&CountryCode=CN

本文主要涉及一些Webcast里面没有说到的东西,关于XML本身的语法和用法我就不在此赘述了,首先,我们来看一看 .NET Compact Framework System.XML这个命名空间下,为我们操作XML提供了哪些类型支持:

类名

说明

XmlReader

抽象类,提供了快速,单向,只读的读取XML文件流操作

XmlWriter

抽象类,为生成一个XML文件流提供了接口

XmlTextReader

继承于XmlReader,用于格式良好的XML文本处理

XmlTextWriter

XmlWriter的一个实现类

XmlNodeReader

公共类,用于处理内存中的XML DOM Tree

XmlNodeWriter

公共类,用于在内存中产生XML DOM Tree

XmlDocument

一个XML DOM Tree的模板类

呃,先来看那个名字跟其他几个类不太一样的吧:XmlDocument.
XmlDocument 用于把XML文件加载到内存中间。调用Load()方法即可将XML文件作为一个数据树加载到内存。Load()方法提供了几个重载,你可以通过文件名,任意流,或从XmlReader继承的类以及System.IO.StreamReaderTextReaderLoad。这里需要区别一下的是另一个方法LoadXml(),它是用来加载Xml字符串的,而不是文件!
下面的例子是从XmlTextReaderLoad 一个XML文件:

 XmlDocument xmldoc = new XmlDocument();
 XmlTextReader xmlRdr 
= new XmlTextReader(@""Storage Card"books.xml"
);
xmlRdr.WhiteSpaceHandling 
=
 WhiteSpaceHandling.None;
xdoc.Load(xmlRdr);

这里提到了XmlTextReader 这个类,可以说XmlTextReader XmlReader在细粒度控制方面的一个实现。XmlTextReader 包含了当前节点的位置信息。调用它的Read()方法,讲从文件中读取下一个节点的信息,读取顺序是深度优先的。通常,在读取数据之初,我们会调用MoveToContent() 去跳过一些非数据的元素段,直接到达根节点处,调用Skip()方法会跳过当前界点的所有分节点,这在检索节点的时候可能会用得到,可以跳过一些不必要的子节点而节约一点性能,但是对设备上小规模的XML文件,这个效果往往不是太明显。不过显然可以理解,这种不需要加载整个文件的单向的读写方式,要比使用XmlDocument对象要快得多~

说到性能,对于资源有限的设备来说,这显然是不可忽略的一点,在操作XML的时候,我们也应考虑到这一点,在使用XmlReaderXmlWriter的时候,可以使用XmlReaderSettingsXmlWriterSettings来调整性能,例如使用IgnoreWhiteSpace来忽略空白字符,或着使用IgnoreComments来忽略注释行等等,

另外需要注意的是,如果我们使用XmlReader来读取的时候要避免使用Schema,因为在单向读取的时候,Schema的校验会损失一部分性能,而用DataSet来读取的时候,尽量使文件包含Schema来确定表结构,这样读起来会比较快,不需要编译器来为Dataset创建架构。

从细粒度方面考虑,可以用MoveToAttribute()来设置XmlReader的访问点,访问各个属性。例如
public void ShowAttributes(XmlReader reader)
{
 
if
 (reader.HasAttributes)
 
{
    Console.WriteLine(
"Attributes of <" + reader.Name + ">"
);
    
for (int i = 0; i < reader.AttributeCount; i++
)
    
{
      reader.MoveToAttribute(i);
      Console.WriteLine(reader.Name
+"::"+
reader.Value);
    }

      reader.MoveToElement(); 
//属性访问完毕后让reader返回到元素节点上来
  }

}
XmlNodeReader
XmlNodeWriter XmlNode提供了快速非缓存的访问方式,可以直接从XmlStream获取信息。
好,再来看一个例子
<?xml version='1.0'?>
<!-- Some of Wrox books in the book database -->
<bookstore>
<book Section=" XML" PublicationDate="2004" ISBN="0-7645-7077-3">
<title>Beginning XML, 3rd Edition</title>   <author>
<first-name>David</first-name>
<last-name>Hunter</last-name>
</author>
<price>39.99</price>
</book>
 
<book Section=" Java" PublicationDate="2004" ISBN="0-7645-6874-4">
    
<title>Ivor Horton's Beginning Java 2, JDK 5 Edition</title>
    
<author>
      
<first-name>Ivor</first-name>
      
<last-name>Horton</last-name>
    
</author>
    
<price>49.99</price>
 
</book>

 
<book Section=" Database" PublicationDate="2005" ISBN="0-7645-7950-9">
    
<title>Beginning MySQL</title>
    
<author>
      
<first-name>Robert</first-name>
      
<last-name>Sheldon</last-name>
    
</author>
    
<author>
      
<first-name>Geoff</first-name>
      
<last-name>Moes</last-name>
    
</author>
    
<price>39.99</price>
 
</book>
</bookstore>

1) 使用 XmlTextReader

这个XML文件包含了几本书(book)的相关信息,书有分元素titleauthorprize和属性SectionPublicationDateISBN。我现在想做的事情就是把这个XML文件的内容按照我预定的格式打印出来,并存放到一个output.txt文本文件里面:

首先,我们定义两个用于读写的readerwriter

        XmlTextReader reader = null;
        StreamWriter writer 
= null;

在处理函数里面,首先我们做一个初始化:

        writer = newStreamWriter(@""Storage Card"output.txt",false);
        reader 
= newXmlTextReader(@""Storage Card"books.xml");

reader在读的时候

        while (reader.Read())
                
{
          
//XmlNodeType这个枚举让我们方便的对不同类型的节点进行相应的操作

                switch (reader.NodeType)
                    
{
                      caseXmlNodeType.XmlDeclaration:
                          FormatOutput(writer, reader, 
"XmlDeclaration"
);
                          
break
;
                      caseXmlNodeType.ProcessingInstruction:
                          FormatOutput(writer, reader, 
"ProcessingInstruction"
);
                          
break
;
                      caseXmlNodeType.DocumentType:
                          FormatOutput(writer, reader, 
"DocumentType"
);
                          
break
;
                      caseXmlNodeType.Comment:
                            FormatOutput(writer, reader, 
"Comment"
);
                            
break
;
                        caseXmlNodeType.Element:
                          FormatOutput(writer, reader, 
"Element"
);
                            
break
;
                        caseXmlNodeType.Text:
                            FormatOutput(writer, reader, 
"Text"
);
                            
break
;
                        caseXmlNodeType.Whitespace:
                          
break
;
                    }


以下是FormatOutput函数:

      privatestaticvoid FormatOutput(StreamWriter writer, XmlReader reader, String nodeType)
        
{
            
//用tab使输出的层次分明一点

            for (int i = 0; i < reader.Depth; i++)
            
{
                writer.Write(
'"t'
);
            }

            
//这里并没有做过多的判断,但是作为Element的节点并没有Value
            if (reader.Name != String.Empty)
                writer.WriteLine(reader.Prefix 
+ nodeType + "<" + reader.Name + ">:" +
 reader.Value);
            
else

                writer.WriteLine(reader.Prefix 
+ nodeType + "" + reader.Value);
            
// 显示当前节点的属性名和值,同样用tab做了格式控制      

          while (reader.MoveToNextAttribute())
            
{
                
for (int i = 0; i < reader.Depth; i++
)
                    writer.Write(
'"t'
);
                writer.WriteLine(
"Attribute: " + reader.Name + "" +
 reader.Value);
            }

        }


程序界面;


输出效果
XmlDeclaration<xml>:version='1.0'
Attribute: version= 1.
Comment: Some of Wrox books in the book database
Element<bookstore>:
         Element<book>:
                   Attribute: Section= XML
                   Attribute: PublicationDate= 2004
                   Attribute: ISBN= 0-7645-7077-3
                   Element<title>:
                            Text: Beginning XML, 3rd Edition
                   Element<author>:
                            Element<first-name>:
                                     Text: David
                            Element<last-name>:
                                     Text: Hunter
                   Element<price>:
                            Text: 39.99
         Element<book>:
                   Attribute: Section= Java
                   Attribute: PublicationDate= 2004
                   Attribute: ISBN= 0-7645-6874-4
                   Element<title>:
                            Text: Ivor Horton's Beginning Java 2, JDK 5 Edition
                   Element<author>:
                            Element<first-name>:
                                     Text: Ivor
                            Element<last-name>:
                                     Text: Horton
                   Element<price>:
                            Text: 49.99
         Element<book>:
                   Attribute: Section= Database
                   Attribute: PublicationDate= 2005
                   Attribute: ISBN= 0-7645-7950-9
                   Element<title>:
                            Text: Beginning MySQL
                   Element<author>:
                            Element<first-name>:
                                     Text: Robert
                            Element<last-name>:
                                     Text: Sheldon
                   Element<author>:
                            Element<first-name>:
                                     Text: Geoff
                            Element<last-name>:
                                     Text: Moes
                   Element<price>:
                            Text: 39.99

2) 使用 DataSet

跟在PC机上一样,在面临复杂数据交互,需要充分利用数据间的相互关系的时候,单向运行的XmlReader就有些不够用了,因为它不保存“流过去”的信息,做过ADO.NET的人对DataSet应该不会陌生,跟XmlReader不同,DataSet就是一个常驻内存的关系型数据库。DataSet里面的数据即可以来自关系型数据库又可以来自XML文件()。下面的意思演示了如何从DataSet加载XML并在DataGrid上面显示出来:

  1        DataTable dt1 = null;
  2        DataTable dt2 = null
;
  3        DataSet ds = null
;
  4        int
 CurrentTable ;
  5        public
 Form2()
  6        
{
  7
            InitializeComponent();
  8        }

  9
 10        private void
 LoadData()
 11        
{
 12            int
 loadTimeSpan;
 13
            
 14            XmlDocument doc = new
 XmlDocument();
 15            try

 16            {
 17               int t1=
 System.Environment.TickCount;
 18                //将XML文件读入内存

 19                doc.Load(@"\Storage Card\books.xml");
 20                int t2 =
 System.Environment.TickCount;
 21                loadTimeSpan = t2 -
 t1;
 22                MessageBox.Show("LoadDocTimeSpan:"+
loadTimeSpan);
 23            }

 24            catch (XmlException ex)
 25            
{
 26
                MessageBox.Show(ex.Message);
 27                return
;
 28            }

 29            Cursor.Current = Cursors.WaitCursor;
 30            //通过XmlNodeReader把XmlDocument中的数据填充到dataSet中去

 31            XmlNodeReader reader = new XmlNodeReader(doc);
 32            int
 DataSetFillSpan;
 33             ds = new
 DataSet();
 34                    int t3 =
 System.Environment.TickCount;
 35
            ds.ReadXml(reader);
 36            int t4 =
 System.Environment.TickCount;
 37            DataSetFillSpan = t4 -
 t3;
 38
            reader.Close();
 39

 40            //因为XML文件里面存在Book和Author的一对多的主从表

 41            dt1 = ds.Tables[0];
 42            dt2 = ds.Tables[1
]; 
 43            //设置默认显示的表

 44            DG_Book.DataSource = ds.Tables[0].DefaultView;
 45            CurrentTable = 0
;
 46            Cursor.Current =
 Cursors.Default;
 47            MessageBox.Show("Fill dataset timeSpan:"+
DataSetFillSpan);
 48        }

 49
 50        private void Form2_Load(object
 sender, EventArgs e)
 51        
{
 52
            LoadData();
 53        }

 54
 55        
/// <summary>
 56        /// 显示特定行的信息
 57        /// </summary>

 58        /// <param name="bookIndex">行号</param>

 59        private void DisplayDataRow(int bookIndex)
 60        
{
 61            String line =
 String.Empty;
 62            DataTable dt = CurrentTable == 0 ?
 dt1 : dt2;
 63

 64            DataRow dr =
 dt.Rows[bookIndex];
 65
            
 66            int col = 0
;
 67            foreach (object value in
 dr.ItemArray)
 68            
{
 69                line += (dt.Columns[col].ColumnName + "" +

 70                    value.ToString() + "\r\n");
 71                col++
;
 72            }

 73            MessageBox.Show(line);
 74        }

 75
 76        private void menuItem3_Click(object
 sender, EventArgs e)
 77        
{
 78            int bookIndex =
 DG_Book.CurrentRowIndex;
 79
            DisplayDataRow(bookIndex);
 80        }

 81
 82        private void menuItem4_Click(object
 sender, EventArgs e)
 83        
{
 84
            SwitchTable();
 85        }

 86
 87        private void menuItem5_Click(object
 sender, EventArgs e)
 88        
{
 89
            SwitchTable();
 90        }

 91
 92        
/// <summary>
 93        /// 在两个表之间切换显示
 94        /// </summary>

 95        private void SwitchTable()
 96        
{
 97            if (CurrentTable == 0
)
 98            
{
 99                DG_Book.DataSource =
 dt2.DefaultView;
100                CurrentTable = 1
;
101                this.Text = "Author Table:"
;
102            }

103            else
104            {
105                DG_Book.DataSource =
 dt1.DefaultView;
106                CurrentTable = 0
;
107                this.Text = "Book Table:"
;
108            }

109        }

110
111        private void menuItem1_Click(object
 sender, EventArgs e)
112        
{
113            //关闭的时候输出带Schema的XML文件

114            if (ds != null)
115            
{
116                ds.WriteXml(@"\Storage Card\bookstore.xml"
, XmlWriteMode.WriteSchema);             
117                //ds.WriteXmlSchema(@"\Storage Card\bookstore.xsd");

118            }

119            Application.Exit();
120        }

程序效果:

最后有一点是要强调的是,在使用DataSet的时候,一定要考虑的数据量的大小,可能超过2K以上的数据加载的时候速度就有点不能忍受了。我在模拟器上测试用的不到1k的数据生成XmlDocument用了1.5秒,填充DataSet用了8秒多,当然在设备上还是要比这快一些。
完整代码点此处下载

Freesc Huang( a.k.a fox23)@HUST all rights reserved
2007-10-10

 

posted on 2008-02-16 02:39  J.D Huang  阅读(2675)  评论(8编辑  收藏  举报