访问XML的方法
昨天用wpf的时候要访问xml,弄了很久,所以记录一下。
C#3.0提供了轻型的XmlReader、XmlWriter类和完全文档对象模式(DOM)的XmlDocument类。这也是我昨天郁闷半天的原因。以前用过XmlTextReader,也没搞太懂,就是找到了方法,贴上代码。看懂下了事。
在这个博客可以找到原理:http://www.cnblogs.com/xdesigner/archive/2008/05/15/1198398.html
整个博客可以看到xml操作方法:http://www.cnblogs.com/surfsky/archive/2007/03/13/673625.html
先上原理:
XmlReader是流式处理模型,所谓流式处理是指将XML文档当做一个数据流来进行处理,逐个处理XML文档中的数据。这种模型下,读取快,内存占用少,性能也就好。它的缺点也明显(昨天我就是在这上面闷了很久):1.只能读取不能修改;2.不能使用XPath技术;3.接口简单,处理方法比较少。
System.Xml空间
以下类适合快速流式读写XML文件(注:DOM适合随机读写)
XmlReader, XmlWriter,
XmlTextReader, XmlTextWriter
XmlValidatingReader, XmlValidatingWriter 添加了DTD和模式验证,因此提供了数据的有效性验证
XmlNodeReader, XmlNodeWriter 把XmlNode作为其源
XmlDocument是DOM处理模型,使用文档对象模型的思想解析整个XML文档,在内存中生成一个对象树来表述XML文档。可以使用XmlElement对象来影射XML文档中的一个元素,使用XmlAttribute对象来影射到XML文档中的一个属性。这样通过编程可以方便的操作XML,比如递归遍历XML文档的一部分或全部,可以像树状结构插入,修改或删除XML元素,可以设置XML元素的属性。
在DOM模式下,我们可以使用XPath技术在XML文档树状结构中进行快速检索和定位,这为处理XML文档带来比较大的方便。
经常用到的几个DOM的类型;
XmlNode 是DOM结构中的所有类型的基础类型,它定义了所有XML节点的通用属性和方法,是XMLDOM的基础。它具有一个ChildNodes属性,表示它所包含的子XML节点。
XmlAttribute 表示XML属性,它只保存在XmlElement的Attributes 列表中。
XmlDocument表示XML文档本身,是XMLDOM模型中的顶级对象,它用于对XML文档进行整体的控制,并且是其它程序访问XML文档对象树的唯一入口。
XmlLinkedNode在XmlNode的基础上实现了访问前后同级节点的方法。
XmlElement元素表示XML元素。是XMLDOM中使用最多的对象类型。它具有Attributes属性可以处理它所拥有的属性,可以使用ChildNodes属性获得它所有的子节点。并提供了一些添加和删除子节点的方法。
下面看一张XDocument的(有个问题想问,XDocument和XElement的关系是?):
再上建议:
使用XmlDocument:1.传统的DOM方法适用。2.所需的整个文档皆在内存中。3.必须在内存中向前或向后遍历以及更新。
使用XmlReader/XmlWriter:1.必须适用流方法。2.必须要求进行最快的处理。3.要处理较大的文档并且无法一次性加载全部文档。
使用XElement/XDocument:1.用代码构建xml声明。2.LINQ的查询能力有助于流方法。3.需要一种针对大多数开发人员的更易读的XML编程语法。
4.要求使用查语义在内存中遍历。
博文后面的代码比较多,我只说我用到的。
XmlReader有个很经典的:
XmlReader reader = xDoc.CreateRedaer(); reader.Settings.CheckCharacters = true; int level = 0; while(reader.Reader()) { switch(reader.NodeType) { case XmlNodeType: Display(level,"CDATA:{0}",reader.Value); break; case XmlNodeType.Comment: Display(level,"Comment:{0}",reader.Value); break; case XmlNodeType.DocumentType: Display(level,"DOCTYPE:{0}= {1}",reader.Name,reader.Value); break; case XmlNodeType.Element: Display(level,"Element:{0}",reader.Name); level++; while(reader.MoveToNextAttribute()) { Display(level,"ATTRIBUTE: {0}='{1}'",reader.Name,reader.Value); } break; case XmlNodeType.EndElement; level--; break; case XmlNodeType.EntityReference: Display(level,"ENTITY:{0}",reader.Name); break; case XmlNodeType.ProcessingInstruction: Display(level,"INSTRUCTION: {0}={1}",reader.Value); break; case XmlNodeType.Text; Display(level,"TEXT:{0}",reader.Value); break; case XmlNodeType.XmlDeclaration: Display(level,"DECLARATION: {0}={1}",reader.Value); break; } } static void Display(int indentLevel,string format,params object[] args) { for(int i=0;i<indentLevel;i++) Console.Write(" "); Console.WriteLine(format,args) }
XDocument的(网上有更详细的,这个是我为了解决自己的问题写的,主要是遍历某个节点下的全部子节点):
XmlDocument xmldoc = new XmlDocument(); xmldoc.Load(filePath); XmlNodeList topM = xmldoc.DocumentElement.ChildNodes; foreach (XmlElement element in topM) { if(element.Name=="Vocabulary") { XmlNodeList nodelist = element.ChildNodes; Model.Vocabulary vocabulary = new Model.Vocabulary(); foreach (XmlElement el in nodelist) { if (el.Name == "Word") vocabulary.Word = el.InnerText; else if (el.Name == "Explain") vocabulary.Explain = el.InnerText; else if (el.Name == "IsLastSelected") vocabulary.IsLastSelected = el.InnerText=="0"?false:true; } vocabularies.Add(vocabulary); }OK,先到这里,以后碰到问题再补上增删的。
继续:
关于linq to xml的,关于Descentdants函数。具体可以参看:http://www.programbbs.com/doc/4564.htm
Desentdants英文意思是后代,晚辈。也就是这个函数是用于获得某个Element下的指定子Element。
foreach (XElement elem in doc.Elements(\"Customers\").Descendants(\"Customer\")) { Console.WriteLine(string.Format( \"Customer ID : {0}, Name : {1}, Address : {2}\", elem.Attribute(\"ID\").Value, elem.Attribute(\"Name\").Value, elem.Attribute(\"Address\").Value) ); }<?xml version=\"1.0\" encoding=\"utf-8\"?> <Customers> <Customer ID=\"A0001\" Name=\"Tom\" Address=\"Taipen\" /> <Customer ID=\"A0002\" Name=\"Mary\" Address=\"LD\" /> <Customer ID=\"A0003\" Name=\"Jeff\" Address=\"YW\" /> </Customers>
特别的,当xml中包含了Namespace时,传入的Descendants的指定Element名称必包含Namespace,
Descendants函数接收的是一个XName的元素,它隐含了\算子,显然刚只得到了Element的LocalName。可以这样做:
var cstr = (from s1 in doc.Descendants() where s1.Name.LocalName==\"Connection\" select s1).First();
var cstr = (from s1 in doc.Descendants(doc.Root.Name.Namespace+\"Connection\" select s1).First();
继续:Linq to xml 的Elements()函数
(发现很多方法都可以轻松搞定我那个问题)
参考网站:http://www.cnblogs.com/ucetgg/archive/2009/04/23/1441739.html
var name = from nm in xelement.Elements("Employee") where (string)nm.Element("Sex")=="Female" select nm;
继续:处理非法字符
XElement和XmlWriter方法:
XElement可以直接处理转义也可以用XCData对象处理。
string invalidChars =@"<>\&"; XElement element = new XElement("Root", new XElement("InvalidChars1", new XCData(invalidChars)), new XElement("InvalidChars2", invalidChars));
InvalidChars1将保存为<![CDATA[<>\&"]>,InvalidChars2将转义存储。
附上转义表:
< <
< >
" "
' '
& &
XmlWriter处理可以使用WriteCData方法将非法字符封装在CDATA片段中,另一种使用WriteElementString方法。
string invalidChars =@"<>\&"; XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; using(XmlWriter writer = XmlWriter.Create(Console.Out,settings)) { writer.WriteStartElement("root"); writer.WriteStartElement("InvalidChars1"); writer.WriteCDate(invalidChars); writer.WriteEndElement(); writer.WriteElementString("InvalidChars2",invalidChars); writer.WriteEndElement(); }
XmlDocumenthe和XmlElement处理方法:
放置于CDATA片段中,并添加至XmlElement的InnerXML属性中。
string invalidChars =@"<>\&"; XmlElement invalidElement1 = xmlDoc.CreateElement("InvalidChars1"); invalidElement1.AppendChild(xmlDoc.CreateCDataSection(invalidChars);
通过赋值给InnerText属性令XmlElement类为封装数据。
string invalidChars =@"<>\&"; XmlElement invalidElement2 = xmlDoc.CreateElement("InvalidChars2"); invalidElement2.InnerText = invalidChars;
作 者:doku
出 处:http://www.cnblogs.com/kulong995/
关于作者:喜欢编程,喜欢美食,专注于.NET项目开发。
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!