[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 Freesc Huang 阅读(1953) 评论(9) 编辑 收藏

评论

#1楼 2008-02-10 15:55 qingzh[未注册用户]

收藏了,代码要是折叠一下就更好了  回复 引用   

#2楼[楼主] 2008-02-10 16:18 fox23      

谢谢,以后会注意的 :-)  回复 引用 查看   

#3楼[楼主] 2008-02-16 02:41 fox23      

改好格式,重新发了 :-)  回复 引用 查看   

#4楼 2008-02-17 18:50 黎波      

总结得很好!  回复 引用 查看   

#5楼[楼主] 2008-02-17 20:55 fox23      

@黎波
谢谢,多多交流~

 回复 引用 查看   

#6楼 2008-11-21 09:08 haihaomeiyou[未注册用户]

不错,现在也在弄这块内容。谢谢LZ了  回复 引用   

#7楼[楼主] 2008-11-21 09:27 fox23      

@haihaomeiyou
多交流
 回复 引用 查看   

#8楼 2010-09-15 13:07 龙ML      

谢谢楼主的精品文章
很好,比看某些书 好多了
 回复 引用 查看   

<2012年2月>
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910

公告

These postings are provided "AS IS" with no warranties
and confer no rights.


Locations of visitors to this page

Blog Keywords
Embedded System,Visual Studio,.Net Framework,.Net Compact Framework,.Net Micro Framework,Windows Mobile,Windows Embedded CE,Emulator,WCF,CLR,Design & Pattern,C/C++,C#,Matlab,Algorithms
昵称:Freesc Huang
园龄:4年11个月
粉丝:32
关注:4

统计

  • 随笔 - 197
  • 文章 - 0
  • 评论 - 840

搜索

 

随笔分类(227)

随笔档案(197)

Blogs

Link

积分与排名

最新评论

阅读排行榜

评论排行榜

推荐排行榜